diff options
Diffstat (limited to 'intern')
298 files changed, 32402 insertions, 9748 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 43e5b6bff3e..9a5476772ab 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -34,6 +34,10 @@ add_subdirectory(mikktspace) add_subdirectory(glew-mx) add_subdirectory(eigen) +if (WITH_GAMEENGINE_DECKLINK) + add_subdirectory(decklink) +endif() + if(WITH_AUDASPACE) add_subdirectory(audaspace) endif() @@ -79,8 +83,10 @@ if(WITH_OPENSUBDIV) endif() # only windows needs utf16 converter +# gpudirect is a runtime interface to the nVidia's DVP driver, only for windows if(WIN32) add_subdirectory(utfconv) + add_subdirectory(gpudirect) endif() if(WITH_OPENVDB) diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index bf54750ea0d..55c00024244 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -129,23 +129,24 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) { + uint32_t ret = x; asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (ret), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return x; + return ret+x; } ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) { - x = (uint32_t)(-(int32_t)x); + ret = (uint32_t)(-(int32_t)x); asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (ret), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return x; + return ret-x; } ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new) diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h index fcbb2346243..bfec9918c16 100644 --- a/intern/atomic/intern/atomic_ops_utils.h +++ b/intern/atomic/intern/atomic_ops_utils.h @@ -81,7 +81,9 @@ # endif #endif -#ifdef UINTPTR_MAX +#if defined(__SIZEOF_POINTER__) +# define LG_SIZEOF_PTR __SIZEOF_POINTER__ +#elif defined(UINTPTR_MAX) # if (UINTPTR_MAX == 0xFFFFFFFF) # define LG_SIZEOF_PTR 4 # elif (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF) diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp index 300fd55e23b..de5c0a2f463 100644 --- a/intern/audaspace/Python/AUD_PyAPI.cpp +++ b/intern/audaspace/Python/AUD_PyAPI.cpp @@ -861,7 +861,7 @@ Factory_filter(Factory* self, PyObject *args) py_a_len= py_a ? PySequence_Size(py_a) : 0; py_b_len= PySequence_Size(py_b); - if(!py_b_len || ((py_a != NULL) && !py_b_len)) + if(!py_b_len || ((py_a != NULL) && !py_a_len)) { PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!"); return NULL; diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 1165db795de..3d3aca33881 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -31,10 +31,10 @@ #include "mesh.h" #include "nodes.h" #include "object.h" +#include "osl.h" #include "shader.h" #include "scene.h" -#include "subd_mesh.h" #include "subd_patch.h" #include "subd_split.h" @@ -72,18 +72,6 @@ struct XMLReadState : public XMLReader { /* Attribute Reading */ -static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - *value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0); - return true; - } - - return false; -} - static bool xml_read_int(int *value, pugi::xml_node node, const char *name) { pugi::xml_attribute attr = node.attribute(name); @@ -192,18 +180,6 @@ static bool xml_read_string(string *str, pugi::xml_node node, const char *name) return false; } -static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - *str = ustring(attr.value()); - return true; - } - - return false; -} - static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value) { pugi::xml_attribute attr = node.attribute(name); @@ -214,113 +190,16 @@ static bool xml_equal_string(pugi::xml_node node, const char *name, const char * return false; } -static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - ustring ustr(attr.value()); - - if(enm.exists(ustr)) { - *str = ustr; - return true; - } - else - fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name); - } - - return false; -} - -static bool xml_read_enum_value(int *value, ShaderEnum& enm, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - ustring ustr(attr.value()); - - if(enm.exists(ustr)) { - *value = enm[ustr]; - return true; - } - else - fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name); - } - - return false; -} - -static ShaderSocketType xml_read_socket_type(pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - string value = attr.value(); - if(string_iequals(value, "float")) - return SHADER_SOCKET_FLOAT; - else if(string_iequals(value, "int")) - return SHADER_SOCKET_INT; - else if(string_iequals(value, "color")) - return SHADER_SOCKET_COLOR; - else if(string_iequals(value, "vector")) - return SHADER_SOCKET_VECTOR; - else if(string_iequals(value, "point")) - return SHADER_SOCKET_POINT; - else if(string_iequals(value, "normal")) - return SHADER_SOCKET_NORMAL; - else if(string_iequals(value, "closure color")) - return SHADER_SOCKET_CLOSURE; - else if(string_iequals(value, "string")) - return SHADER_SOCKET_STRING; - else - fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name); - } - - return SHADER_SOCKET_UNDEFINED; -} - /* Camera */ -static void xml_read_camera(const XMLReadState& state, pugi::xml_node node) +static void xml_read_camera(XMLReadState& state, pugi::xml_node node) { Camera *cam = state.scene->camera; xml_read_int(&cam->width, node, "width"); xml_read_int(&cam->height, node, "height"); - if(xml_read_float(&cam->fov, node, "fov")) - cam->fov = DEG2RADF(cam->fov); - - xml_read_float(&cam->nearclip, node, "nearclip"); - xml_read_float(&cam->farclip, node, "farclip"); - xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop - xml_read_float(&cam->focaldistance, node, "focaldistance"); - xml_read_float(&cam->shuttertime, node, "shuttertime"); - xml_read_float(&cam->aperture_ratio, node, "aperture_ratio"); - - if(xml_equal_string(node, "type", "orthographic")) - cam->type = CAMERA_ORTHOGRAPHIC; - else if(xml_equal_string(node, "type", "perspective")) - cam->type = CAMERA_PERSPECTIVE; - else if(xml_equal_string(node, "type", "panorama")) - cam->type = CAMERA_PANORAMA; - - if(xml_equal_string(node, "panorama_type", "equirectangular")) - cam->panorama_type = PANORAMA_EQUIRECTANGULAR; - else if(xml_equal_string(node, "panorama_type", "fisheye_equidistant")) - cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT; - else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid")) - cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID; - - xml_read_float(&cam->fisheye_fov, node, "fisheye_fov"); - xml_read_float(&cam->fisheye_lens, node, "fisheye_lens"); - - xml_read_bool(&cam->use_spherical_stereo, node, "use_spherical_stereo"); - xml_read_float(&cam->interocular_distance, node, "interocular_distance"); - xml_read_float(&cam->convergence_distance, node, "convergence_distance"); - - xml_read_float(&cam->sensorwidth, node, "sensorwidth"); - xml_read_float(&cam->sensorheight, node, "sensorheight"); + xml_read_node(state, cam, node); cam->matrix = state.tfm; @@ -347,378 +226,14 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml ShaderGraph *graph = new ShaderGraph(); - map<string, ShaderNode*> nodemap; - - nodemap["output"] = graph->output(); + /* local state, shader nodes can't link to nodes outside the shader graph */ + XMLReader graph_reader; + graph_reader.node_map[ustring("output")] = graph->output(); for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) { - ShaderNode *snode = NULL; - - /* ToDo: Add missing nodes - * RGBCurvesNode, VectorCurvesNode, RGBRampNode and ConvertNode (RGB -> BW). - */ - - if(string_iequals(node.name(), "image_texture")) { - ImageTextureNode *img = new ImageTextureNode(); - - xml_read_string(&img->filename, node, "src"); - img->filename = path_join(state.base, img->filename); - - xml_read_enum(&img->color_space, ImageTextureNode::color_space_enum, node, "color_space"); - xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection"); - xml_read_float(&img->projection_blend, node, "projection_blend"); - - /* ToDo: Interpolation */ - - snode = img; - } - else if(string_iequals(node.name(), "environment_texture")) { - EnvironmentTextureNode *env = new EnvironmentTextureNode(); - - xml_read_string(&env->filename, node, "src"); - env->filename = path_join(state.base, env->filename); - - xml_read_enum(&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space"); - xml_read_enum(&env->projection, EnvironmentTextureNode::projection_enum, node, "projection"); - - snode = env; - } - else if(string_iequals(node.name(), "osl_shader")) { - OSLScriptNode *osl = new OSLScriptNode(); - - /* Source */ - xml_read_string(&osl->filepath, node, "src"); - if(path_is_relative(osl->filepath)) { - osl->filepath = path_join(state.base, osl->filepath); - } - - /* Generate inputs/outputs from node sockets - * - * Note: ShaderInput/ShaderOutput store shallow string copies only! - * So we register them as ustring to ensure the pointer stays valid. */ - /* read input values */ - for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) { - if(string_iequals(param.name(), "input")) { - string name; - if(!xml_read_string(&name, param, "name")) - continue; - - ShaderSocketType type = xml_read_socket_type(param, "type"); - if(type == SHADER_SOCKET_UNDEFINED) - continue; - - osl->add_input(ustring(name).c_str(), type); - } - else if(string_iequals(param.name(), "output")) { - string name; - if(!xml_read_string(&name, param, "name")) - continue; - - ShaderSocketType type = xml_read_socket_type(param, "type"); - if(type == SHADER_SOCKET_UNDEFINED) - continue; - - osl->add_output(ustring(name).c_str(), type); - } - } - - snode = osl; - } - else if(string_iequals(node.name(), "sky_texture")) { - SkyTextureNode *sky = new SkyTextureNode(); - - xml_read_enum(&sky->type, SkyTextureNode::type_enum, node, "type"); - xml_read_float3(&sky->sun_direction, node, "sun_direction"); - xml_read_float(&sky->turbidity, node, "turbidity"); - xml_read_float(&sky->ground_albedo, node, "ground_albedo"); - - snode = sky; - } - else if(string_iequals(node.name(), "noise_texture")) { - snode = new NoiseTextureNode(); - } - else if(string_iequals(node.name(), "checker_texture")) { - snode = new CheckerTextureNode(); - } - else if(string_iequals(node.name(), "brick_texture")) { - BrickTextureNode *brick = new BrickTextureNode(); - - xml_read_float(&brick->offset, node, "offset"); - xml_read_int(&brick->offset_frequency, node, "offset_frequency"); - xml_read_float(&brick->squash, node, "squash"); - xml_read_int(&brick->squash_frequency, node, "squash_frequency"); - - snode = brick; - } - else if(string_iequals(node.name(), "gradient_texture")) { - GradientTextureNode *blend = new GradientTextureNode(); - xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type"); - snode = blend; - } - else if(string_iequals(node.name(), "voronoi_texture")) { - VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring"); - snode = voronoi; - } - else if(string_iequals(node.name(), "musgrave_texture")) { - MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type"); - snode = musgrave; - } - else if(string_iequals(node.name(), "magic_texture")) { - MagicTextureNode *magic = new MagicTextureNode(); - xml_read_int(&magic->depth, node, "depth"); - snode = magic; - } - else if(string_iequals(node.name(), "wave_texture")) { - WaveTextureNode *wave = new WaveTextureNode(); - xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type"); - xml_read_enum(&wave->profile, WaveTextureNode::profile_enum, node, "profile"); - snode = wave; - } - else if(string_iequals(node.name(), "normal")) { - NormalNode *normal = new NormalNode(); - xml_read_float3(&normal->direction, node, "direction"); - snode = normal; - } - else if(string_iequals(node.name(), "bump")) { - BumpNode *bump = new BumpNode(); - xml_read_bool(&bump->invert, node, "invert"); - snode = bump; - } - else if(string_iequals(node.name(), "mapping")) { - MappingNode *map = new MappingNode(); - - TextureMapping *texmap = &map->tex_mapping; - xml_read_enum_value((int*) &texmap->type, TextureMapping::type_enum, node, "type"); - xml_read_enum_value((int*) &texmap->projection, TextureMapping::projection_enum, node, "projection"); - xml_read_enum_value((int*) &texmap->x_mapping, TextureMapping::mapping_enum, node, "x_mapping"); - xml_read_enum_value((int*) &texmap->y_mapping, TextureMapping::mapping_enum, node, "y_mapping"); - xml_read_enum_value((int*) &texmap->z_mapping, TextureMapping::mapping_enum, node, "z_mapping"); - xml_read_bool(&texmap->use_minmax, node, "use_minmax"); - if(texmap->use_minmax) { - xml_read_float3(&texmap->min, node, "min"); - xml_read_float3(&texmap->max, node, "max"); - } - xml_read_float3(&texmap->translation, node, "translation"); - xml_read_float3(&texmap->rotation, node, "rotation"); - xml_read_float3(&texmap->scale, node, "scale"); + ustring node_name(node.name()); - snode = map; - } - else if(string_iequals(node.name(), "anisotropic_bsdf")) { - AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); - xml_read_enum(&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution"); - snode = aniso; - } - else if(string_iequals(node.name(), "diffuse_bsdf")) { - snode = new DiffuseBsdfNode(); - } - /*else if(string_iequals(node.name(), "disney_bsdf")) { - snode = new DisneyBsdfNode(); - }*/ - else if(string_iequals(node.name(), "translucent_bsdf")) { - snode = new TranslucentBsdfNode(); - } - else if(string_iequals(node.name(), "transparent_bsdf")) { - snode = new TransparentBsdfNode(); - } - else if(string_iequals(node.name(), "velvet_bsdf")) { - snode = new VelvetBsdfNode(); - } - else if(string_iequals(node.name(), "toon_bsdf")) { - ToonBsdfNode *toon = new ToonBsdfNode(); - xml_read_enum(&toon->component, ToonBsdfNode::component_enum, node, "component"); - snode = toon; - } - else if(string_iequals(node.name(), "glossy_bsdf")) { - GlossyBsdfNode *glossy = new GlossyBsdfNode(); - xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution"); - snode = glossy; - } - else if(string_iequals(node.name(), "glass_bsdf")) { - GlassBsdfNode *diel = new GlassBsdfNode(); - xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution"); - snode = diel; - } - else if(string_iequals(node.name(), "refraction_bsdf")) { - RefractionBsdfNode *diel = new RefractionBsdfNode(); - xml_read_enum(&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution"); - snode = diel; - } - else if(string_iequals(node.name(), "hair_bsdf")) { - HairBsdfNode *hair = new HairBsdfNode(); - xml_read_enum(&hair->component, HairBsdfNode::component_enum, node, "component"); - snode = hair; - } - else if(string_iequals(node.name(), "emission")) { - snode = new EmissionNode(); - } - else if(string_iequals(node.name(), "ambient_occlusion")) { - snode = new AmbientOcclusionNode(); - } - else if(string_iequals(node.name(), "background")) { - snode = new BackgroundNode(); - } - else if(string_iequals(node.name(), "holdout")) { - snode = new HoldoutNode(); - } - else if(string_iequals(node.name(), "absorption_volume")) { - snode = new AbsorptionVolumeNode(); - } - else if(string_iequals(node.name(), "scatter_volume")) { - snode = new ScatterVolumeNode(); - } - else if(string_iequals(node.name(), "subsurface_scattering")) { - SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode(); - - string falloff; - xml_read_string(&falloff, node, "falloff"); - if(falloff == "cubic") - sss->closure = CLOSURE_BSSRDF_CUBIC_ID; - else if(falloff == "gaussian") - sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID; - else /*if(falloff == "burley")*/ - sss->closure = CLOSURE_BSSRDF_BURLEY_ID; - - snode = sss; - } - else if(string_iequals(node.name(), "geometry")) { - snode = new GeometryNode(); - } - else if(string_iequals(node.name(), "texture_coordinate")) { - snode = new TextureCoordinateNode(); - } - else if(string_iequals(node.name(), "light_path")) { - snode = new LightPathNode(); - } - else if(string_iequals(node.name(), "light_falloff")) { - snode = new LightFalloffNode(); - } - else if(string_iequals(node.name(), "object_info")) { - snode = new ObjectInfoNode(); - } - else if(string_iequals(node.name(), "particle_info")) { - snode = new ParticleInfoNode(); - } - else if(string_iequals(node.name(), "hair_info")) { - snode = new HairInfoNode(); - } - else if(string_iequals(node.name(), "value")) { - ValueNode *value = new ValueNode(); - xml_read_float(&value->value, node, "value"); - snode = value; - } - else if(string_iequals(node.name(), "color")) { - ColorNode *color = new ColorNode(); - xml_read_float3(&color->value, node, "value"); - snode = color; - } - else if(string_iequals(node.name(), "mix_closure")) { - snode = new MixClosureNode(); - } - else if(string_iequals(node.name(), "add_closure")) { - snode = new AddClosureNode(); - } - else if(string_iequals(node.name(), "invert")) { - snode = new InvertNode(); - } - else if(string_iequals(node.name(), "mix")) { - /* ToDo: Tag Mix case for optimization */ - MixNode *mix = new MixNode(); - xml_read_enum(&mix->type, MixNode::type_enum, node, "type"); - xml_read_bool(&mix->use_clamp, node, "use_clamp"); - snode = mix; - } - else if(string_iequals(node.name(), "gamma")) { - snode = new GammaNode(); - } - else if(string_iequals(node.name(), "brightness")) { - snode = new BrightContrastNode(); - } - else if(string_iequals(node.name(), "combine_rgb")) { - snode = new CombineRGBNode(); - } - else if(string_iequals(node.name(), "separate_rgb")) { - snode = new SeparateRGBNode(); - } - else if(string_iequals(node.name(), "combine_hsv")) { - snode = new CombineHSVNode(); - } - else if(string_iequals(node.name(), "separate_hsv")) { - snode = new SeparateHSVNode(); - } - else if(string_iequals(node.name(), "combine_xyz")) { - snode = new CombineXYZNode(); - } - else if(string_iequals(node.name(), "separate_xyz")) { - snode = new SeparateXYZNode(); - } - else if(string_iequals(node.name(), "hsv")) { - snode = new HSVNode(); - } - else if(string_iequals(node.name(), "wavelength")) { - snode = new WavelengthNode(); - } - else if(string_iequals(node.name(), "blackbody")) { - snode = new BlackbodyNode(); - } - else if(string_iequals(node.name(), "attribute")) { - AttributeNode *attr = new AttributeNode(); - xml_read_ustring(&attr->attribute, node, "attribute"); - snode = attr; - } - else if(string_iequals(node.name(), "uv_map")) { - UVMapNode *uvm = new UVMapNode(); - xml_read_ustring(&uvm->attribute, node, "uv_map"); - snode = uvm; - } - else if(string_iequals(node.name(), "camera")) { - snode = new CameraNode(); - } - else if(string_iequals(node.name(), "fresnel")) { - snode = new FresnelNode(); - } - else if(string_iequals(node.name(), "layer_weight")) { - snode = new LayerWeightNode(); - } - else if(string_iequals(node.name(), "wireframe")) { - WireframeNode *wire = new WireframeNode; - xml_read_bool(&wire->use_pixel_size, node, "use_pixel_size"); - snode = wire; - } - else if(string_iequals(node.name(), "normal_map")) { - NormalMapNode *nmap = new NormalMapNode; - xml_read_ustring(&nmap->attribute, node, "attribute"); - xml_read_enum(&nmap->space, NormalMapNode::space_enum, node, "space"); - snode = nmap; - } - else if(string_iequals(node.name(), "tangent")) { - TangentNode *tangent = new TangentNode; - xml_read_ustring(&tangent->attribute, node, "attribute"); - xml_read_enum(&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type"); - xml_read_enum(&tangent->axis, TangentNode::axis_enum, node, "axis"); - snode = tangent; - } - else if(string_iequals(node.name(), "math")) { - MathNode *math = new MathNode(); - xml_read_enum(&math->type, MathNode::type_enum, node, "type"); - xml_read_bool(&math->use_clamp, node, "use_clamp"); - snode = math; - } - else if(string_iequals(node.name(), "vector_math")) { - VectorMathNode *vmath = new VectorMathNode(); - xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type"); - snode = vmath; - } - else if(string_iequals(node.name(), "vector_transform")) { - VectorTransformNode *vtransform = new VectorTransformNode(); - xml_read_enum(&vtransform->type, VectorTransformNode::type_enum, node, "type"); - xml_read_enum(&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from"); - xml_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to"); - snode = vtransform; - } - else if(string_iequals(node.name(), "connect")) { + if(node_name == "connect") { /* connect nodes */ vector<string> from_tokens, to_tokens; @@ -726,35 +241,40 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml string_split(to_tokens, node.attribute("to").value()); if(from_tokens.size() == 2 && to_tokens.size() == 2) { + ustring from_node_name(from_tokens[0]); + ustring from_socket_name(from_tokens[1]); + ustring to_node_name(to_tokens[0]); + ustring to_socket_name(to_tokens[1]); + /* find nodes and sockets */ ShaderOutput *output = NULL; ShaderInput *input = NULL; - if(nodemap.find(from_tokens[0]) != nodemap.end()) { - ShaderNode *fromnode = nodemap[from_tokens[0]]; + if(graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) { + ShaderNode *fromnode = (ShaderNode*)graph_reader.node_map[from_node_name]; foreach(ShaderOutput *out, fromnode->outputs) - if(string_iequals(xml_socket_name(out->name), from_tokens[1])) + if(string_iequals(xml_socket_name(out->name().c_str()), from_socket_name.c_str())) output = out; if(!output) - fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str()); + fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_node_name.c_str(), from_socket_name.c_str()); } else - fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str()); + fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str()); - if(nodemap.find(to_tokens[0]) != nodemap.end()) { - ShaderNode *tonode = nodemap[to_tokens[0]]; + if(graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) { + ShaderNode *tonode = (ShaderNode*)graph_reader.node_map[to_node_name]; foreach(ShaderInput *in, tonode->inputs) - if(string_iequals(xml_socket_name(in->name), to_tokens[1])) + if(string_iequals(xml_socket_name(in->name().c_str()), to_socket_name.c_str())) input = in; if(!input) - fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str()); + fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_socket_name.c_str(), to_node_name.c_str()); } else - fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str()); + fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str()); /* connect */ if(output && input) @@ -762,44 +282,76 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml } else fprintf(stderr, "Invalid from or to value for connect node.\n"); + + continue; } - else - fprintf(stderr, "Unknown shader node \"%s\".\n", node.name()); - if(snode) { - /* add to graph */ - graph->add(snode); + ShaderNode *snode = NULL; + +#ifdef WITH_OSL + if(node_name == "osl_shader") { + ShaderManager *manager = state.scene->shader_manager; - /* add to map for name lookups */ - string name = ""; - xml_read_string(&name, node, "name"); - - nodemap[name] = snode; - - /* read input values */ - for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) { - foreach(ShaderInput *in, snode->inputs) { - if(string_iequals(in->name, attr.name())) { - switch(in->type) { - case SHADER_SOCKET_FLOAT: - case SHADER_SOCKET_INT: - xml_read_float(&in->value.x, node, attr.name()); - break; - case SHADER_SOCKET_COLOR: - case SHADER_SOCKET_VECTOR: - case SHADER_SOCKET_POINT: - case SHADER_SOCKET_NORMAL: - xml_read_float3(&in->value, node, attr.name()); - break; - case SHADER_SOCKET_STRING: - xml_read_ustring( &in->value_string, node, attr.name() ); - break; - default: - break; - } + if(manager->use_osl()) { + std::string filepath; + + if(xml_read_string(&filepath, node, "src")) { + if(path_is_relative(filepath)) { + filepath = path_join(state.base, filepath); + } + + snode = ((OSLShaderManager*)manager)->osl_node(filepath); + + if(!snode) { + fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str()); + continue; } } + else { + fprintf(stderr, "OSL node missing \"src\" attribute.\n"); + continue; + } + } + else { + fprintf(stderr, "OSL node without using --shadingsys osl.\n"); + continue; + } + } + else +#endif + { + /* exception for name collision */ + if(node_name == "background") + node_name = "background_shader"; + + const NodeType *node_type = NodeType::find(node_name); + + if(!node_type) { + fprintf(stderr, "Unknown shader node \"%s\".\n", node.name()); + continue; + } + else if(node_type->type != NodeType::SHADER) { + fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str()); + continue; } + + snode = (ShaderNode*) node_type->create(node_type); + } + + xml_read_node(graph_reader, snode, node); + + if(node_name == "image_texture") { + ImageTextureNode *img = (ImageTextureNode*) snode; + img->filename = path_join(state.base, img->filename.string()); + } + else if(node_name == "environment_texture") { + EnvironmentTextureNode *env = (EnvironmentTextureNode*) snode; + env->filename = path_join(state.base, env->filename.string()); + } + + if(snode) { + /* add to graph */ + graph->add(snode); } } @@ -864,6 +416,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) xml_read_int_array(verts, node, "verts"); xml_read_int_array(nverts, node, "nverts"); +#if 0 if(xml_equal_string(node, "subdivision", "catmull-clark")) { /* create subd mesh */ SubdMesh sdmesh; @@ -907,10 +460,17 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) DiagSplit dsplit(sdparams); sdmesh.tessellate(&dsplit); } - else { + else +#endif + { /* create vertices */ mesh->verts = P; + size_t num_triangles = 0; + for(size_t i = 0; i < nverts.size(); i++) + num_triangles += nverts[i]-2; + mesh->reserve_mesh(mesh->verts.size(), num_triangles); + /* create triangles */ int index_offset = 0; @@ -1010,7 +570,7 @@ static void xml_read_patch(const XMLReadState& state, pugi::xml_node node) mesh->used_shaders.push_back(state.shader); /* split */ - SubdParams sdparams(mesh, 0, state.smooth); + SubdParams sdparams(mesh); xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); DiagSplit dsplit(sdparams); diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index d4b7535b9ee..2c5365c9189 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -82,7 +82,6 @@ def init(): import bpy import _cycles import os.path - import sys # Workaround possibly buggy legacy drivers which crashes on the OpenCL # device enumeration. @@ -103,10 +102,12 @@ def init(): _cycles.init(path, user_path, bpy.app.background) _parse_command_line() + def exit(): import _cycles _cycles.exit() + def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False): import bpy import _cycles diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 140862721a8..81204eb8ae0 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -46,12 +46,6 @@ enum_displacement_methods = ( ('BOTH', "Both", "Combination of displacement and bump mapping"), ) -enum_subdivision_types = ( - ('NONE', "None", "No subdivision"), - ('LINEAR', "Linear", "Use linear subdivision"), - ('CATMULL_CLARK', "Catmull–Clark", "Use Catmull-Clark subdivision"), - ) - enum_bvh_types = ( ('DYNAMIC_BVH', "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"), ('STATIC_BVH', "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"), @@ -503,6 +497,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Use BVH spatial splits: longer builder time, faster render", default=False, ) + cls.debug_use_hair_bvh = BoolProperty( + name="Use Hair BVH", + description="Use special type BVH optimized for hair (uses more ram but renders faster)", + default=True, + ) cls.tile_order = EnumProperty( name="Tile Order", description="Tile order for rendering", @@ -959,18 +958,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup): items=enum_displacement_methods, default='BUMP', ) - cls.subdivision_type = EnumProperty( - name="Subdivision Type", - description="Type of subdivision to use", - items=enum_subdivision_types, - default='NONE', - ) - cls.dicing_rate = FloatProperty( - name="Dicing Rate", - description="Multiplier for scene dicing rate", - min=0.1, max=1000.0, - default=1.0, - ) @classmethod def unregister(cls): @@ -979,11 +966,9 @@ class CyclesMeshSettings(bpy.types.PropertyGroup): del bpy.types.MetaBall.cycles -class CyclesObjectBlurSettings(bpy.types.PropertyGroup): - +class CyclesObjectSettings(bpy.types.PropertyGroup): @classmethod def register(cls): - bpy.types.Object.cycles = PointerProperty( name="Cycles Object Settings", description="Cycles object settings", @@ -1015,6 +1000,19 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup): default=False, ) + cls.use_adaptive_subdivision = BoolProperty( + name="Use Adaptive Subdivision", + description="Use adaptive render time subdivision", + default=False, + ) + + cls.dicing_rate = FloatProperty( + name="Dicing Rate", + description="Multiplier for scene dicing rate", + min=0.1, max=1000.0, + default=1.0, + ) + @classmethod def unregister(cls): del bpy.types.Object.cycles @@ -1131,6 +1129,7 @@ def register(): bpy.utils.register_class(CyclesWorldSettings) bpy.utils.register_class(CyclesVisibilitySettings) bpy.utils.register_class(CyclesMeshSettings) + bpy.utils.register_class(CyclesObjectSettings) bpy.utils.register_class(CyclesCurveRenderSettings) bpy.utils.register_class(CyclesCurveSettings) @@ -1142,6 +1141,7 @@ def unregister(): bpy.utils.unregister_class(CyclesLampSettings) bpy.utils.unregister_class(CyclesWorldSettings) bpy.utils.unregister_class(CyclesMeshSettings) + bpy.utils.unregister_class(CyclesObjectSettings) bpy.utils.unregister_class(CyclesVisibilitySettings) bpy.utils.unregister_class(CyclesCurveRenderSettings) bpy.utils.unregister_class(CyclesCurveSettings) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 023841a7a17..42f7970769a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -76,9 +76,8 @@ def use_cuda(context): def use_branched_path(context): cscene = context.scene.cycles - device_type = context.user_preferences.system.compute_device_type - return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL') + return (cscene.progressive == 'BRANCHED_PATH' and not use_opencl(context)) def use_sample_all_lights(context): @@ -384,7 +383,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): sub.prop(cscene, "use_progressive_refine") subsub = sub.column(align=True) - subsub.enabled = not rd.use_border subsub.prop(rd, "use_save_buffers") col = split.column(align=True) @@ -403,6 +401,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): col.label(text="Acceleration structure:") col.prop(cscene, "debug_use_spatial_splits") + col.prop(cscene, "debug_use_hair_bvh") class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): @@ -460,7 +459,9 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel): col.prop(rl, "use_pass_z") col.prop(rl, "use_pass_mist") col.prop(rl, "use_pass_normal") - col.prop(rl, "use_pass_vector") + row = col.row() + row.prop(rl, "use_pass_vector") + row.active = not rd.use_motion_blur col.prop(rl, "use_pass_uv") col.prop(rl, "use_pass_object_index") col.prop(rl, "use_pass_material_index") @@ -704,17 +705,9 @@ class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel): col = split.column() sub = col.column(align=True) - sub.label(text="Displacment:") + sub.label(text="Displacement:") sub.prop(cdata, "displacement_method", text="") - col = split.column() - sub = col.column(align=True) - sub.label(text="Subdivision:") - sub.prop(cdata, "subdivision_type", text="") - - if cdata.subdivision_type != 'NONE': - sub.prop(cdata, "dicing_rate") - class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel): bl_label = "Motion Blur" bl_context = "object" @@ -894,7 +887,7 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel): lamp = context.lamp clamp = lamp.cycles - cscene = context.scene.cycles + # cscene = context.scene.cycles layout.prop(lamp, "type", expand=True) @@ -1114,7 +1107,7 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): world = context.world cworld = world.cycles - cscene = context.scene.cycles + # cscene = context.scene.cycles split = layout.split() @@ -1664,104 +1657,62 @@ def draw_pause(self, context): def get_panels(): - types = bpy.types - panels = [ - "RENDER_PT_render", - "RENDER_PT_output", - "RENDER_PT_encoding", - "RENDER_PT_dimensions", - "RENDER_PT_stamp", - "RENDER_PT_freestyle", - "RENDERLAYER_PT_layers", - "RENDERLAYER_PT_freestyle", - "RENDERLAYER_PT_freestyle_lineset", - "RENDERLAYER_PT_freestyle_linestyle", - "SCENE_PT_scene", - "SCENE_PT_color_management", - "SCENE_PT_custom_props", - "SCENE_PT_audio", - "SCENE_PT_unit", - "SCENE_PT_keying_sets", - "SCENE_PT_keying_set_paths", - "SCENE_PT_physics", - "WORLD_PT_context_world", - "WORLD_PT_custom_props", - "DATA_PT_context_mesh", - "DATA_PT_context_camera", - "DATA_PT_context_lamp", - "DATA_PT_context_speaker", - "DATA_PT_normals", - "DATA_PT_texture_space", - "DATA_PT_curve_texture_space", - "DATA_PT_mball_texture_space", - "DATA_PT_vertex_groups", - "DATA_PT_shape_keys", - "DATA_PT_uv_texture", - "DATA_PT_vertex_colors", - "DATA_PT_camera", - "DATA_PT_camera_display", - "DATA_PT_camera_stereoscopy", - "DATA_PT_camera_safe_areas", - "DATA_PT_lens", - "DATA_PT_speaker", - "DATA_PT_distance", - "DATA_PT_cone", - "DATA_PT_customdata", - "DATA_PT_custom_props_mesh", - "DATA_PT_custom_props_camera", - "DATA_PT_custom_props_lamp", - "DATA_PT_custom_props_speaker", - "DATA_PT_custom_props_arm", - "DATA_PT_custom_props_curve", - "DATA_PT_custom_props_lattice", - "DATA_PT_custom_props_metaball", - "TEXTURE_PT_preview", - "TEXTURE_PT_custom_props", - "TEXTURE_PT_clouds", - "TEXTURE_PT_wood", - "TEXTURE_PT_marble", - "TEXTURE_PT_magic", - "TEXTURE_PT_blend", - "TEXTURE_PT_stucci", - "TEXTURE_PT_image", - "TEXTURE_PT_image_sampling", - "TEXTURE_PT_image_mapping", - "TEXTURE_PT_musgrave", - "TEXTURE_PT_voronoi", - "TEXTURE_PT_distortednoise", - "TEXTURE_PT_voxeldata", - "TEXTURE_PT_pointdensity", - "TEXTURE_PT_pointdensity_turbulence", - "TEXTURE_PT_mapping", - "TEXTURE_PT_ocean", - "TEXTURE_PT_influence", - "TEXTURE_PT_colors", - "PARTICLE_PT_context_particles", - "PARTICLE_PT_custom_props", - "PARTICLE_PT_emission", - "PARTICLE_PT_hair_dynamics", - "PARTICLE_PT_cache", - "PARTICLE_PT_velocity", - "PARTICLE_PT_rotation", - "PARTICLE_PT_physics", - "SCENE_PT_rigid_body_world", - "SCENE_PT_rigid_body_cache", - "SCENE_PT_rigid_body_field_weights", - "PARTICLE_PT_boidbrain", - "PARTICLE_PT_render", - "PARTICLE_PT_draw", - "PARTICLE_PT_children", - "PARTICLE_PT_field_weights", - "PARTICLE_PT_force_fields", - "PARTICLE_PT_vertexgroups", - "MATERIAL_PT_custom_props", - "MATERIAL_PT_freestyle_line", - "BONE_PT_custom_props", - "OBJECT_PT_custom_props", - ] - - return [getattr(types, p) for p in panels if hasattr(types, p)] - + exclude_panels = { + 'DATA_PT_area', + 'DATA_PT_camera_dof', + 'DATA_PT_falloff_curve', + 'DATA_PT_lamp', + 'DATA_PT_preview', + 'DATA_PT_shadow', + 'DATA_PT_spot', + 'DATA_PT_sunsky', + 'MATERIAL_PT_context_material', + 'MATERIAL_PT_diffuse', + 'MATERIAL_PT_flare', + 'MATERIAL_PT_halo', + 'MATERIAL_PT_mirror', + 'MATERIAL_PT_options', + 'MATERIAL_PT_pipeline', + 'MATERIAL_PT_preview', + 'MATERIAL_PT_shading', + 'MATERIAL_PT_shadow', + 'MATERIAL_PT_specular', + 'MATERIAL_PT_sss', + 'MATERIAL_PT_strand', + 'MATERIAL_PT_transp', + 'MATERIAL_PT_volume_density', + 'MATERIAL_PT_volume_integration', + 'MATERIAL_PT_volume_lighting', + 'MATERIAL_PT_volume_options', + 'MATERIAL_PT_volume_shading', + 'MATERIAL_PT_volume_transp', + 'RENDERLAYER_PT_layer_options', + 'RENDERLAYER_PT_layer_passes', + 'RENDERLAYER_PT_views', + 'RENDER_PT_antialiasing', + 'RENDER_PT_bake', + 'RENDER_PT_motion_blur', + 'RENDER_PT_performance', + 'RENDER_PT_post_processing', + 'RENDER_PT_shading', + 'SCENE_PT_simplify', + 'TEXTURE_PT_context_texture', + 'WORLD_PT_ambient_occlusion', + 'WORLD_PT_environment_lighting', + 'WORLD_PT_gather', + 'WORLD_PT_indirect_lighting', + 'WORLD_PT_mist', + 'WORLD_PT_preview', + 'WORLD_PT_world' + } + + panels = [] + for panel in bpy.types.Panel.__subclasses__(): + if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES: + if panel.__name__ not in exclude_panels: + panels.append(panel) + + return panels def register(): bpy.types.RENDER_PT_render.append(draw_device) @@ -1770,10 +1721,10 @@ def register(): for panel in get_panels(): panel.COMPAT_ENGINES.add('CYCLES') - def unregister(): bpy.types.RENDER_PT_render.remove(draw_device) bpy.types.VIEW3D_HT_header.remove(draw_pause) for panel in get_panels(): - panel.COMPAT_ENGINES.remove('CYCLES') + if 'CYCLES' in panel.COMPAT_ENGINES: + panel.COMPAT_ENGINES.remove('CYCLES') diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 221b1437128..830723d6149 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -104,7 +104,6 @@ def vector_curve_node_remap(node): """ Remap values of vector curve node from normalized to absolute values """ - from mathutils import Vector if node.bl_idname == 'ShaderNodeVectorCurve': node.mapping.use_clip = False for curve in node.mapping.curves: diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 9dec489ce33..f02fc553908 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -37,7 +37,7 @@ struct BlenderCamera { float lens; float shuttertime; Camera::MotionPosition motion_position; - float shutter_curve[RAMP_TABLE_SIZE]; + array<float> shutter_curve; Camera::RollingShutterType rolling_shutter_type; float rolling_shutter_duration; @@ -108,10 +108,6 @@ static void blender_camera_init(BlenderCamera *bcam, /* render resolution */ bcam->full_width = render_resolution_x(b_render); bcam->full_height = render_resolution_y(b_render); - - /* pixel aspect */ - bcam->pixelaspect.x = b_render.pixel_aspect_x(); - bcam->pixelaspect.y = b_render.pixel_aspect_y(); } static float blender_camera_focal_distance(BL::RenderEngine& b_engine, @@ -464,7 +460,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->rolling_shutter_type = bcam->rolling_shutter_type; cam->rolling_shutter_duration = bcam->rolling_shutter_duration; - memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve)); + cam->shutter_curve = bcam->shutter_curve; /* border */ cam->border = bcam->border; @@ -563,6 +559,10 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, float aspectratio, sensor_size; blender_camera_init(&bcam, b_render); + /* TODO(sergey): Consider making it a part of blender_camera_init(). */ + bcam.pixelaspect.x = b_render.pixel_aspect_x(); + bcam.pixelaspect.y = b_render.pixel_aspect_y(); + blender_camera_from_object(&bcam, b_engine, b_ob); blender_camera_viewplane(&bcam, width, height, diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 64f1b66405e..378ae67f0c7 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -156,16 +156,16 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles"); - CData->psys_firstcurve.push_back(curvenum); - CData->psys_curvenum.push_back(totcurves); - CData->psys_shader.push_back(shader); + CData->psys_firstcurve.push_back_slow(curvenum); + CData->psys_curvenum.push_back_slow(totcurves); + CData->psys_shader.push_back_slow(shader); float radius = get_float(cpsys, "radius_scale") * 0.5f; - CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width")); - CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width")); - CData->psys_shape.push_back(get_float(cpsys, "shape")); - CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip")); + CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width")); + CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width")); + CData->psys_shape.push_back_slow(get_float(cpsys, "shape")); + CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip")); int pa_no = 0; if(!(b_part.child_type() == 0) && totchild != 0) @@ -180,7 +180,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par for(; pa_no < totparts+totchild; pa_no++) { int keynum = 0; - CData->curve_firstkey.push_back(keyno); + CData->curve_firstkey.push_back_slow(keyno); float curve_length = 0.0f; float3 pcKey; @@ -195,15 +195,15 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par continue; curve_length += step_length; } - CData->curvekey_co.push_back(cKey); - CData->curvekey_time.push_back(curve_length); + CData->curvekey_co.push_back_slow(cKey); + CData->curvekey_time.push_back_slow(curve_length); pcKey = cKey; keynum++; } keyno += keynum; - CData->curve_keynum.push_back(keynum); - CData->curve_length.push_back(curve_length); + CData->curve_keynum.push_back_slow(keynum); + CData->curve_length.push_back_slow(curve_length); curvenum++; } } @@ -255,7 +255,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti float3 uv = make_float3(0.0f, 0.0f, 0.0f); if(b_mesh->tessface_uv_textures.length()) b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x); - CData->curve_uv.push_back(uv); + CData->curve_uv.push_back_slow(uv); if(pa_no < totparts && b_pa != b_psys.particles.end()) ++b_pa; @@ -309,7 +309,7 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par float3 vcol = make_float3(0.0f, 0.0f, 0.0f); if(b_mesh->tessface_vertex_colors.length()) b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); - CData->curve_vcol.push_back(vcol); + CData->curve_vcol.push_back_slow(vcol); if(pa_no < totparts && b_pa != b_psys.particles.end()) ++b_pa; @@ -351,10 +351,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, } } - mesh->verts.reserve(mesh->verts.size() + numverts); - mesh->triangles.reserve(mesh->triangles.size() + numtris); - mesh->shader.reserve(mesh->shader.size() + numtris); - mesh->smooth.reserve(mesh->smooth.size() + numtris); + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { @@ -374,8 +371,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->verts.push_back(ickey_loc_shfl); - mesh->verts.push_back(ickey_loc_shfr); + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); vertexindex += 2; for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { @@ -401,8 +398,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->verts.push_back(ickey_loc_shfl); - mesh->verts.push_back(ickey_loc_shfr); + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true); vertexindex += 2; @@ -410,7 +407,6 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, } } - mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); @@ -437,10 +433,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol } } - mesh->verts.reserve(mesh->verts.size() + numverts); - mesh->triangles.reserve(mesh->triangles.size() + numtris); - mesh->shader.reserve(mesh->shader.size() + numtris); - mesh->smooth.reserve(mesh->smooth.size() + numtris); + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { @@ -529,7 +522,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol float angle = M_2PI_F / (float)resolution; for(int section = 0; section < resolution; section++) { float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); - mesh->verts.push_back(ickey_loc_shf); + mesh->add_vertex(ickey_loc_shf); } if(subv != 0) { @@ -546,7 +539,6 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol } } - mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); @@ -561,7 +553,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) int num_keys = 0; int num_curves = 0; - if(!(mesh->curves.empty() && mesh->curve_keys.empty())) + if(mesh->num_curves()) return; Attribute *attr_intercept = NULL; @@ -584,8 +576,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) VLOG(1) << "Exporting curve segments for mesh " << mesh->name; } - mesh->curve_keys.reserve(mesh->curve_keys.size() + num_keys); - mesh->curves.reserve(mesh->curves.size() + num_curves); + mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); num_keys = 0; num_curves = 0; @@ -613,18 +604,16 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) num_curve_keys++; } - mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]); + mesh->add_curve(num_keys, CData->psys_shader[sys]); num_keys += num_curve_keys; num_curves++; } } /* check allocation */ - if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) { + if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { VLOG(1) << "Allocation failed, clearing data"; - mesh->curve_keys.clear(); - mesh->curves.clear(); - mesh->curve_attributes.clear(); + mesh->clear(); } } @@ -667,13 +656,16 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = 0.0f; + /* curve motion keys store both position and radius in float4 */ mP[i] = float3_to_float4(ickey_loc); mP[i].w = radius; /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ - if(len_squared(mP[i] - mesh->curve_keys[i]) > 1e-5f*1e-5f) + float4 curve_key = float3_to_float4(mesh->curve_keys[i]); + curve_key.w = mesh->curve_radius[i]; + if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f) have_motion = true; } @@ -697,8 +689,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int for(int step = 0; step < time_index; step++) { float4 *mP = attr_mP->data_float4() + step*numkeys; - for(int key = 0; key < numkeys; key++) - mP[key] = mesh->curve_keys[key]; + for(int key = 0; key < numkeys; key++) { + mP[key] = float3_to_float4(mesh->curve_keys[key]); + mP[key].w = mesh->curve_radius[key]; + } } } } @@ -872,7 +866,9 @@ void BlenderSync::sync_curves(Mesh *mesh, if(!motion) { /* Clear stored curve data */ mesh->curve_keys.clear(); - mesh->curves.clear(); + mesh->curve_radius.clear(); + mesh->curve_first_key.clear(); + mesh->curve_shader.clear(); mesh->curve_attributes.clear(); } @@ -889,7 +885,7 @@ void BlenderSync::sync_curves(Mesh *mesh, int triangle_method = scene->curve_system_manager->triangle_method; int resolution = scene->curve_system_manager->resolution; size_t vert_num = mesh->verts.size(); - size_t tri_num = mesh->triangles.size(); + size_t tri_num = mesh->num_triangles(); int used_res = 1; /* extract particle hair data - should be combined with connecting to mesh later*/ @@ -950,11 +946,10 @@ void BlenderSync::sync_curves(Mesh *mesh, else { Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); float3 *generated = attr_generated->data_float3(); - size_t i = 0; - foreach(Mesh::Curve& curve, mesh->curves) { - float3 co = float4_to_float3(mesh->curve_keys[curve.first_key]); - generated[i++] = co*size - loc; + for(size_t i = 0; i < mesh->num_curves(); i++) { + float3 co = mesh->curve_keys[mesh->get_curve(i).first_key]; + generated[i] = co*size - loc; } } } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 4a0ad79f3ae..74fd4cb44a0 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -24,7 +24,6 @@ #include "blender_session.h" #include "blender_util.h" -#include "subd_mesh.h" #include "subd_patch.h" #include "subd_split.h" @@ -335,44 +334,71 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, - const vector<int>& face_flags) + const vector<int>& face_flags, + bool subdivision) { - BL::Mesh::tessface_vertex_colors_iterator l; - for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { - if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) - continue; + if(subdivision) { + BL::Mesh::vertex_colors_iterator l; - Attribute *attr = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; - BL::MeshColorLayer::data_iterator c; - uchar4 *cdata = attr->data_uchar4(); - size_t i = 0; + Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()), + TypeDesc::TypeColor, + ATTR_ELEMENT_CORNER_BYTE); - for(l->data.begin(c); c != l->data.end(); ++c, ++i) { - int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + BL::Mesh::polygons_iterator p; + uchar4 *cdata = attr->data_uchar4(); - uchar4 colors[4]; - colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); - colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); - colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); - if(nverts[i] == 4) { - colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for(int i = 0; i < n; i++) { + float3 color = get_float3(l->data[p->loop_start() + i].color()); + *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color)); + } } + } + } + else { + BL::Mesh::tessface_vertex_colors_iterator l; + for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()), + TypeDesc::TypeColor, + ATTR_ELEMENT_CORNER_BYTE); + + BL::MeshColorLayer::data_iterator c; + uchar4 *cdata = attr->data_uchar4(); + size_t i = 0; + + for(l->data.begin(c); c != l->data.end(); ++c, ++i) { + int tri_a[3], tri_b[3]; + face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + + uchar4 colors[4]; + colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); + colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); + colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); + if(nverts[i] == 4) { + colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); + } - cdata[0] = colors[tri_a[0]]; - cdata[1] = colors[tri_a[1]]; - cdata[2] = colors[tri_a[2]]; + cdata[0] = colors[tri_a[0]]; + cdata[1] = colors[tri_a[1]]; + cdata[2] = colors[tri_a[2]]; - if(nverts[i] == 4) { - cdata[3] = colors[tri_b[0]]; - cdata[4] = colors[tri_b[1]]; - cdata[5] = colors[tri_b[2]]; - cdata += 6; + if(nverts[i] == 4) { + cdata[3] = colors[tri_b[0]]; + cdata[4] = colors[tri_b[1]]; + cdata[5] = colors[tri_b[2]]; + cdata += 6; + } + else + cdata += 3; } - else - cdata += 3; } } } @@ -382,9 +408,40 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, - const vector<int>& face_flags) + const vector<int>& face_flags, + bool subdivision) { - if(b_mesh.tessface_uv_textures.length() != 0) { + if(subdivision) { + BL::Mesh::uv_layers_iterator l; + int i = 0; + + for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { + bool active_render = b_mesh.uv_textures[i].active_render(); + AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; + ustring name = ustring(l->name().c_str()); + + /* UV map */ + if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { + Attribute *attr; + + if(active_render) + attr = mesh->subd_attributes.add(std, name); + else + attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + + BL::Mesh::polygons_iterator p; + float3 *fdata = attr->data_float3(); + + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for(int j = 0; j < n; j++) { + *(fdata++) = get_float3(l->data[p->loop_start() + j].uv()); + } + } + } + } + } + else if(b_mesh.tessface_uv_textures.length() != 0) { BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { @@ -465,11 +522,13 @@ static void attr_create_uv_map(Scene *scene, /* Create vertex pointiness attributes. */ static void attr_create_pointiness(Scene *scene, Mesh *mesh, - BL::Mesh& b_mesh) + BL::Mesh& b_mesh, + bool subdivision) { if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { const int numverts = b_mesh.vertices.length(); - Attribute *attr = mesh->attributes.add(ATTR_STD_POINTINESS); + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr = attributes.add(ATTR_STD_POINTINESS); float *data = attr->data_float(); int *counter = new int[numverts]; float *raw_data = new float[numverts]; @@ -532,31 +591,44 @@ static void attr_create_pointiness(Scene *scene, static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, - const vector<Shader*>& used_shaders) + const vector<Shader*>& used_shaders, + bool subdivision=false) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); - int numfaces = b_mesh.tessfaces.length(); + int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length(); int numtris = 0; + int numcorners = 0; + int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth(); BL::Mesh::vertices_iterator v; BL::Mesh::tessfaces_iterator f; + BL::Mesh::polygons_iterator p; - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { - int4 vi = get_int4(f->vertices_raw()); - numtris += (vi[3] == 0)? 1: 2; + if(!subdivision) { + for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { + int4 vi = get_int4(f->vertices_raw()); + numtris += (vi[3] == 0)? 1: 2; + } + } + else { + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + numngons += (p->loop_total() == 4)? 0: 1; + numcorners += p->loop_total(); + } } - /* reserve memory */ - mesh->reserve(numverts, numtris, 0, 0); + /* allocate memory */ + mesh->reserve_mesh(numverts, numtris); + mesh->reserve_subd_faces(numfaces, numngons, numcorners); /* create vertex coordinates and normals */ - int i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i) - mesh->verts[i] = get_float3(v->co()); + for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) + mesh->add_vertex(get_float3(v->co())); - Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) @@ -565,7 +637,7 @@ static void create_mesh(Scene *scene, /* create generated coordinates from undeformed coordinates */ if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { - Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); + Attribute *attr = attributes.add(ATTR_STD_GENERATED); float3 loc, size; mesh_texture_space(b_mesh, loc, size); @@ -578,67 +650,103 @@ static void create_mesh(Scene *scene, } /* Create needed vertex attributes. */ - attr_create_pointiness(scene, mesh, b_mesh); + attr_create_pointiness(scene, mesh, b_mesh, subdivision); /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); - int fi = 0, ti = 0; - - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { - int4 vi = get_int4(f->vertices_raw()); - int n = (vi[3] == 0)? 3: 4; - int shader = clamp(f->material_index(), 0, used_shaders.size()-1); - bool smooth = f->use_smooth() || use_loop_normals; - - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - BL::Array<float, 12> loop_normals = f->split_normals(); - - for(int i = 0; i < n; i++) { - float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; + int fi = 0; + + if(!subdivision) { + for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { + int4 vi = get_int4(f->vertices_raw()); + int n = (vi[3] == 0)? 3: 4; + int shader = clamp(f->material_index(), 0, used_shaders.size()-1); + bool smooth = f->use_smooth() || use_loop_normals; + + /* split vertices if normal is different + * + * note all vertex attributes must have been set here so we can split + * and copy attributes in split_vertex without remapping later */ + if(use_loop_normals) { + BL::Array<float, 12> loop_normals = f->split_normals(); + + for(int i = 0; i < n; i++) { + float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); + + if(N[vi[i]] != loop_N) { + int new_vi = mesh->split_vertex(vi[i]); + + /* set new normal and vertex index */ + N = attr_N->data_float3(); + N[new_vi] = loop_N; + vi[i] = new_vi; + } } } - } - /* create triangles */ - if(n == 4) { - if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || - is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) - { - // TODO(mai): order here is probably wrong - mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth, true); - mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth, true); - face_flags[fi] |= FACE_FLAG_DIVIDE_24; + /* create triangles */ + if(n == 4) { + if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || + is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) + { + mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); + mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); + face_flags[fi] |= FACE_FLAG_DIVIDE_24; + } + else { + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); + mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + face_flags[fi] |= FACE_FLAG_DIVIDE_13; + } } else { - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, true); - mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth, true); - face_flags[fi] |= FACE_FLAG_DIVIDE_13; + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); } + + nverts[fi] = n; } - else - mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, false); + } + else { + vector<int> vi; + + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + int shader = clamp(p->material_index(), 0, used_shaders.size()-1); + bool smooth = p->use_smooth() || use_loop_normals; + + vi.reserve(n); + for(int i = 0; i < n; i++) { + vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); + + /* split vertices if normal is different + * + * note all vertex attributes must have been set here so we can split + * and copy attributes in split_vertex without remapping later */ + if(use_loop_normals) { + float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); + + if(N[vi[i]] != loop_N) { + int new_vi = mesh->split_vertex(vi[i]); + + /* set new normal and vertex index */ + N = attr_N->data_float3(); + N[new_vi] = loop_N; + vi[i] = new_vi; + } + } + } - nverts[fi] = n; + /* create subd faces */ + mesh->add_subd_face(&vi[0], n, shader, smooth); + } } /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ - attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags); - attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags); + attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); + attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision); /* for volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can @@ -658,16 +766,17 @@ static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Object& b_ob, BL::Mesh& b_mesh, - PointerRNA *cmesh, const vector<Shader*>& used_shaders, float dicing_rate, int max_subdivisions) { - Mesh basemesh; - create_mesh(scene, &basemesh, b_mesh, used_shaders); + create_mesh(scene, mesh, b_mesh, used_shaders, true); - SubdParams sdparams(mesh, 0, true, false); - sdparams.dicing_rate = max(0.1f, RNA_float_get(cmesh, "dicing_rate") * dicing_rate); + SubdParams sdparams(mesh); + + PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); + + sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate); sdparams.max_level = max_subdivisions; scene->camera->update(); @@ -676,11 +785,48 @@ static void create_subd_mesh(Scene *scene, /* tesselate */ DiagSplit dsplit(sdparams); - basemesh.tessellate(&dsplit); + mesh->tessellate(&dsplit); } /* Sync */ +static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) +{ + if(scene->need_motion() == Scene::MOTION_NONE) + return; + + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + + if(!b_fluid_domain) + return; + + /* If the mesh has modifiers following the fluid domain we can't export motion. */ + if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size()) + return; + + /* Find or add attribute */ + float3 *P = &mesh->verts[0]; + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; + float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); + + BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi; + int i = 0; + + for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) { + mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time; + } + } +} + Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris) @@ -759,11 +905,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, /* create derived mesh */ PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); - vector<Mesh::Triangle> oldtriangle = mesh->triangles; + array<int> oldtriangle = mesh->triangles; /* compares curve_keys rather than strands in order to handle quick hair * adjustments in dynamic BVH - other methods could probably do this better*/ - vector<float4> oldcurve_keys = mesh->curve_keys; + array<float3> oldcurve_keys = mesh->curve_keys; + array<float> oldcurve_radius = mesh->curve_radius; mesh->clear(); mesh->used_shaders = used_shaders; @@ -780,20 +927,41 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, b_ob.update_from_editmode(); bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed); + + mesh->subdivision_type = Mesh::SUBDIVISION_NONE; + + PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); + + if(cobj.data && b_ob.modifiers.length() > 0 && experimental) { + BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length()-1]; + bool enabled = preview ? mod.show_viewport() : mod.show_render(); + + if(enabled && mod.type() == BL::Modifier::type_SUBSURF && RNA_int_get(&cobj, "use_adaptive_subdivision")) { + BL::SubsurfModifier subsurf(mod); + + if(subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) { + mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK; + } + else { + mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR; + } + } + } + + BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { - if(cmesh.data && experimental && RNA_enum_get(&cmesh, "subdivision_type")) - create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders, + if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) + create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); else - create_mesh(scene, mesh, b_mesh, used_shaders); + create_mesh(scene, mesh, b_mesh, used_shaders, false); create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } - if(render_layer.use_hair) + if(render_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) sync_curves(mesh, b_mesh, b_ob, false); if(can_free_caches) { @@ -801,7 +969,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -821,20 +989,30 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->displacement_method = Mesh::DISPLACE_BOTH; } + /* fluid motion */ + sync_mesh_fluid_motion(b_ob, scene, mesh); + /* tag update */ bool rebuild = false; if(oldtriangle.size() != mesh->triangles.size()) rebuild = true; else if(oldtriangle.size()) { - if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) + if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(int)*oldtriangle.size()) != 0) rebuild = true; } if(oldcurve_keys.size() != mesh->curve_keys.size()) rebuild = true; else if(oldcurve_keys.size()) { - if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0) + if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float3)*oldcurve_keys.size()) != 0) + rebuild = true; + } + + if(oldcurve_radius.size() != mesh->curve_radius.size()) + rebuild = true; + else if(oldcurve_radius.size()) { + if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0) rebuild = true; } @@ -903,9 +1081,14 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, * would need a more extensive check to see which objects are animated */ BL::Mesh b_mesh(PointerRNA_NULL); + /* fluid motion is exported immediate with mesh, skip here */ + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + if (b_fluid_domain) + return; + if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false); + b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false); } if(!b_mesh) { @@ -931,8 +1114,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_mP) { - float4 *keys = &mesh->curve_keys[0]; - memcpy(attr_mP->data_float4() + time_index*numkeys, keys, sizeof(float4)*numkeys); + float3 *keys = &mesh->curve_keys[0]; + memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys); } } @@ -1006,7 +1189,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 80768c096e3..4886735a18f 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -253,11 +253,20 @@ static bool object_boundbox_clip(Scene *scene, boundbox[3 * i + 1], boundbox[3 * i + 2]); p = transform_point(&tfm, p); - p = transform_point(&worldtondc, p); - if(p.z >= -margin) { + + float4 b = make_float4(p.x, p.y, p.z, 1.0f); + float4 c = make_float4(dot(worldtondc.x, b), + dot(worldtondc.y, b), + dot(worldtondc.z, b), + dot(worldtondc.w, b)); + p = float4_to_float3(c / c.w); + if(c.z < 0.0f) { + p.x = 1.0f - p.x; + p.y = 1.0f - p.y; + } + if(c.z >= -margin) { all_behind = false; } - p /= p.z; bb_min = min(bb_min, p); bb_max = max(bb_max, p); } @@ -720,12 +729,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, << relative_time << "."; /* fixed shutter time to get previous and next frame for motion pass */ - float shuttertime; - - if(scene->need_motion() == Scene::MOTION_PASS) - shuttertime = 2.0f; - else - shuttertime = scene->camera->shuttertime; + float shuttertime = scene->motion_shutter_time(); /* compute frame and subframe time */ float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f; diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index d1e702cfdc2..b9876cd604f 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -76,7 +76,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob, pa.velocity = get_float3(b_pa.velocity()); pa.angular_velocity = get_float3(b_pa.angular_velocity()); - psys->particles.push_back(pa); + psys->particles.push_back_slow(pa); if(object->particle_index != psys->particles.size() - 1) scene->object_manager->tag_update(scene); diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index d2cd9307bab..7b8317a50a7 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -127,82 +127,60 @@ static float3 get_node_output_vector(BL::Node& b_node, const string& name) return make_float3(value[0], value[1], value[2]); } -static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket) +static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket) { switch(b_socket.type()) { case BL::NodeSocket::type_VALUE: - return SHADER_SOCKET_FLOAT; + return SocketType::FLOAT; case BL::NodeSocket::type_INT: - return SHADER_SOCKET_INT; + return SocketType::INT; case BL::NodeSocket::type_VECTOR: - return SHADER_SOCKET_VECTOR; + return SocketType::VECTOR; case BL::NodeSocket::type_RGBA: - return SHADER_SOCKET_COLOR; + return SocketType::COLOR; case BL::NodeSocket::type_STRING: - return SHADER_SOCKET_STRING; + return SocketType::STRING; case BL::NodeSocket::type_SHADER: - return SHADER_SOCKET_CLOSURE; + return SocketType::CLOSURE; default: - return SHADER_SOCKET_UNDEFINED; + return SocketType::UNDEFINED; } } -#ifdef WITH_OSL -static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query, - BL::NodeSocket& b_socket) -{ - ShaderSocketType socket_type = convert_socket_type(b_socket); - if(socket_type == SHADER_SOCKET_VECTOR) { - /* TODO(sergey): Do we need compatible_name() here? */ - const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name()); - assert(param != NULL); - if(param != NULL) { - if(param->type.vecsemantics == TypeDesc::POINT) { - socket_type = SHADER_SOCKET_POINT; - } - else if(param->type.vecsemantics == TypeDesc::NORMAL) { - socket_type = SHADER_SOCKET_NORMAL; - } - } - } - - return socket_type; -} -#endif /* WITH_OSL */ - static void set_default_value(ShaderInput *input, BL::NodeSocket& b_sock, BL::BlendData& b_data, BL::ID& b_id) { + Node *node = input->parent; + const SocketType& socket = input->socket_type; + /* copy values for non linked inputs */ - switch(input->type) { - case SHADER_SOCKET_FLOAT: { - input->set(get_float(b_sock.ptr, "default_value")); + switch(input->type()) { + case SocketType::FLOAT: { + node->set(socket, get_float(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_INT: { - input->set((float)get_int(b_sock.ptr, "default_value")); + case SocketType::INT: { + node->set(socket, get_int(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_COLOR: { - input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value"))); + case SocketType::COLOR: { + node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value"))); break; } - case SHADER_SOCKET_NORMAL: - case SHADER_SOCKET_POINT: - case SHADER_SOCKET_VECTOR: { - input->set(get_float3(b_sock.ptr, "default_value")); + case SocketType::NORMAL: + case SocketType::POINT: + case SocketType::VECTOR: { + node->set(socket, get_float3(b_sock.ptr, "default_value")); break; } - case SHADER_SOCKET_STRING: { - input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); + case SocketType::STRING: { + node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); break; } - - case SHADER_SOCKET_CLOSURE: - case SHADER_SOCKET_UNDEFINED: + default: break; } } @@ -315,7 +293,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) { BL::ShaderNodeMixRGB b_mix_node(b_node); MixNode *mix = new MixNode(); - mix->type = MixNode::type_enum[b_mix_node.blend_type()]; + mix->type = (NodeMix)b_mix_node.blend_type(); mix->use_clamp = b_mix_node.use_clamp(); node = mix; } @@ -341,27 +319,27 @@ static ShaderNode *add_node(Scene *scene, node = new HSVNode(); } else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) { - node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT); + node = new RGBToBWNode(); } else if(b_node.is_a(&RNA_ShaderNodeMath)) { BL::ShaderNodeMath b_math_node(b_node); MathNode *math = new MathNode(); - math->type = MathNode::type_enum[b_math_node.operation()]; + math->type = (NodeMath)b_math_node.operation(); math->use_clamp = b_math_node.use_clamp(); node = math; } else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) { BL::ShaderNodeVectorMath b_vector_math_node(b_node); VectorMathNode *vmath = new VectorMathNode(); - vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()]; + vmath->type = (NodeVectorMath)b_vector_math_node.operation(); node = vmath; } else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) { BL::ShaderNodeVectorTransform b_vector_transform_node(b_node); VectorTransformNode *vtransform = new VectorTransformNode(); - vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()]; - vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()]; - vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()]; + vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type(); + vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from(); + vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to(); node = vtransform; } else if(b_node.is_a(&RNA_ShaderNodeNormal)) { @@ -410,13 +388,16 @@ static ShaderNode *add_node(Scene *scene, switch(b_aniso_node.distribution()) { case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN: - aniso->distribution = ustring("Beckmann"); + aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; break; case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: - aniso->distribution = ustring("GGX"); + aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; + break; + case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; break; case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: - aniso->distribution = ustring("Ashikhmin-Shirley"); + aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; } @@ -432,13 +413,13 @@ static ShaderNode *add_node(Scene *scene, switch(b_subsurface_node.falloff()) { case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC: - subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID; + subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID; break; case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN: - subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID; + subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID; break; case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY: - subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID; + subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID; break; } @@ -450,16 +431,19 @@ static ShaderNode *add_node(Scene *scene, switch(b_glossy_node.distribution()) { case BL::ShaderNodeBsdfGlossy::distribution_SHARP: - glossy->distribution = ustring("Sharp"); + glossy->distribution = CLOSURE_BSDF_REFLECTION_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN: - glossy->distribution = ustring("Beckmann"); + glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_GGX: - glossy->distribution = ustring("GGX"); + glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: - glossy->distribution = ustring("Ashikhmin-Shirley"); + glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; break; } node = glossy; @@ -469,13 +453,16 @@ static ShaderNode *add_node(Scene *scene, GlassBsdfNode *glass = new GlassBsdfNode(); switch(b_glass_node.distribution()) { case BL::ShaderNodeBsdfGlass::distribution_SHARP: - glass->distribution = ustring("Sharp"); + glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID; break; case BL::ShaderNodeBsdfGlass::distribution_BECKMANN: - glass->distribution = ustring("Beckmann"); + glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID; break; case BL::ShaderNodeBsdfGlass::distribution_GGX: - glass->distribution = ustring("GGX"); + glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; + break; + case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; break; } node = glass; @@ -485,13 +472,13 @@ static ShaderNode *add_node(Scene *scene, RefractionBsdfNode *refraction = new RefractionBsdfNode(); switch(b_refraction_node.distribution()) { case BL::ShaderNodeBsdfRefraction::distribution_SHARP: - refraction->distribution = ustring("Sharp"); + refraction->distribution = CLOSURE_BSDF_REFRACTION_ID; break; case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN: - refraction->distribution = ustring("Beckmann"); + refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; break; case BL::ShaderNodeBsdfRefraction::distribution_GGX: - refraction->distribution = ustring("GGX"); + refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; break; } node = refraction; @@ -501,10 +488,10 @@ static ShaderNode *add_node(Scene *scene, ToonBsdfNode *toon = new ToonBsdfNode(); switch(b_toon_node.component()) { case BL::ShaderNodeBsdfToon::component_DIFFUSE: - toon->component = ustring("Diffuse"); + toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID; break; case BL::ShaderNodeBsdfToon::component_GLOSSY: - toon->component = ustring("Glossy"); + toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID; break; } node = toon; @@ -514,10 +501,10 @@ static ShaderNode *add_node(Scene *scene, HairBsdfNode *hair = new HairBsdfNode(); switch(b_hair_node.component()) { case BL::ShaderNodeBsdfHair::component_Reflection: - hair->component = ustring("Reflection"); + hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID; break; case BL::ShaderNodeBsdfHair::component_Transmission: - hair->component = ustring("Transmission"); + hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; break; } node = hair; @@ -587,62 +574,17 @@ static ShaderNode *add_node(Scene *scene, if(scene->shader_manager->use_osl()) { /* create script node */ BL::ShaderNodeScript b_script_node(b_node); - OSLScriptNode *script_node = new OSLScriptNode(); OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager; string bytecode_hash = b_script_node.bytecode_hash(); - /* Gather additional information from the shader, such as - * input/output type info needed for proper node construction. - */ - OSL::OSLQuery query; - string absolute_filepath; - if(!bytecode_hash.empty()) { - query.open_bytecode(b_script_node.bytecode()); + node = manager->osl_node("", bytecode_hash, b_script_node.bytecode()); } else { - absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath()); - OSLShaderManager::osl_query(query, absolute_filepath); - } - /* TODO(sergey): Add proper query info error parsing. */ - - /* Generate inputs/outputs from node sockets - * - * Note: the node sockets are generated from OSL parameters, - * so the names match those of the corresponding parameters exactly. - * - * Note 2: ShaderInput/ShaderOutput store shallow string copies only! - * So we register them as ustring to ensure the pointer stays valid. */ - BL::Node::inputs_iterator b_input; - - for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) { - ShaderInput *input = script_node->add_input(ustring(b_input->name()).c_str(), - convert_osl_socket_type(query, *b_input)); - set_default_value(input, *b_input, b_data, b_ntree); - } - - BL::Node::outputs_iterator b_output; - - for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) { - script_node->add_output(ustring(b_output->name()).c_str(), - convert_osl_socket_type(query, *b_output)); + string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath()); + node = manager->osl_node(absolute_filepath, ""); } - - /* load bytecode or filepath */ - if(!bytecode_hash.empty()) { - /* loaded bytecode if not already done */ - if(!manager->shader_test_loaded(bytecode_hash)) - manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode()); - - script_node->bytecode_hash = bytecode_hash; - } - else { - /* set filepath */ - script_node->filepath = absolute_filepath; - } - - node = script_node; } #else (void)b_data; @@ -689,14 +631,14 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Does not work properly when we change builtin type. */ if(b_image.is_updated()) { scene->image_manager->tag_reload_image( - image->filename, + image->filename.string(), image->builtin_data, get_image_interpolation(b_image_node), get_image_extension(b_image_node)); } } - image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()]; - image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()]; + image->color_space = (NodeImageColorSpace)b_image_node.color_space(); + image->projection = (NodeImageProjection)b_image_node.projection(); image->interpolation = get_image_interpolation(b_image_node); image->extension = get_image_extension(b_image_node); image->projection_blend = b_image_node.projection_blend(); @@ -735,15 +677,15 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Does not work properly when we change builtin type. */ if(b_image.is_updated()) { scene->image_manager->tag_reload_image( - env->filename, + env->filename.string(), env->builtin_data, get_image_interpolation(b_env_node), EXTENSION_REPEAT); } } - env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()]; + env->color_space = (NodeImageColorSpace)b_env_node.color_space(); env->interpolation = get_image_interpolation(b_env_node); - env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()]; + env->projection = (NodeEnvironmentProjection)b_env_node.projection(); BL::TexMapping b_texture_mapping(b_env_node.texture_mapping()); get_tex_mapping(&env->tex_mapping, b_texture_mapping); node = env; @@ -751,7 +693,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) { BL::ShaderNodeTexGradient b_gradient_node(b_node); GradientTextureNode *gradient = new GradientTextureNode(); - gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()]; + gradient->type = (NodeGradientType)b_gradient_node.gradient_type(); BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping()); get_tex_mapping(&gradient->tex_mapping, b_texture_mapping); node = gradient; @@ -759,7 +701,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) { BL::ShaderNodeTexVoronoi b_voronoi_node(b_node); VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()]; + voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring(); BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping()); get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping); node = voronoi; @@ -775,8 +717,8 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexWave)) { BL::ShaderNodeTexWave b_wave_node(b_node); WaveTextureNode *wave = new WaveTextureNode(); - wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()]; - wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()]; + wave->type = (NodeWaveType)b_wave_node.wave_type(); + wave->profile = (NodeWaveProfile)b_wave_node.wave_profile(); BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping()); get_tex_mapping(&wave->tex_mapping, b_texture_mapping); node = wave; @@ -809,7 +751,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) { BL::ShaderNodeTexMusgrave b_musgrave_node(b_node); MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()]; + musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type(); BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping()); get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping); node = musgrave; @@ -827,7 +769,7 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeTexSky)) { BL::ShaderNodeTexSky b_sky_node(b_node); SkyTextureNode *sky = new SkyTextureNode(); - sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()]; + sky->type = (NodeSkyType)b_sky_node.sky_type(); sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction())); sky->turbidity = b_sky_node.turbidity(); sky->ground_albedo = b_sky_node.ground_albedo(); @@ -838,15 +780,15 @@ static ShaderNode *add_node(Scene *scene, else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) { BL::ShaderNodeNormalMap b_normal_map_node(b_node); NormalMapNode *nmap = new NormalMapNode(); - nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()]; + nmap->space = (NodeNormalMapSpace)b_normal_map_node.space(); nmap->attribute = b_normal_map_node.uv_map(); node = nmap; } else if(b_node.is_a(&RNA_ShaderNodeTangent)) { BL::ShaderNodeTangent b_tangent_node(b_node); TangentNode *tangent = new TangentNode(); - tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()]; - tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()]; + tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type(); + tangent->axis = (NodeTangentAxis)b_tangent_node.axis(); tangent->attribute = b_tangent_node.uv_map(); node = tangent; } @@ -861,8 +803,7 @@ static ShaderNode *add_node(Scene *scene, BL::ShaderNodeTexPointDensity b_point_density_node(b_node); PointDensityTextureNode *point_density = new PointDensityTextureNode(); point_density->filename = b_point_density_node.name(); - point_density->space = - PointDensityTextureNode::space_enum[(int)b_point_density_node.space()]; + point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); point_density->interpolation = get_image_interpolation(b_point_density_node); point_density->builtin_data = b_point_density_node.ptr.data; @@ -873,7 +814,7 @@ static ShaderNode *add_node(Scene *scene, if(true) { b_point_density_node.cache_point_density(b_scene, settings); scene->image_manager->tag_reload_image( - point_density->filename, + point_density->filename.string(), point_density->builtin_data, point_density->interpolation, EXTENSION_CLIP); @@ -1023,7 +964,7 @@ static void add_nodes(Scene *scene, BL::Node::internal_links_iterator b_link; for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) { BL::NodeSocket to_socket(b_link->to_socket()); - ShaderSocketType to_socket_type = convert_socket_type(to_socket); + SocketType::Type to_socket_type = convert_socket_type(to_socket); ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true); input_map[b_link->from_socket().ptr.data] = proxy->inputs[0]; @@ -1046,7 +987,7 @@ static void add_nodes(Scene *scene, * so that links have something to connect to and assert won't fail. */ for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { - ShaderSocketType input_type = convert_socket_type(*b_input); + SocketType::Type input_type = convert_socket_type(*b_input); ConvertNode *proxy = new ConvertNode(input_type, input_type, true); graph->add(proxy); @@ -1058,7 +999,7 @@ static void add_nodes(Scene *scene, set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); } for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { - ShaderSocketType output_type = convert_socket_type(*b_output); + SocketType::Type output_type = convert_socket_type(*b_output); ConvertNode *proxy = new ConvertNode(output_type, output_type, true); graph->add(proxy); @@ -1227,13 +1168,12 @@ void BlenderSync::sync_materials(bool update_all) add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { - ShaderNode *closure, *out; - - closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->value = get_float3(b_mat->diffuse_color()); - out = graph->output(); + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = get_float3(b_mat->diffuse_color()); + graph->add(diffuse); - graph->connect(closure->output("BSDF"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(diffuse->output("BSDF"), out->input("Surface")); } /* settings */ @@ -1276,13 +1216,12 @@ void BlenderSync::sync_world(bool update_all) shader->volume_interpolation_method = get_volume_interpolation(cworld); } else if(b_world) { - ShaderNode *closure, *out; - - closure = graph->add(new BackgroundNode()); - closure->input("Color")->value = get_float3(b_world.horizon_color()); - out = graph->output(); + BackgroundNode *background = new BackgroundNode(); + background->color = get_float3(b_world.horizon_color()); + graph->add(background); - graph->connect(closure->output("Background"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(background->output("Background"), out->input("Surface")); } if(b_world) { @@ -1361,7 +1300,6 @@ void BlenderSync::sync_lamps(bool update_all) add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { - ShaderNode *closure, *out; float strength = 1.0f; if(b_lamp->type() == BL::Lamp::type_POINT || @@ -1371,12 +1309,13 @@ void BlenderSync::sync_lamps(bool update_all) strength = 100.0f; } - closure = graph->add(new EmissionNode()); - closure->input("Color")->value = get_float3(b_lamp->color()); - closure->input("Strength")->value.x = strength; - out = graph->output(); + EmissionNode *emission = new EmissionNode(); + emission->color = get_float3(b_lamp->color()); + emission->strength = strength; + graph->add(emission); - graph->connect(closure->output("Emission"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(emission->output("Emission"), out->input("Surface")); } shader->set_graph(graph); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 33084f1c163..e7e57b2be36 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -492,6 +492,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, SceneParams::BVH_STATIC); params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); + params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); if(background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d690adb5662..b8b9597914e 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -131,7 +131,9 @@ private: Transform& tfm, bool *use_portal); void sync_background_light(bool use_portal); - void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time); + void sync_mesh_motion(BL::Object& b_ob, + Object *object, + float motion_time); void sync_camera_motion(BL::RenderSettings& b_render, BL::Object& b_ob, int width, int height, diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index e23d8bf4e2d..d5dbaba094b 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -45,14 +45,39 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Scene& scene, bool apply_modifiers, bool render, - bool calc_undeformed) + bool calc_undeformed, + bool subdivision) { + bool subsurf_mod_show_render; + bool subsurf_mod_show_viewport; + + if(subdivision) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; + + subsurf_mod_show_render = subsurf_mod.show_render(); + subsurf_mod_show_viewport = subsurf_mod.show_render(); + + subsurf_mod.show_render(false); + subsurf_mod.show_viewport(false); + + } + BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); + + if(subdivision) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; + + subsurf_mod.show_render(subsurf_mod_show_render); + subsurf_mod.show_viewport(subsurf_mod_show_viewport); + } + if((bool)me) { if(me.use_auto_smooth()) { me.calc_normals_split(); } - me.calc_tessface(true); + if(!subdivision) { + me.calc_tessface(true); + } } return me; } @@ -98,11 +123,12 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap, } static inline void curvemapping_to_array(BL::CurveMapping& cumap, - float *data, + array<float>& data, int size) { cumap.update(); BL::CurveMap curve = cumap.curves[0]; + data.resize(size); for(int i = 0; i < size; i++) { float t = (float)i/(float)(size-1); data[i] = curve.evaluate(t); @@ -518,6 +544,23 @@ static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob) return BL::SmokeDomainSettings(PointerRNA_NULL); } +static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob) +{ + BL::Object::modifiers_iterator b_mod; + + for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if(b_mod->is_a(&RNA_FluidSimulationModifier)) { + BL::FluidSimulationModifier b_fmd(*b_mod); + BL::FluidSettings fss = b_fmd.settings(); + + if(fss.type() == BL::FluidSettings::type_DOMAIN) + return (BL::DomainFluidSettings)b_fmd.settings(); + } + } + + return BL::DomainFluidSettings(PointerRNA_NULL); +} + /* ID Map * * Utility class to keep in sync with blender data. diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt index 5729fa6113d..92e48f0d87f 100644 --- a/intern/cycles/bvh/CMakeLists.txt +++ b/intern/cycles/bvh/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRC bvh_node.cpp bvh_sort.cpp bvh_split.cpp + bvh_unaligned.cpp ) set(SRC_HEADERS @@ -29,6 +30,7 @@ set(SRC_HEADERS bvh_params.h bvh_sort.h bvh_split.h + bvh_unaligned.h ) include_directories(${INC}) diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 5c474c8c3e9..1bb3e95c810 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -24,6 +24,7 @@ #include "bvh_build.h" #include "bvh_node.h" #include "bvh_params.h" +#include "bvh_unaligned.h" #include "util_debug.h" #include "util_foreach.h" @@ -121,57 +122,66 @@ void BVH::refit(Progress& progress) /* Triangles */ -void BVH::pack_triangle(int idx, float4 storage[3]) +void BVH::pack_triangle(int idx, float4 tri_verts[3]) { int tob = pack.prim_object[idx]; assert(tob >= 0 && tob < objects.size()); const Mesh *mesh = objects[tob]->mesh; int tidx = pack.prim_index[idx]; - const int *vidx = mesh->triangles[tidx].v; - const float3* vpos = &mesh->verts[0]; - float3 v0 = vpos[vidx[0]]; - float3 v1 = vpos[vidx[1]]; - float3 v2 = vpos[vidx[2]]; - - storage[0] = float3_to_float4(v0); - storage[1] = float3_to_float4(v1); - storage[2] = float3_to_float4(v2); + Mesh::Triangle t = mesh->get_triangle(tidx); + const float3 *vpos = &mesh->verts[0]; + float3 v0 = vpos[t.v[0]]; + float3 v1 = vpos[t.v[1]]; + float3 v2 = vpos[t.v[2]]; + + tri_verts[0] = float3_to_float4(v0); + tri_verts[1] = float3_to_float4(v1); + tri_verts[2] = float3_to_float4(v2); } void BVH::pack_primitives() { - int nsize = TRI_NODE_SIZE; - size_t tidx_size = pack.prim_index.size(); - - pack.tri_storage.clear(); - pack.tri_storage.resize(tidx_size * nsize); + const size_t tidx_size = pack.prim_index.size(); + size_t num_prim_triangles = 0; + /* Count number of triangles primitives in BVH. */ + for(unsigned int i = 0; i < tidx_size; i++) { + if((pack.prim_index[i] != -1)) { + if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + ++num_prim_triangles; + } + } + } + /* Reserve size for arrays. */ + pack.prim_tri_index.clear(); + pack.prim_tri_index.resize(tidx_size); + pack.prim_tri_verts.clear(); + pack.prim_tri_verts.resize(num_prim_triangles * 3); pack.prim_visibility.clear(); pack.prim_visibility.resize(tidx_size); - + /* Fill in all the arrays. */ + size_t prim_triangle_index = 0; for(unsigned int i = 0; i < tidx_size; i++) { if(pack.prim_index[i] != -1) { - float4 storage[3]; + int tob = pack.prim_object[i]; + Object *ob = objects[tob]; - if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) { - pack_triangle(i, storage); + if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]); + pack.prim_tri_index[i] = 3 * prim_triangle_index; + ++prim_triangle_index; } else { - /* Avoid use of uninitialized memory. */ - memset(&storage, 0, sizeof(storage)); + pack.prim_tri_index[i] = -1; } - memcpy(&pack.tri_storage[i * nsize], storage, sizeof(float4)*3); - - int tob = pack.prim_object[i]; - Object *ob = objects[tob]; pack.prim_visibility[i] = ob->visibility; if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) pack.prim_visibility[i] |= PATH_RAY_CURVE; } else { - memset(&pack.tri_storage[i * nsize], 0, sizeof(float4)*3); + pack.prim_tri_index[i] = -1; pack.prim_visibility[i] = 0; } } @@ -183,13 +193,13 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) { /* The BVH's for instances are built separately, but for traversal all * BVH's are stored in global arrays. This function merges them into the - * top level BVH, adjusting indexes and offsets where appropriate. */ - bool use_qbvh = params.use_qbvh; - size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE; - size_t nsize_leaf = (use_qbvh)? BVH_QNODE_LEAF_SIZE: BVH_NODE_LEAF_SIZE; + * top level BVH, adjusting indexes and offsets where appropriate. + */ + const bool use_qbvh = params.use_qbvh; - /* adjust primitive index to point to the triangle in the global array, for - * meshes with transform applied and already in the top level BVH */ + /* Adjust primitive index to point to the triangle in the global array, for + * meshes with transform applied and already in the top level BVH. + */ for(size_t i = 0; i < pack.prim_index.size(); i++) if(pack.prim_index[i] != -1) { if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) @@ -208,10 +218,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) /* reserve */ size_t prim_index_size = pack.prim_index.size(); - size_t tri_storage_size = pack.tri_storage.size(); + size_t prim_tri_verts_size = pack.prim_tri_verts.size(); size_t pack_prim_index_offset = prim_index_size; - size_t pack_tri_storage_offset = tri_storage_size; + size_t pack_prim_tri_verts_offset = prim_tri_verts_size; size_t pack_nodes_offset = nodes_size; size_t pack_leaf_nodes_offset = leaf_nodes_size; size_t object_offset = 0; @@ -225,7 +235,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) if(mesh->need_build_bvh()) { if(mesh_map.find(mesh) == mesh_map.end()) { prim_index_size += bvh->pack.prim_index.size(); - tri_storage_size += bvh->pack.tri_storage.size(); + prim_tri_verts_size += bvh->pack.prim_tri_verts.size(); nodes_size += bvh->pack.nodes.size(); leaf_nodes_size += bvh->pack.leaf_nodes.size(); @@ -240,7 +250,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) pack.prim_type.resize(prim_index_size); pack.prim_object.resize(prim_index_size); pack.prim_visibility.resize(prim_index_size); - pack.tri_storage.resize(tri_storage_size); + pack.prim_tri_verts.resize(prim_tri_verts_size); + pack.prim_tri_index.resize(prim_index_size); pack.nodes.resize(nodes_size); pack.leaf_nodes.resize(leaf_nodes_size); pack.object_node.resize(objects.size()); @@ -249,7 +260,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL; int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL; uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL; - float4 *pack_tri_storage = (pack.tri_storage.size())? &pack.tri_storage[0]: NULL; + float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL; + uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL; int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL; int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL; @@ -277,8 +289,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) BVH *bvh = mesh->bvh; - int noffset = nodes_offset/nsize; - int noffset_leaf = nodes_leaf_offset/nsize_leaf; + int noffset = nodes_offset; + int noffset_leaf = nodes_leaf_offset; int mesh_tri_offset = mesh->tri_offset; int mesh_curve_offset = mesh->curve_offset; @@ -290,18 +302,24 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) mesh_map[mesh] = pack.object_node[object_offset-1]; - /* merge primitive and object indexes */ + /* merge primitive, object and triangle indexes */ if(bvh->pack.prim_index.size()) { size_t bvh_prim_index_size = bvh->pack.prim_index.size(); int *bvh_prim_index = &bvh->pack.prim_index[0]; int *bvh_prim_type = &bvh->pack.prim_type[0]; uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0]; + uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0]; for(size_t i = 0; i < bvh_prim_index_size; i++) { - if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) + if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; - else + pack_prim_tri_index[pack_prim_index_offset] = -1; + } + else { pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + pack_prim_tri_index[pack_prim_index_offset] = + bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; + } pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; @@ -310,50 +328,64 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) } } - /* merge triangle intersection data */ - if(bvh->pack.tri_storage.size()) { - memcpy(pack_tri_storage + pack_tri_storage_offset, - &bvh->pack.tri_storage[0], - bvh->pack.tri_storage.size()*sizeof(float4)); - pack_tri_storage_offset += bvh->pack.tri_storage.size(); + /* Merge triangle vertices data. */ + if(bvh->pack.prim_tri_verts.size()) { + const size_t prim_tri_size = bvh->pack.prim_tri_verts.size(); + memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset, + &bvh->pack.prim_tri_verts[0], + prim_tri_size*sizeof(float4)); + pack_prim_tri_verts_offset += prim_tri_size; } /* merge nodes */ if(bvh->pack.leaf_nodes.size()) { int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0]; size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size(); - for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; i+=nsize_leaf, j++) { + for(size_t i = 0, j = 0; + i < leaf_nodes_offset_size; + i+= BVH_NODE_LEAF_SIZE, j++) + { int4 data = leaf_nodes_offset[i]; data.x += prim_offset; data.y += prim_offset; pack_leaf_nodes[pack_leaf_nodes_offset] = data; - for(int j = 1; j < nsize_leaf; ++j) { + for(int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) { pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j]; } - pack_leaf_nodes_offset += nsize_leaf; + pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE; } } if(bvh->pack.nodes.size()) { - /* For QBVH we're packing a child bbox into 6 float4, - * and for regular BVH they're packed into 3 float4. - */ - size_t nsize_bbox = (use_qbvh)? 6: 3; int4 *bvh_nodes = &bvh->pack.nodes[0]; - size_t bvh_nodes_size = bvh->pack.nodes.size(); + size_t bvh_nodes_size = bvh->pack.nodes.size(); + + for(size_t i = 0, j = 0; i < bvh_nodes_size; j++) { + size_t nsize, nsize_bbox; + if(bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) { + nsize = use_qbvh + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_UNALIGNED_NODE_SIZE; + nsize_bbox = (use_qbvh)? 13: 0; + } + else { + nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE; + nsize_bbox = (use_qbvh)? 7: 0; + } - for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) { - memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4)); + memcpy(pack_nodes + pack_nodes_offset, + bvh_nodes + i, + nsize_bbox*sizeof(int4)); - /* modify offsets into arrays */ + /* Modify offsets into arrays */ int4 data = bvh_nodes[i + nsize_bbox]; - data.x += (data.x < 0)? -noffset_leaf: noffset; - data.y += (data.y < 0)? -noffset_leaf: noffset; + data.z += (data.z < 0)? -noffset_leaf: noffset; + data.w += (data.w < 0)? -noffset_leaf: noffset; if(use_qbvh) { - data.z += (data.z < 0)? -noffset_leaf: noffset; - data.w += (data.w < 0)? -noffset_leaf: noffset; + data.x += (data.x < 0)? -noffset_leaf: noffset; + data.y += (data.y < 0)? -noffset_leaf: noffset; } pack_nodes[pack_nodes_offset + nsize_bbox] = data; @@ -366,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) sizeof(int4) * (nsize - (nsize_bbox+1))); pack_nodes_offset += nsize; + i += nsize; } } @@ -377,12 +410,20 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) /* Regular BVH */ +static bool node_bvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + return node0->is_unaligned() || node1->is_unaligned(); +} + RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_) : BVH(params_, objects_) { } -void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) +void RegularBVH::pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf) { float4 data[BVH_NODE_LEAF_SIZE]; memset(data, 0, sizeof(data)); @@ -401,54 +442,130 @@ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); } - memcpy(&pack.leaf_nodes[e.idx * BVH_NODE_LEAF_SIZE], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); +} + +void RegularBVH::pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) +{ + if (e0.node->is_unaligned() || e1.node->is_unaligned()) { + pack_unaligned_inner(e, e0, e1); + } else { + pack_aligned_inner(e, e0, e1); + } } -void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1) +void RegularBVH::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) { - pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility); + pack_aligned_node(e.idx, + e0.node->m_bounds, e1.node->m_bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->m_visibility, e1.node->m_visibility); } -void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1) +void RegularBVH::pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1) { int4 data[BVH_NODE_SIZE] = { + make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED, + visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1), make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)), make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)), make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)), - make_int4(c0, c1, visibility0, visibility1) }; - memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE); + memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE); } -void RegularBVH::pack_nodes(const BVHNode *root) +void RegularBVH::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) { - size_t tot_node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT); - size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - size_t node_size = tot_node_size - leaf_node_size; + pack_unaligned_node(e.idx, + e0.node->get_aligned_space(), + e1.node->get_aligned_space(), + e0.node->m_bounds, + e1.node->m_bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->m_visibility, e1.node->m_visibility); +} - /* resize arrays */ - pack.nodes.clear(); +void RegularBVH::pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& bounds0, + const BoundBox& bounds1, + int c0, int c1, + uint visibility0, uint visibility1) +{ + float4 data[BVH_UNALIGNED_NODE_SIZE]; + Transform space0 = BVHUnaligned::compute_node_transform(bounds0, + aligned_space0); + Transform space1 = BVHUnaligned::compute_node_transform(bounds1, + aligned_space1); + data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(c0), + __int_as_float(c1)); + + data[1] = space0.x; + data[2] = space0.y; + data[3] = space0.z; + data[4] = space1.x; + data[5] = space1.y; + data[6] = space1.z; + + memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE); +} - /* for top level BVH, first merge existing BVH's so we know the offsets */ +void RegularBVH::pack_nodes(const BVHNode *root) +{ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_NODE_SIZE; + } + /* Resize arrays */ + pack.nodes.clear(); + pack.leaf_nodes.clear(); + /* For top level BVH, first merge existing BVH's so we know the offsets. */ if(params.top_level) { - pack_instances(node_size*BVH_NODE_SIZE, - leaf_node_size*BVH_NODE_LEAF_SIZE); + pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE); } else { - pack.nodes.resize(node_size*BVH_NODE_SIZE); - pack.leaf_nodes.resize(leaf_node_size*BVH_NODE_LEAF_SIZE); + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE); } int nextNodeIdx = 0, nextLeafNodeIdx = 0; vector<BVHStackEntry> stack; stack.reserve(BVHParams::MAX_DEPTH*2); - if(root->is_leaf()) + if(root->is_leaf()) { stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); - else - stack.push_back(BVHStackEntry(root, nextNodeIdx++)); + } + else { + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_bvh_is_unaligned(root) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } while(stack.size()) { BVHStackEntry e = stack.back(); @@ -456,20 +573,31 @@ void RegularBVH::pack_nodes(const BVHNode *root) if(e.node->is_leaf()) { /* leaf node */ - const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node); + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); pack_leaf(e, leaf); } else { /* innner node */ - int idx0 = (e.node->get_child(0)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++); - int idx1 = (e.node->get_child(1)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++); - stack.push_back(BVHStackEntry(e.node->get_child(0), idx0)); - stack.push_back(BVHStackEntry(e.node->get_child(1), idx1)); + int idx[2]; + for (int i = 0; i < 2; ++i) { + if (e.node->get_child(i)->is_leaf()) { + idx[i] = nextLeafNodeIdx++; + } + else { + idx[i] = nextNodeIdx; + nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i)) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } + } + + stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0])); + stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1])); pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]); } } - + assert(node_size == nextNodeIdx); /* root index to start traversal at, to handle case of single leaf node */ pack.root_index = (root->is_leaf())? -1: 0; } @@ -486,7 +614,7 @@ void RegularBVH::refit_nodes() void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { if(leaf) { - int4 *data = &pack.leaf_nodes[idx*BVH_NODE_LEAF_SIZE]; + int4 *data = &pack.leaf_nodes[idx]; int c0 = data[0].x; int c1 = data[0].y; /* refit leaf node */ @@ -506,10 +634,10 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* curves */ int str_offset = (params.top_level)? mesh->curve_offset: 0; - const Mesh::Curve& curve = mesh->curves[pidx - str_offset]; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], bbox); + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; @@ -520,17 +648,17 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; - float4 *key_steps = attr->data_float4(); + float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bbox); + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* triangles */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset]; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); @@ -560,14 +688,12 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility leaf_data[0].y = __int_as_float(c1); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(data[0].w); - memcpy(&pack.leaf_nodes[idx * BVH_NODE_LEAF_SIZE], - leaf_data, - sizeof(float4)*BVH_NODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE); } else { - int4 *data = &pack.nodes[idx*BVH_NODE_SIZE]; - int c0 = data[3].x; - int c1 = data[3].y; + int4 *data = &pack.nodes[idx]; + int c0 = data[0].z; + int c1 = data[0].w; /* refit inner node, set bbox from children */ BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty; uint visibility0 = 0, visibility1 = 0; @@ -575,7 +701,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0); refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1); - pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1); + pack_aligned_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1); bbox.grow(bbox0); bbox.grow(bbox1); @@ -585,6 +711,33 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility /* QBVH */ +/* Can we avoid this somehow or make more generic? + * + * Perhaps we can merge nodes in actual tree and make our + * life easier all over the place. + */ +static bool node_qbvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + bool has_unaligned = false; + if(node0->is_leaf()) { + has_unaligned |= node0->is_unaligned(); + } + else { + has_unaligned |= node0->get_child(0)->is_unaligned(); + has_unaligned |= node0->get_child(1)->is_unaligned(); + } + if(node1->is_leaf()) { + has_unaligned |= node1->is_unaligned(); + } + else { + has_unaligned |= node1->get_child(0)->is_unaligned(); + has_unaligned |= node1->get_child(1)->is_unaligned(); + } + return has_unaligned; +} + QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_) : BVH(params_, objects_) { @@ -610,66 +763,153 @@ void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); } - memcpy(&pack.leaf_nodes[e.idx * BVH_QNODE_LEAF_SIZE], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); +} + +void QBVH::pack_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + bool has_unaligned = false; + /* Check whether we have to create unaligned node or all nodes are aligned + * and we can cut some corner here. + */ + if(params.use_unaligned_nodes) { + for(int i = 0; i < num; i++) { + if(en[i].node->is_unaligned()) { + has_unaligned = true; + break; + } + } + } + if(has_unaligned) { + /* There's no unaligned children, pack into AABB node. */ + pack_unaligned_inner(e, en, num); + } + else { + /* Create unaligned node with orientation transform for each of the + * children. + */ + pack_aligned_inner(e, en, num); + } } -void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num) +void QBVH::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) { float4 data[BVH_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + data[0].x = __uint_as_float(e.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED); for(int i = 0; i < num; i++) { float3 bb_min = en[i].node->m_bounds.min; float3 bb_max = en[i].node->m_bounds.max; - data[0][i] = bb_min.x; - data[1][i] = bb_max.x; - data[2][i] = bb_min.y; - data[3][i] = bb_max.y; - data[4][i] = bb_min.z; - data[5][i] = bb_max.z; + data[1][i] = bb_min.x; + data[2][i] = bb_max.x; + data[3][i] = bb_min.y; + data[4][i] = bb_max.y; + data[5][i] = bb_min.z; + data[6][i] = bb_max.z; - data[6][i] = __int_as_float(en[i].encodeIdx()); + data[7][i] = __int_as_float(en[i].encodeIdx()); } for(int i = num; i < 4; i++) { /* We store BB which would never be recorded as intersection * so kernel might safely assume there are always 4 child nodes. */ - data[0][i] = FLT_MAX; - data[1][i] = -FLT_MAX; + data[1][i] = FLT_MAX; + data[2][i] = -FLT_MAX; - data[2][i] = FLT_MAX; - data[3][i] = -FLT_MAX; + data[3][i] = FLT_MAX; + data[4][i] = -FLT_MAX; - data[4][i] = FLT_MAX; - data[5][i] = -FLT_MAX; + data[5][i] = FLT_MAX; + data[6][i] = -FLT_MAX; - data[6][i] = __int_as_float(0); + data[7][i] = __int_as_float(0); } - memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE); + memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_QNODE_SIZE); +} + +void QBVH::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + float4 data[BVH_UNALIGNED_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + + data[0].x = __uint_as_float(e.node->m_visibility | PATH_RAY_NODE_UNALIGNED); + + for(int i = 0; i < num; i++) { + Transform space = BVHUnaligned::compute_node_transform( + en[i].node->m_bounds, + en[i].node->get_aligned_space()); + + data[1][i] = space.x.x; + data[2][i] = space.x.y; + data[3][i] = space.x.z; + + data[4][i] = space.y.x; + data[5][i] = space.y.y; + data[6][i] = space.y.z; + + data[7][i] = space.z.x; + data[8][i] = space.z.y; + data[9][i] = space.z.z; + + data[10][i] = space.x.w; + data[11][i] = space.y.w; + data[12][i] = space.z.w; + + data[13][i] = __int_as_float(en[i].encodeIdx()); + } + + for(int i = num; i < 4; i++) { + /* We store BB which would never be recorded as intersection + * so kernel might safely assume there are always 4 child nodes. + */ + for(int j = 1; j < 13; ++j) { + data[j][i] = 0.0f; + } + data[13][i] = __int_as_float(0); + } + + memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); } /* Quad SIMD Nodes */ void QBVH::pack_nodes(const BVHNode *root) { - size_t tot_node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); - size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - size_t node_size = tot_node_size - leaf_node_size; - - /* resize arrays */ + /* Calculate size of the arrays required. */ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_QNODE_SIZE; + } + /* Resize arrays. */ pack.nodes.clear(); pack.leaf_nodes.clear(); - - /* for top level BVH, first merge existing BVH's so we know the offsets */ + /* For top level BVH, first merge existing BVH's so we know the offsets. */ if(params.top_level) { - pack_instances(node_size*BVH_QNODE_SIZE, - leaf_node_size*BVH_QNODE_LEAF_SIZE); + pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE); } else { - pack.nodes.resize(node_size*BVH_QNODE_SIZE); - pack.leaf_nodes.resize(leaf_node_size*BVH_QNODE_LEAF_SIZE); + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE); } int nextNodeIdx = 0, nextLeafNodeIdx = 0; @@ -680,7 +920,10 @@ void QBVH::pack_nodes(const BVHNode *root) stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); } else { - stack.push_back(BVHStackEntry(root, nextNodeIdx++)); + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_qbvh_is_unaligned(root) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; } while(stack.size()) { @@ -689,19 +932,17 @@ void QBVH::pack_nodes(const BVHNode *root) if(e.node->is_leaf()) { /* leaf node */ - const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node); + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); pack_leaf(e, leaf); } else { - /* inner node */ + /* Inner node. */ const BVHNode *node = e.node; const BVHNode *node0 = node->get_child(0); const BVHNode *node1 = node->get_child(1); - - /* collect nodes */ + /* Collect nodes. */ const BVHNode *nodes[4]; int numnodes = 0; - if(node0->is_leaf()) { nodes[numnodes++] = node0; } @@ -709,7 +950,6 @@ void QBVH::pack_nodes(const BVHNode *root) nodes[numnodes++] = node0->get_child(0); nodes[numnodes++] = node0->get_child(1); } - if(node1->is_leaf()) { nodes[numnodes++] = node1; } @@ -717,25 +957,26 @@ void QBVH::pack_nodes(const BVHNode *root) nodes[numnodes++] = node1->get_child(0); nodes[numnodes++] = node1->get_child(1); } - - /* push entries on the stack */ - for(int i = 0; i < numnodes; i++) { + /* Push entries on the stack. */ + for(int i = 0; i < numnodes; ++i) { int idx; if(nodes[i]->is_leaf()) { idx = nextLeafNodeIdx++; } else { - idx = nextNodeIdx++; + idx = nextNodeIdx; + nextNodeIdx += node_qbvh_is_unaligned(nodes[i]) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; } stack.push_back(BVHStackEntry(nodes[i], idx)); } - - /* set node */ + /* Set node. */ pack_inner(e, &stack[stack.size()-numnodes], numnodes); } } - - /* root index to start traversal at, to handle case of single leaf node */ + assert(node_size == nextNodeIdx); + /* Root index to start traversal at, to handle case of single leaf node. */ pack.root_index = (root->is_leaf())? -1: 0; } @@ -751,7 +992,7 @@ void QBVH::refit_nodes() void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { if(leaf) { - int4 *data = &pack.leaf_nodes[idx*BVH_QNODE_LEAF_SIZE]; + int4 *data = &pack.leaf_nodes[idx]; int4 c = data[0]; /* Refit leaf node. */ for(int prim = c.x; prim < c.y; prim++) { @@ -770,10 +1011,10 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ int str_offset = (params.top_level)? mesh->curve_offset: 0; - const Mesh::Curve& curve = mesh->curves[pidx - str_offset]; + Mesh::Curve curve = mesh->get_curve(pidx - str_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], bbox); + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; @@ -784,17 +1025,17 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) if(attr) { size_t mesh_size = mesh->curve_keys.size(); size_t steps = mesh->motion_steps - 1; - float4 *key_steps = attr->data_float4(); + float3 *key_steps = attr->data_float3(); for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bbox); + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox); } } } else { /* Triangles. */ int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset]; + Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); @@ -833,13 +1074,18 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) leaf_data[0].y = __int_as_float(c.y); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(c.w); - memcpy(&pack.leaf_nodes[idx * BVH_QNODE_LEAF_SIZE], - leaf_data, - sizeof(float4)*BVH_QNODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); } else { - int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE]; - int4 c = data[6]; + int4 *data = &pack.nodes[idx]; + bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; + int4 c; + if(is_unaligned) { + c = data[13]; + } + else { + c = data[7]; + } /* Refit inner node, set bbox from children. */ BoundBox child_bbox[4] = {BoundBox::empty, BoundBox::empty, @@ -858,21 +1104,62 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) } } - float4 inner_data[BVH_QNODE_SIZE]; - for(int i = 0; i < 4; ++i) { - float3 bb_min = child_bbox[i].min; - float3 bb_max = child_bbox[i].max; - inner_data[0][i] = bb_min.x; - inner_data[1][i] = bb_max.x; - inner_data[2][i] = bb_min.y; - inner_data[3][i] = bb_max.y; - inner_data[4][i] = bb_min.z; - inner_data[5][i] = bb_max.z; - inner_data[6][i] = __int_as_float(c[i]); + /* TODO(sergey): To be de-duplicated with pack_inner(), + * but for that need some sort of pack_node(). which operates with + * direct data, not stack element. + */ + if(is_unaligned) { + Transform aligned_space = transform_identity(); + float4 inner_data[BVH_UNALIGNED_QNODE_SIZE]; + inner_data[0] = make_float4( + __int_as_float(visibility | PATH_RAY_NODE_UNALIGNED), + 0.0f, + 0.0f, + 0.0f); + for(int i = 0; i < 4; ++i) { + Transform space = BVHUnaligned::compute_node_transform( + child_bbox[i], + aligned_space); + inner_data[1][i] = space.x.x; + inner_data[2][i] = space.x.y; + inner_data[3][i] = space.x.z; + + inner_data[4][i] = space.y.x; + inner_data[5][i] = space.y.y; + inner_data[6][i] = space.y.z; + + inner_data[7][i] = space.z.x; + inner_data[8][i] = space.z.y; + inner_data[9][i] = space.z.z; + + inner_data[10][i] = space.x.w; + inner_data[11][i] = space.y.w; + inner_data[12][i] = space.z.w; + + inner_data[13][i] = __int_as_float(c[i]); + } + memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); + } + else { + float4 inner_data[BVH_QNODE_SIZE]; + inner_data[0] = make_float4( + __int_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED), + 0.0f, + 0.0f, + 0.0f); + for(int i = 0; i < 4; ++i) { + float3 bb_min = child_bbox[i].min; + float3 bb_max = child_bbox[i].max; + inner_data[1][i] = bb_min.x; + inner_data[2][i] = bb_max.x; + inner_data[3][i] = bb_min.y; + inner_data[4][i] = bb_max.y; + inner_data[5][i] = bb_min.z; + inner_data[6][i] = bb_max.z; + inner_data[7][i] = __int_as_float(c[i]); + } + memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_QNODE_SIZE); } - memcpy(&pack.nodes[idx * BVH_QNODE_SIZE], - inner_data, - sizeof(float4)*BVH_QNODE_SIZE); } } diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 6076c25ca31..16752076f6a 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -35,11 +35,14 @@ class Progress; #define BVH_NODE_SIZE 4 #define BVH_NODE_LEAF_SIZE 1 -#define BVH_QNODE_SIZE 7 +#define BVH_QNODE_SIZE 8 #define BVH_QNODE_LEAF_SIZE 1 #define BVH_ALIGN 4096 #define TRI_NODE_SIZE 3 +#define BVH_UNALIGNED_NODE_SIZE 7 +#define BVH_UNALIGNED_QNODE_SIZE 14 + /* Packed BVH * * BVH stored as it will be used for traversal on the rendering device. */ @@ -52,8 +55,10 @@ struct PackedBVH { array<int4> leaf_nodes; /* object index to BVH node index mapping for instances */ array<int> object_node; - /* Aligned triangle storage for fatser lookup in the kernel. */ - array<float4> tri_storage; + /* Mapping from primitive index to index in triangle array. */ + array<uint> prim_tri_index; + /* Continuous storage of triangle vertices. */ + array<float4> prim_tri_verts; /* primitive type - triangle or strand */ array<int> prim_type; /* visibility visibilitys for primitives */ @@ -91,7 +96,7 @@ public: protected: BVH(const BVHParams& params, const vector<Object*>& objects); - /* triangles and strands*/ + /* triangles and strands */ void pack_primitives(); void pack_triangle(int idx, float4 storage[3]); @@ -115,9 +120,32 @@ protected: /* pack */ void pack_nodes(const BVHNode *root); - void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); - void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1); - void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1); + + void pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf); + void pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); + + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); /* refit */ void refit_nodes(); @@ -136,9 +164,17 @@ protected: /* pack */ void pack_nodes(const BVHNode *root); + void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num); + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + /* refit */ void refit_nodes(); void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp index b07e870d759..5ddd7349f7b 100644 --- a/intern/cycles/bvh/bvh_binning.cpp +++ b/intern/cycles/bvh/bvh_binning.cpp @@ -52,12 +52,35 @@ __forceinline int get_best_dimension(const float4& bestSAH) /* BVH Object Binning */ -BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) -: BVHRange(job), splitSAH(FLT_MAX), dim(0), pos(0) +BVHObjectBinning::BVHObjectBinning(const BVHRange& job, + BVHReference *prims, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) +: BVHRange(job), + splitSAH(FLT_MAX), + dim(0), + pos(0), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { + if(aligned_space_ == NULL) { + bounds_ = bounds(); + cent_bounds_ = cent_bounds(); + } + else { + /* TODO(sergey): With some additional storage we can avoid + * need in re-calculating this. + */ + bounds_ = unaligned_heuristic->compute_aligned_boundbox( + *this, + prims, + *aligned_space, + ¢_bounds_); + } + /* compute number of bins to use and precompute scaling factor for binning */ num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f*size())); - scale = rcp(cent_bounds().size()) * make_float3((float)num_bins); + scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins); /* initialize binning counter and bounds */ BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */ @@ -79,30 +102,34 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) const BVHReference& prim0 = prims[start() + i + 0]; const BVHReference& prim1 = prims[start() + i + 1]; - int4 bin0 = get_bin(prim0.bounds()); - int4 bin1 = get_bin(prim1.bounds()); + BoundBox bounds0 = get_prim_bounds(prim0); + BoundBox bounds1 = get_prim_bounds(prim1); + + int4 bin0 = get_bin(bounds0); + int4 bin1 = get_bin(bounds1); /* increase bounds for bins for even primitive */ - int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds()); - int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds()); - int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds()); + int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0); + int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0); + int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0); /* increase bounds of bins for odd primitive */ - int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(prim1.bounds()); - int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(prim1.bounds()); - int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(prim1.bounds()); + int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(bounds1); + int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(bounds1); + int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(bounds1); } /* for uneven number of primitives */ if(i < ssize_t(size())) { /* map primitive to bin */ const BVHReference& prim0 = prims[start() + i]; - int4 bin0 = get_bin(prim0.bounds()); + BoundBox bounds0 = get_prim_bounds(prim0); + int4 bin0 = get_bin(bounds0); /* increase bounds of bins */ - int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds()); - int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds()); - int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds()); + int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0); + int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0); + int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0); } } @@ -151,17 +178,19 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) bestSAH = min(sah,bestSAH); } - int4 mask = float3_to_float4(cent_bounds().size()) <= make_float4(0.0f); + int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f); bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX); /* find best dimension */ dim = get_best_dimension(bestSAH); splitSAH = bestSAH[dim]; pos = bestSplit[dim]; - leafSAH = bounds().half_area() * blocks(size()); + leafSAH = bounds_.half_area() * blocks(size()); } -void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const +void BVHObjectBinning::split(BVHReference* prims, + BVHObjectBinning& left_o, + BVHObjectBinning& right_o) const { size_t N = size(); @@ -176,10 +205,12 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO prefetch_L2(&prims[start() + l + 8]); prefetch_L2(&prims[start() + r - 8]); - const BVHReference& prim = prims[start() + l]; + BVHReference prim = prims[start() + l]; + BoundBox unaligned_bounds = get_prim_bounds(prim); + float3 unaligned_center = unaligned_bounds.center2(); float3 center = prim.bounds().center2(); - if(get_bin(center)[dim] < pos) { + if(get_bin(unaligned_center)[dim] < pos) { lgeom_bounds.grow(prim.bounds()); lcent_bounds.grow(center); l++; @@ -191,7 +222,6 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO r--; } } - /* finish */ if(l != 0 && N-1-r != 0) { right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N-1-r), prims); diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h index 60742157055..52955f70151 100644 --- a/intern/cycles/bvh/bvh_binning.h +++ b/intern/cycles/bvh/bvh_binning.h @@ -19,11 +19,14 @@ #define __BVH_BINNING_H__ #include "bvh_params.h" +#include "bvh_unaligned.h" #include "util_types.h" CCL_NAMESPACE_BEGIN +class BVHBuild; + /* Single threaded object binner. Finds the split with the best SAH heuristic * by testing for each dimension multiple partitionings for regular spaced * partition locations. A partitioning for a partition location is computed, @@ -34,10 +37,18 @@ CCL_NAMESPACE_BEGIN class BVHObjectBinning : public BVHRange { public: - __forceinline BVHObjectBinning() {} - BVHObjectBinning(const BVHRange& job, BVHReference *prims); + __forceinline BVHObjectBinning() : leafSAH(FLT_MAX) {} + + BVHObjectBinning(const BVHRange& job, + BVHReference *prims, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); - void split(BVHReference *prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const; + void split(BVHReference *prims, + BVHObjectBinning& left_o, + BVHObjectBinning& right_o) const; + + __forceinline const BoundBox& unaligned_bounds() { return bounds_; } float splitSAH; /* SAH cost of the best split */ float leafSAH; /* SAH cost of creating a leaf */ @@ -48,13 +59,20 @@ protected: size_t num_bins; /* actual number of bins to use */ float3 scale; /* scaling factor to compute bin */ + /* Effective bounds and centroid bounds. */ + BoundBox bounds_; + BoundBox cent_bounds_; + + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; + enum { MAX_BINS = 32 }; enum { LOG_BLOCK_SIZE = 2 }; /* computes the bin numbers for each dimension for a box. */ __forceinline int4 get_bin(const BoundBox& box) const { - int4 a = make_int4((box.center2() - cent_bounds().min)*scale - make_float3(0.5f)); + int4 a = make_int4((box.center2() - cent_bounds_.min)*scale - make_float3(0.5f)); int4 mn = make_int4(0); int4 mx = make_int4((int)num_bins-1); @@ -64,7 +82,7 @@ protected: /* computes the bin numbers for each dimension for a point. */ __forceinline int4 get_bin(const float3& c) const { - return make_int4((c - cent_bounds().min)*scale - make_float3(0.5f)); + return make_int4((c - cent_bounds_.min)*scale - make_float3(0.5f)); } /* compute the number of blocks occupied for each dimension. */ @@ -78,6 +96,17 @@ protected: { return (int)((a+((1LL << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE); } + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } }; CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 76a1bfa2bfe..67ffb6853d6 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -33,6 +33,7 @@ #include "util_stack_allocator.h" #include "util_simd.h" #include "util_time.h" +#include "util_queue.h" CCL_NAMESPACE_BEGIN @@ -99,7 +100,8 @@ BVHBuild::BVHBuild(const vector<Object*>& objects_, prim_object(prim_object_), params(params_), progress(progress_), - progress_start_time(0.0) + progress_start_time(0.0), + unaligned_heuristic(objects_) { spatial_min_overlap = 0.0f; } @@ -112,68 +114,74 @@ BVHBuild::~BVHBuild() void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { - Attribute *attr_mP = NULL; - - if(mesh->has_motion_blur()) - attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + Attribute *attr_mP = NULL; - for(uint j = 0; j < mesh->triangles.size(); j++) { - Mesh::Triangle t = mesh->triangles[j]; - BoundBox bounds = BoundBox::empty; - PrimitiveType type = PRIMITIVE_TRIANGLE; + if(mesh->has_motion_blur()) + attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + size_t num_triangles = mesh->num_triangles(); + for(uint j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); + BoundBox bounds = BoundBox::empty; + PrimitiveType type = PRIMITIVE_TRIANGLE; - t.bounds_grow(&mesh->verts[0], bounds); + t.bounds_grow(&mesh->verts[0], bounds); - /* motion triangles */ - if(attr_mP) { - size_t mesh_size = mesh->verts.size(); - size_t steps = mesh->motion_steps - 1; - float3 *vert_steps = attr_mP->data_float3(); + /* motion triangles */ + if(attr_mP) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - t.bounds_grow(vert_steps + i*mesh_size, bounds); + for(size_t i = 0; i < steps; i++) + t.bounds_grow(vert_steps + i*mesh_size, bounds); - type = PRIMITIVE_MOTION_TRIANGLE; - } + type = PRIMITIVE_MOTION_TRIANGLE; + } - if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i, type)); - root.grow(bounds); - center.grow(bounds.center2()); + if(bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, type)); + root.grow(bounds); + center.grow(bounds.center2()); + } } } - Attribute *curve_attr_mP = NULL; + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + Attribute *curve_attr_mP = NULL; - if(mesh->has_motion_blur()) - curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if(mesh->has_motion_blur()) + curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(uint j = 0; j < mesh->curves.size(); j++) { - Mesh::Curve curve = mesh->curves[j]; - PrimitiveType type = PRIMITIVE_CURVE; + size_t num_curves = mesh->num_curves(); + for(uint j = 0; j < num_curves; j++) { + Mesh::Curve curve = mesh->get_curve(j); + PrimitiveType type = PRIMITIVE_CURVE; - for(int k = 0; k < curve.num_keys - 1; k++) { - BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], bounds); + for(int k = 0; k < curve.num_keys - 1; k++) { + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds); - /* motion curve */ - if(curve_attr_mP) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; - float4 *key_steps = curve_attr_mP->data_float4(); + /* motion curve */ + if(curve_attr_mP) { + size_t mesh_size = mesh->curve_keys.size(); + size_t steps = mesh->motion_steps - 1; + float3 *key_steps = curve_attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, bounds); + for(size_t i = 0; i < steps; i++) + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds); - type = PRIMITIVE_MOTION_CURVE; - } + type = PRIMITIVE_MOTION_CURVE; + } - if(bounds.valid()) { - int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); - - references.push_back(BVHReference(bounds, j, i, packed_type)); - root.grow(bounds); - center.grow(bounds.center2()); + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); + + references.push_back(BVHReference(bounds, j, i, packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); + } } } } @@ -188,10 +196,10 @@ void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob static size_t count_curve_segments(Mesh *mesh) { - size_t num = 0, num_curves = mesh->curves.size(); + size_t num = 0, num_curves = mesh->num_curves(); for(size_t i = 0; i < num_curves; i++) - num += mesh->curves[i].num_keys - 1; + num += mesh->get_curve(i).num_keys - 1; return num; } @@ -203,16 +211,27 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { + if(!ob->is_traceable()) { + continue; + } if(!ob->mesh->is_instanced()) { - num_alloc_references += ob->mesh->triangles.size(); - num_alloc_references += count_curve_segments(ob->mesh); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + num_alloc_references += ob->mesh->num_triangles(); + } + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + num_alloc_references += count_curve_segments(ob->mesh); + } } else num_alloc_references++; } else { - num_alloc_references += ob->mesh->triangles.size(); - num_alloc_references += count_curve_segments(ob->mesh); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + num_alloc_references += ob->mesh->num_triangles(); + } + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + num_alloc_references += count_curve_segments(ob->mesh); + } } } @@ -224,6 +243,10 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { + if(!ob->is_traceable()) { + ++i; + continue; + } if(!ob->mesh->is_instanced()) add_reference_mesh(bounds, center, ob->mesh, i); else @@ -326,11 +349,13 @@ BVHNode* BVHBuild::run() VLOG(1) << "BVH build statistics:\n" << " Build time: " << time_dt() - build_start_time << "\n" << " Total number of nodes: " - << rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT)) << "\n" << " Number of inner nodes: " - << rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n" << " Number of leaf nodes: " - << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n" + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n" + << " Number of unaligned nodes: " + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT)) << "\n" << " Allocation slop factor: " << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() @@ -436,10 +461,11 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) float leafSAH = params.sah_primitive_cost * range.leafSAH; float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH; - /* have at least one inner node on top level, for performance and correct - * visibility tests, since object instances do not check visibility flag */ + /* Have at least one inner node on top level, for performance and correct + * visibility tests, since object instances do not check visibility flag. + */ if(!(range.size() > 0 && params.top_level && level == 0)) { - /* make leaf node when threshold reached or SAH tells us */ + /* Make leaf node when threshold reached or SAH tells us. */ if((params.small_enough_for_leaf(size, level)) || (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) { @@ -447,28 +473,70 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) } } - /* perform split */ + BVHObjectBinning unaligned_range; + float unalignedSplitSAH = FLT_MAX; + float unalignedLeafSAH = FLT_MAX; + Transform aligned_space; + if(params.use_unaligned_nodes && + splitSAH > params.unaligned_split_threshold*leafSAH) + { + aligned_space = unaligned_heuristic.compute_aligned_space( + range, &references[0]); + unaligned_range = BVHObjectBinning(range, + &references[0], + &unaligned_heuristic, + &aligned_space); + unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() + + params.sah_primitive_cost * unaligned_range.splitSAH; + unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH; + if(!(range.size() > 0 && params.top_level && level == 0)) { + if(unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH && + range_within_max_leaf_size(range, references)) + { + return create_leaf_node(range, references); + } + } + } + + /* Perform split. */ BVHObjectBinning left, right; - range.split(&references[0], left, right); + if(unalignedSplitSAH < splitSAH) { + unaligned_range.split(&references[0], left, right); + } + else { + range.split(&references[0], left, right); + } - /* create inner node. */ - InnerNode *inner; + BoundBox bounds; + if(unalignedSplitSAH < splitSAH) { + bounds = unaligned_heuristic.compute_aligned_boundbox( + range, &references[0], aligned_space); + } + else { + bounds = range.bounds(); + } + /* Create inner node. */ + InnerNode *inner; if(range.size() < THREAD_TASK_SIZE) { /* local build */ BVHNode *leftnode = build_node(left, level + 1); BVHNode *rightnode = build_node(right, level + 1); - inner = new InnerNode(range.bounds(), leftnode, rightnode); + inner = new InnerNode(bounds, leftnode, rightnode); } else { - /* threaded build */ - inner = new InnerNode(range.bounds()); + /* Threaded build */ + inner = new InnerNode(bounds); task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true); task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true); } + if(unalignedSplitSAH < splitSAH) { + inner->set_aligned_space(aligned_space); + } + return inner; } @@ -507,16 +575,54 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, return create_leaf_node(range, *references); } } + float leafSAH = params.sah_primitive_cost * split.leafSAH; + float splitSAH = params.sah_node_cost * range.bounds().half_area() + + params.sah_primitive_cost * split.nodeSAH; + + BVHMixedSplit unaligned_split; + float unalignedSplitSAH = FLT_MAX; + /* float unalignedLeafSAH = FLT_MAX; */ + Transform aligned_space; + if(params.use_unaligned_nodes && + splitSAH > params.unaligned_split_threshold*leafSAH) + { + aligned_space = + unaligned_heuristic.compute_aligned_space(range, &references->at(0)); + unaligned_split = BVHMixedSplit(this, + storage, + range, + references, + level, + &unaligned_heuristic, + &aligned_space); + /* 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. */ + } /* Do split. */ BVHRange left, right; - split.split(this, left, right, range); + if(unalignedSplitSAH < splitSAH) { + unaligned_split.split(this, left, right, range); + } + else { + split.split(this, left, right, range); + } progress_total += left.size() + right.size() - range.size(); + BoundBox bounds; + if(unalignedSplitSAH < splitSAH) { + bounds = unaligned_heuristic.compute_aligned_boundbox( + range, &references->at(0), aligned_space); + } + else { + bounds = range.bounds(); + } + /* Create inner node. */ InnerNode *inner; - if(range.size() < THREAD_TASK_SIZE) { /* Local build. */ @@ -530,11 +636,11 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, /* Build right node. */ BVHNode *rightnode = build_node(right, ©, level + 1, thread_id); - inner = new InnerNode(range.bounds(), leftnode, rightnode); + inner = new InnerNode(bounds, leftnode, rightnode); } else { /* Threaded build. */ - inner = new InnerNode(range.bounds()); + inner = new InnerNode(bounds); task_pool.push(new BVHSpatialSplitBuildTask(this, inner, 0, @@ -551,6 +657,10 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, true); } + if(unalignedSplitSAH < splitSAH) { + inner->set_aligned_space(aligned_space); + } + return inner; } @@ -607,6 +717,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL]; + vector<BVHReference, LeafStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL]; /* TODO(sergey): In theory we should be able to store references. */ typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator; @@ -625,6 +736,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, const BVHReference& ref = references[range.start() + i]; if(ref.prim_index() != -1) { int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL); + p_ref[type_index].push_back(ref); p_type[type_index].push_back(ref.prim_type()); p_index[type_index].push_back(ref.prim_index()); p_object[type_index].push_back(ref.prim_object()); @@ -665,16 +777,38 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, if(num != 0) { assert(p_type[i].size() == p_index[i].size()); assert(p_type[i].size() == p_object[i].size()); + Transform aligned_space; + bool alignment_found = false; for(int j = 0; j < num; ++j) { const int index = start_index + j; local_prim_type[index] = p_type[i][j]; local_prim_index[index] = p_index[i][j]; local_prim_object[index] = p_object[i][j]; + if(params.use_unaligned_nodes && !alignment_found) { + alignment_found = + unaligned_heuristic.compute_aligned_space(p_ref[i][j], + &aligned_space); + } + } + LeafNode *leaf_node = new LeafNode(bounds[i], + visibility[i], + start_index, + start_index + num); + if(alignment_found) { + /* Need to recalculate leaf bounds with new alignment. */ + leaf_node->m_bounds = BoundBox::empty; + for(int j = 0; j < num; ++j) { + const BVHReference &ref = p_ref[i][j]; + BoundBox ref_bounds = + unaligned_heuristic.compute_aligned_prim_boundbox( + ref, + aligned_space); + leaf_node->m_bounds.grow(ref_bounds); + } + /* Set alignment space. */ + leaf_node->set_aligned_space(aligned_space); } - leaves[num_leaves++] = new LeafNode(bounds[i], - visibility[i], - start_index, - start_index + num); + leaves[num_leaves++] = leaf_node; start_index += num; } } @@ -756,6 +890,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, ++num_leaves; } + /* TODO(sergey): Need to take care of alignment when number of leaves + * is more than 1. + */ if(num_leaves == 1) { /* Simplest case: single leaf, just return it. * In all the rest cases we'll be creating intermediate inner node with diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index a015b89d72f..64180349935 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -22,6 +22,7 @@ #include "bvh.h" #include "bvh_binning.h" +#include "bvh_unaligned.h" #include "util_boundbox.h" #include "util_task.h" @@ -59,13 +60,14 @@ protected: friend class BVHSpatialSplit; friend class BVHBuildTask; friend class BVHSpatialSplitBuildTask; + friend class BVHObjectBinning; - /* adding references */ + /* Adding references. */ void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i); void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i); void add_references(BVHRange& root); - /* building */ + /* Building. */ BVHNode *build_node(const BVHRange& range, vector<BVHReference> *references, int level, @@ -78,7 +80,7 @@ protected: bool range_within_max_leaf_size(const BVHRange& range, const vector<BVHReference>& references) const; - /* threads */ + /* Threads. */ enum { THREAD_TASK_SIZE = 4096 }; void thread_build_node(InnerNode *node, int child, @@ -92,41 +94,44 @@ protected: int thread_id); thread_mutex build_mutex; - /* progress */ + /* Progress. */ void progress_update(); - /* tree rotations */ + /* Tree rotations. */ void rotate(BVHNode *node, int max_depth); void rotate(BVHNode *node, int max_depth, int iterations); - /* objects and primitive references */ + /* Objects and primitive references. */ vector<Object*> objects; vector<BVHReference> references; int num_original_references; - /* output primitive indexes and objects */ + /* Output primitive indexes and objects. */ array<int>& prim_type; array<int>& prim_index; array<int>& prim_object; - /* build parameters */ + /* Build parameters. */ BVHParams params; - /* progress reporting */ + /* Progress reporting. */ Progress& progress; double progress_start_time; size_t progress_count; size_t progress_total; size_t progress_original_total; - /* spatial splitting */ + /* Spatial splitting. */ float spatial_min_overlap; vector<BVHSpatialStorage> spatial_storage; size_t spatial_free_index; thread_spin_lock spatial_spin_lock; - /* threads */ + /* Threads. */ TaskPool task_pool; + + /* Unaligned building. */ + BVHUnaligned unaligned_heuristic; }; CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp index 8294690da7d..f5cd699bdf4 100644 --- a/intern/cycles/bvh/bvh_node.cpp +++ b/intern/cycles/bvh/bvh_node.cpp @@ -61,6 +61,76 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const } } return cnt; + case BVH_STAT_ALIGNED_COUNT: + if(!is_unaligned()) { + cnt = 1; + } + break; + case BVH_STAT_UNALIGNED_COUNT: + if(is_unaligned()) { + cnt = 1; + } + break; + case BVH_STAT_ALIGNED_INNER_COUNT: + if(!is_leaf()) { + bool has_unaligned = false; + for(int j = 0; j < num_children(); j++) { + has_unaligned |= get_child(j)->is_unaligned(); + } + cnt += has_unaligned? 0: 1; + } + break; + case BVH_STAT_UNALIGNED_INNER_COUNT: + if(!is_leaf()) { + bool has_unaligned = false; + for(int j = 0; j < num_children(); j++) { + has_unaligned |= get_child(j)->is_unaligned(); + } + cnt += has_unaligned? 1: 0; + } + break; + case BVH_STAT_ALIGNED_INNER_QNODE_COUNT: + { + bool has_unaligned = false; + for(int i = 0; i < num_children(); i++) { + BVHNode *node = get_child(i); + if(node->is_leaf()) { + has_unaligned |= node->is_unaligned(); + } + else { + for(int j = 0; j < node->num_children(); j++) { + cnt += node->get_child(j)->getSubtreeSize(stat); + has_unaligned |= node->get_child(j)->is_unaligned(); + } + } + } + cnt += has_unaligned? 0: 1; + } + return cnt; + case BVH_STAT_UNALIGNED_INNER_QNODE_COUNT: + { + bool has_unaligned = false; + for(int i = 0; i < num_children(); i++) { + BVHNode *node = get_child(i); + if(node->is_leaf()) { + has_unaligned |= node->is_unaligned(); + } + else { + for(int j = 0; j < node->num_children(); j++) { + cnt += node->get_child(j)->getSubtreeSize(stat); + has_unaligned |= node->get_child(j)->is_unaligned(); + } + } + } + cnt += has_unaligned? 1: 0; + } + return cnt; + case BVH_STAT_ALIGNED_LEAF_COUNT: + cnt = (is_leaf() && !is_unaligned()) ? 1 : 0; + break; + case BVH_STAT_UNALIGNED_LEAF_COUNT: + cnt = (is_leaf() && is_unaligned()) ? 1 : 0; + break; default: assert(0); /* unknown mode */ } diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index d476fb917ed..f2965a785e6 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -31,6 +31,14 @@ enum BVH_STAT { BVH_STAT_TRIANGLE_COUNT, BVH_STAT_CHILDNODE_COUNT, BVH_STAT_QNODE_COUNT, + BVH_STAT_ALIGNED_COUNT, + BVH_STAT_UNALIGNED_COUNT, + BVH_STAT_ALIGNED_INNER_COUNT, + BVH_STAT_UNALIGNED_INNER_COUNT, + BVH_STAT_ALIGNED_INNER_QNODE_COUNT, + BVH_STAT_UNALIGNED_INNER_QNODE_COUNT, + BVH_STAT_ALIGNED_LEAF_COUNT, + BVH_STAT_UNALIGNED_LEAF_COUNT, }; class BVHParams; @@ -38,16 +46,41 @@ class BVHParams; class BVHNode { public: - BVHNode() + BVHNode() : m_is_unaligned(false), + m_aligned_space(NULL) { } - virtual ~BVHNode() {} + virtual ~BVHNode() + { + delete m_aligned_space; + } + virtual bool is_leaf() const = 0; virtual int num_children() const = 0; virtual BVHNode *get_child(int i) const = 0; virtual int num_triangles() const { return 0; } virtual void print(int depth = 0) const = 0; + bool is_unaligned() const { return m_is_unaligned; } + + inline void set_aligned_space(const Transform& aligned_space) + { + m_is_unaligned = true; + if (m_aligned_space == NULL) { + m_aligned_space = new Transform(aligned_space); + } + else { + *m_aligned_space = aligned_space; + } + } + + inline Transform get_aligned_space() const + { + if(m_aligned_space == NULL) { + return transform_identity(); + } + return *m_aligned_space; + } BoundBox m_bounds; uint m_visibility; @@ -58,12 +91,20 @@ public: void deleteSubtree(); uint update_visibility(); + + bool m_is_unaligned; + + // TODO(sergey): Can be stored as 3x3 matrix, but better to have some + // utilities and type defines in util_transform first. + Transform *m_aligned_space; }; class InnerNode : public BVHNode { public: - InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1) + InnerNode(const BoundBox& bounds, + BVHNode* child0, + BVHNode* child1) { m_bounds = bounds; children[0] = child0; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index cf683df1b31..2e698a80742 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -20,6 +20,8 @@ #include "util_boundbox.h" +#include "kernel_types.h" + CCL_NAMESPACE_BEGIN /* BVH Parameters */ @@ -31,6 +33,9 @@ public: bool use_spatial_split; float spatial_split_alpha; + /* Unaligned nodes creation threshold */ + float unaligned_split_threshold; + /* SAH costs */ float sah_node_cost; float sah_primitive_cost; @@ -46,6 +51,14 @@ public: /* QBVH */ bool use_qbvh; + /* Mask of primitives to be included into the BVH. */ + int primitive_mask; + + /* Use unaligned bounding boxes. + * Only used for curves BVH. + */ + bool use_unaligned_nodes; + /* fixed parameters */ enum { MAX_DEPTH = 64, @@ -58,6 +71,8 @@ public: use_spatial_split = true; spatial_split_alpha = 1e-5f; + unaligned_split_threshold = 0.7f; + /* todo: see if splitting up primitive cost to be separate for triangles * and curves can help. so far in tests it doesn't help, but why? */ sah_node_cost = 1.0f; @@ -69,6 +84,9 @@ public: top_level = false; use_qbvh = false; + use_unaligned_nodes = false; + + primitive_mask = PRIMITIVE_ALL; } /* SAH costs */ diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index e9032c61c3b..e5bcf9995bf 100644 --- a/intern/cycles/bvh/bvh_sort.cpp +++ b/intern/cycles/bvh/bvh_sort.cpp @@ -26,23 +26,27 @@ CCL_NAMESPACE_BEGIN static const int BVH_SORT_THRESHOLD = 4096; -/* Silly workaround for float extended precision that happens when compiling - * on x86, due to one float staying in 80 bit precision register and the other - * not, which causes the strictly weak ordering to break. - */ -#if !defined(__i386__) -# define NO_EXTENDED_PRECISION -#else -# define NO_EXTENDED_PRECISION volatile -#endif - struct BVHReferenceCompare { public: int dim; + const BVHUnaligned *unaligned_heuristic; + const Transform *aligned_space; + + BVHReferenceCompare(int dim, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) + : dim(dim), + unaligned_heuristic(unaligned_heuristic), + aligned_space(aligned_space) + { + } - explicit BVHReferenceCompare(int dim_) + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const { - dim = dim_; + return (aligned_space != NULL) + ? unaligned_heuristic->compute_aligned_prim_boundbox( + prim, *aligned_space) + : prim.bounds(); } /* Compare two references. @@ -52,8 +56,10 @@ public: __forceinline int compare(const BVHReference& ra, const BVHReference& rb) const { - NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim]; - NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim]; + BoundBox ra_bounds = get_prim_bounds(ra), + rb_bounds = get_prim_bounds(rb); + float ca = ra_bounds.min[dim] + ra_bounds.max[dim]; + float cb = rb_bounds.min[dim] + rb_bounds.max[dim]; if(ca < cb) return -1; else if(ca > cb) return 1; @@ -171,10 +177,15 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool, } } -void bvh_reference_sort(int start, int end, BVHReference *data, int dim) +void bvh_reference_sort(int start, + int end, + BVHReference *data, + int dim, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) { const int count = end - start; - BVHReferenceCompare compare(dim); + BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space); if(count < BVH_SORT_THRESHOLD) { /* It is important to not use any mutex if array is small enough, * otherwise we end up in situation when we're going to sleep far diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h index 18aafb5f1ff..b49ca02eb60 100644 --- a/intern/cycles/bvh/bvh_sort.h +++ b/intern/cycles/bvh/bvh_sort.h @@ -20,7 +20,15 @@ CCL_NAMESPACE_BEGIN -void bvh_reference_sort(int start, int end, BVHReference *data, int dim); +class BVHUnaligned; +struct Transform; + +void bvh_reference_sort(int start, + int end, + BVHReference *data, + int dim, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 8084975565e..d0d5fbe5a7a 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -32,14 +32,18 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH) + float nodeSAH, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) : sah(FLT_MAX), dim(0), num_left(0), left_bounds(BoundBox::empty), right_bounds(BoundBox::empty), storage_(storage), - references_(references) + references_(references), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { const BVHReference *ref_ptr = &references_->at(range.start()); float min_sah = FLT_MAX; @@ -51,12 +55,15 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, bvh_reference_sort(range.start(), range.end(), &references_->at(0), - dim); + dim, + unaligned_heuristic_, + aligned_space_); /* sweep right to left and determine bounds. */ BoundBox right_bounds = BoundBox::empty; for(int i = range.size() - 1; i > 0; i--) { - right_bounds.grow(ref_ptr[i].bounds()); + BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]); + right_bounds.grow(prim_bounds); storage_->right_bounds[i - 1] = right_bounds; } @@ -64,7 +71,8 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, BoundBox left_bounds = BoundBox::empty; for(int i = 1; i < range.size(); i++) { - left_bounds.grow(ref_ptr[i - 1].bounds()); + BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]); + left_bounds.grow(prim_bounds); right_bounds = storage_->right_bounds[i - 1]; float sah = nodeSAH + @@ -88,16 +96,37 @@ void BVHObjectSplit::split(BVHRange& left, BVHRange& right, const BVHRange& range) { + assert(references_->size() > 0); /* sort references according to split */ bvh_reference_sort(range.start(), range.end(), &references_->at(0), - this->dim); + this->dim, + unaligned_heuristic_, + aligned_space_); + + BoundBox effective_left_bounds, effective_right_bounds; + const int num_right = range.size() - this->num_left; + if(aligned_space_ == NULL) { + effective_left_bounds = left_bounds; + effective_right_bounds = right_bounds; + } + else { + effective_left_bounds = BoundBox::empty; + effective_right_bounds = BoundBox::empty; + for(int i = 0; i < this->num_left; ++i) { + BoundBox prim_boundbox = references_->at(range.start() + i).bounds(); + effective_left_bounds.grow(prim_boundbox); + } + for(int i = 0; i < num_right; ++i) { + BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds(); + effective_right_bounds.grow(prim_boundbox); + } + } /* split node ranges */ - left = BVHRange(this->left_bounds, range.start(), this->num_left); - right = BVHRange(this->right_bounds, left.end(), range.size() - this->num_left); - + left = BVHRange(effective_left_bounds, range.start(), this->num_left); + right = BVHRange(effective_right_bounds, left.end(), num_right); } /* Spatial Split */ @@ -106,16 +135,31 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH) + float nodeSAH, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) : sah(FLT_MAX), dim(0), pos(0.0f), storage_(storage), - references_(references) + references_(references), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { /* initialize bins. */ - float3 origin = range.bounds().min; - float3 binSize = (range.bounds().max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS); + BoundBox range_bounds; + if(aligned_space == NULL) { + range_bounds = range.bounds(); + } + else { + range_bounds = unaligned_heuristic->compute_aligned_boundbox( + range, + &references->at(0), + *aligned_space); + } + + float3 origin = range_bounds.min; + float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS); float3 invBinSize = 1.0f / binSize; for(int dim = 0; dim < 3; dim++) { @@ -131,8 +175,9 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, /* chop references into bins. */ for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) { const BVHReference& ref = references_->at(refIdx); - float3 firstBinf = (ref.bounds().min - origin) * invBinSize; - float3 lastBinf = (ref.bounds().max - origin) * invBinSize; + BoundBox prim_bounds = get_prim_bounds(ref); + float3 firstBinf = (prim_bounds.min - origin) * invBinSize; + float3 lastBinf = (prim_bounds.max - origin) * invBinSize; int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z); int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z); @@ -140,7 +185,10 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1); for(int dim = 0; dim < 3; dim++) { - BVHReference currRef = ref; + BVHReference currRef(get_prim_bounds(ref), + ref.prim_index(), + ref.prim_object(), + ref.prim_type()); for(int i = firstBin[dim]; i < lastBin[dim]; i++) { BVHReference leftRef, rightRef; @@ -209,14 +257,15 @@ void BVHSpatialSplit::split(BVHBuild *builder, BoundBox right_bounds = BoundBox::empty; for(int i = left_end; i < right_start; i++) { - if(refs[i].bounds().max[this->dim] <= this->pos) { + BoundBox prim_bounds = get_prim_bounds(refs[i]); + if(prim_bounds.max[this->dim] <= this->pos) { /* entirely on the left-hand side */ - left_bounds.grow(refs[i].bounds()); + left_bounds.grow(prim_bounds); swap(refs[i], refs[left_end++]); } - else if(refs[i].bounds().min[this->dim] >= this->pos) { + else if(prim_bounds.min[this->dim] >= this->pos) { /* entirely on the right-hand side */ - right_bounds.grow(refs[i].bounds()); + right_bounds.grow(prim_bounds); swap(refs[i--], refs[--right_start]); } } @@ -231,8 +280,12 @@ void BVHSpatialSplit::split(BVHBuild *builder, new_refs.reserve(right_start - left_end); while(left_end < right_start) { /* split reference. */ + BVHReference curr_ref(get_prim_bounds(refs[left_end]), + refs[left_end].prim_index(), + refs[left_end].prim_object(), + refs[left_end].prim_type()); BVHReference lref, rref; - split_reference(*builder, lref, rref, refs[left_end], this->dim, this->pos); + split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos); /* compute SAH for duplicate/unsplit candidates. */ BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds. @@ -240,8 +293,8 @@ void BVHSpatialSplit::split(BVHBuild *builder, BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds. BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds. - lub.grow(refs[left_end].bounds()); - rub.grow(refs[left_end].bounds()); + lub.grow(curr_ref.bounds()); + rub.grow(curr_ref.bounds()); ldb.grow(lref.bounds()); rdb.grow(rref.bounds()); @@ -280,6 +333,17 @@ void BVHSpatialSplit::split(BVHBuild *builder, new_refs.begin(), new_refs.end()); } + if(aligned_space_ != NULL) { + left_bounds = right_bounds = BoundBox::empty; + for(int i = left_start; i < left_end - left_start; ++i) { + BoundBox prim_boundbox = references_->at(i).bounds(); + left_bounds.grow(prim_boundbox); + } + for(int i = right_start; i < right_end - right_start; ++i) { + BoundBox prim_boundbox = references_->at(i).bounds(); + right_bounds.grow(prim_boundbox); + } + } left = BVHRange(left_bounds, left_start, left_end - left_start); right = BVHRange(right_bounds, right_start, right_end - right_start); } @@ -292,14 +356,16 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh, BoundBox& left_bounds, BoundBox& right_bounds) { - const int *inds = mesh->triangles[prim_index].v; + Mesh::Triangle t = mesh->get_triangle(prim_index); const float3 *verts = &mesh->verts[0]; - float3 v1 = tfm ? transform_point(tfm, verts[inds[2]]) : verts[inds[2]]; + float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]]; + v1 = get_unaligned_point(v1); for(int i = 0; i < 3; i++) { float3 v0 = v1; - int vindex = inds[i]; + int vindex = t.v[i]; v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex]; + v1 = get_unaligned_point(v1); float v0p = v0[dim]; float v1p = v1[dim]; @@ -329,17 +395,18 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh, BoundBox& right_bounds) { /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ - const int k0 = mesh->curves[prim_index].first_key + segment_index; + Mesh::Curve curve = mesh->get_curve(prim_index); + const int k0 = curve.first_key + segment_index; const int k1 = k0 + 1; - const float4& key0 = mesh->curve_keys[k0]; - const float4& key1 = mesh->curve_keys[k1]; - float3 v0 = float4_to_float3(key0); - float3 v1 = float4_to_float3(key1); + float3 v0 = mesh->curve_keys[k0]; + float3 v1 = mesh->curve_keys[k1]; if(tfm != NULL) { v0 = transform_point(tfm, v0); v1 = transform_point(tfm, v1); } + v0 = get_unaligned_point(v0); + v1 = get_unaligned_point(v1); float v0p = v0[dim]; float v1p = v1[dim]; @@ -405,7 +472,7 @@ void BVHSpatialSplit::split_object_reference(const Object *object, BoundBox& right_bounds) { Mesh *mesh = object->mesh; - for(int tri_idx = 0; tri_idx < mesh->triangles.size(); ++tri_idx) { + for(int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) { split_triangle_primitive(mesh, &object->tfm, tri_idx, @@ -414,8 +481,8 @@ void BVHSpatialSplit::split_object_reference(const Object *object, left_bounds, right_bounds); } - for(int curve_idx = 0; curve_idx < mesh->curves.size(); ++curve_idx) { - Mesh::Curve &curve = mesh->curves[curve_idx]; + for(int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) { + Mesh::Curve curve = mesh->get_curve(curve_idx); for(int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) @@ -474,6 +541,7 @@ void BVHSpatialSplit::split_reference(const BVHBuild& builder, /* intersect with original bounds. */ left_bounds.max[dim] = pos; right_bounds.min[dim] = pos; + left_bounds.intersect(ref.bounds()); right_bounds.intersect(ref.bounds()); diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h index aea8b2565e0..dbdb51f1a5b 100644 --- a/intern/cycles/bvh/bvh_split.h +++ b/intern/cycles/bvh/bvh_split.h @@ -24,6 +24,7 @@ CCL_NAMESPACE_BEGIN class BVHBuild; +struct Transform; /* Object Split */ @@ -41,7 +42,9 @@ public: BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH); + float nodeSAH, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); void split(BVHRange& left, BVHRange& right, @@ -50,6 +53,19 @@ public: protected: BVHSpatialStorage *storage_; vector<BVHReference> *references_; + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } }; /* Spatial Split */ @@ -70,7 +86,9 @@ public: BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH); + float nodeSAH, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); void split(BVHBuild *builder, BVHRange& left, @@ -87,6 +105,8 @@ public: protected: BVHSpatialStorage *storage_; vector<BVHReference> *references_; + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; /* Lower-level functions which calculates boundaries of left and right nodes * needed for spatial split. @@ -132,6 +152,27 @@ protected: float pos, BoundBox& left_bounds, BoundBox& right_bounds); + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } + + __forceinline float3 get_unaligned_point(const float3& point) const + { + if(aligned_space_ == NULL) { + return point; + } + else { + return transform_point(aligned_space_, point); + } + } }; /* Mixed Object-Spatial Split */ @@ -148,19 +189,40 @@ public: bool no_split; + BoundBox bounds; + + BVHMixedSplit() {} + __forceinline BVHMixedSplit(BVHBuild *builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - int level) + int level, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL) { + if(aligned_space == NULL) { + bounds = range.bounds(); + } + else { + bounds = unaligned_heuristic->compute_aligned_boundbox( + range, + &references->at(0), + *aligned_space); + } /* find split candidates. */ - float area = range.bounds().safe_area(); + float area = bounds.safe_area(); leafSAH = area * builder->params.primitive_cost(range.size()); nodeSAH = area * builder->params.node_cost(2); - object = BVHObjectSplit(builder, storage, range, references, nodeSAH); + object = BVHObjectSplit(builder, + storage, + range, + references, + nodeSAH, + unaligned_heuristic, + aligned_space); if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) { BoundBox overlap = object.left_bounds; @@ -171,7 +233,9 @@ public: storage, range, references, - nodeSAH); + nodeSAH, + unaligned_heuristic, + aligned_space); } } @@ -181,7 +245,10 @@ public: builder->range_within_max_leaf_size(range, *references)); } - __forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range) + __forceinline void split(BVHBuild *builder, + BVHRange& left, + BVHRange& right, + const BVHRange& range) { if(builder->params.use_spatial_split && minSAH == spatial.sah) spatial.split(builder, left, right, range); @@ -193,4 +260,3 @@ public: CCL_NAMESPACE_END #endif /* __BVH_SPLIT_H__ */ - diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp new file mode 100644 index 00000000000..a876c670914 --- /dev/null +++ b/intern/cycles/bvh/bvh_unaligned.cpp @@ -0,0 +1,178 @@ +/* + * 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. + */ + + +#include "bvh_unaligned.h" + +#include "mesh.h" +#include "object.h" + +#include "bvh_binning.h" +#include "bvh_params.h" + +#include "util_boundbox.h" +#include "util_debug.h" +#include "util_transform.h" + +CCL_NAMESPACE_BEGIN + + +BVHUnaligned::BVHUnaligned(const vector<Object*>& objects) + : objects_(objects) +{ +} + +Transform BVHUnaligned::compute_aligned_space( + const BVHObjectBinning& range, + const BVHReference *references) const +{ + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + Transform aligned_space; + /* Use first primitive which defines correct direction to define + * the orientation space. + */ + if(compute_aligned_space(ref, &aligned_space)) { + return aligned_space; + } + } + return transform_identity(); +} + +Transform BVHUnaligned::compute_aligned_space( + const BVHRange& range, + const BVHReference *references) const +{ + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + Transform aligned_space; + /* Use first primitive which defines correct direction to define + * the orientation space. + */ + if(compute_aligned_space(ref, &aligned_space)) { + return aligned_space; + } + } + return transform_identity(); +} + +bool BVHUnaligned::compute_aligned_space(const BVHReference& ref, + Transform *aligned_space) const +{ + const Object *object = objects_[ref.prim_object()]; + const int packed_type = ref.prim_type(); + const int type = (packed_type & PRIMITIVE_ALL); + if(type & PRIMITIVE_CURVE) { + const int curve_index = ref.prim_index(); + const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); + const Mesh *mesh = object->mesh; + const Mesh::Curve& curve = mesh->get_curve(curve_index); + const int key = curve.first_key + segment; + const float3 v1 = mesh->curve_keys[key], + v2 = mesh->curve_keys[key + 1]; + float length; + const float3 axis = normalize_len(v2 - v1, &length); + if(length > 1e-6f) { + *aligned_space = make_transform_frame(axis); + return true; + } + } + *aligned_space = transform_identity(); + return false; +} + +BoundBox BVHUnaligned::compute_aligned_prim_boundbox( + const BVHReference& prim, + const Transform& aligned_space) const +{ + BoundBox bounds = BoundBox::empty; + const Object *object = objects_[prim.prim_object()]; + const int packed_type = prim.prim_type(); + const int type = (packed_type & PRIMITIVE_ALL); + if(type & PRIMITIVE_CURVE) { + const int curve_index = prim.prim_index(); + const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); + const Mesh *mesh = object->mesh; + const Mesh::Curve& curve = mesh->get_curve(curve_index); + curve.bounds_grow(segment, + &mesh->curve_keys[0], + &mesh->curve_radius[0], + aligned_space, + bounds); + } + else { + bounds = prim.bounds().transformed(&aligned_space); + } + return bounds; +} + +BoundBox BVHUnaligned::compute_aligned_boundbox( + const BVHObjectBinning& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds) const +{ + BoundBox bounds = BoundBox::empty; + if(cent_bounds != NULL) { + *cent_bounds = BoundBox::empty; + } + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space); + bounds.grow(ref_bounds); + if(cent_bounds != NULL) { + cent_bounds->grow(ref_bounds.center2()); + } + } + return bounds; +} + +BoundBox BVHUnaligned::compute_aligned_boundbox( + const BVHRange& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds) const +{ + BoundBox bounds = BoundBox::empty; + if(cent_bounds != NULL) { + *cent_bounds = BoundBox::empty; + } + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space); + bounds.grow(ref_bounds); + if(cent_bounds != NULL) { + cent_bounds->grow(ref_bounds.center2()); + } + } + return bounds; +} + +Transform BVHUnaligned::compute_node_transform( + const BoundBox& bounds, + const Transform& aligned_space) +{ + Transform space = aligned_space; + space.x.w -= bounds.min.x; + space.y.w -= bounds.min.y; + space.z.w -= bounds.min.z; + float3 dim = bounds.max - bounds.min; + return transform_scale(1.0f / max(1e-18f, dim.x), + 1.0f / max(1e-18f, dim.y), + 1.0f / max(1e-18f, dim.z)) * space; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h new file mode 100644 index 00000000000..4d0872f4a39 --- /dev/null +++ b/intern/cycles/bvh/bvh_unaligned.h @@ -0,0 +1,81 @@ +/* + * 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 __BVH_UNALIGNED_H__ +#define __BVH_UNALIGNED_H__ + +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +class BoundBox; +class BVHObjectBinning; +class BVHRange; +class BVHReference; +struct Transform; +class Object; + +/* Helper class to perform calculations needed for unaligned nodes. */ +class BVHUnaligned { +public: + BVHUnaligned(const vector<Object*>& objects); + + /* Calculate alignment for the oriented node for a given range. */ + Transform compute_aligned_space( + const BVHObjectBinning& range, + const BVHReference *references) const; + Transform compute_aligned_space( + const BVHRange& range, + const BVHReference *references) const; + + /* Calculate alignment for the oriented node for a given reference. + * + * Return true when space was calculated successfully. + */ + bool compute_aligned_space(const BVHReference& ref, + Transform *aligned_space) const; + + /* Calculate primitive's bounding box in given space. */ + BoundBox compute_aligned_prim_boundbox( + const BVHReference& prim, + const Transform& aligned_space) const; + + /* Calculate bounding box in given space. */ + BoundBox compute_aligned_boundbox( + const BVHObjectBinning& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds = NULL) const; + BoundBox compute_aligned_boundbox( + const BVHRange& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds = NULL) const; + + /* Calculate affine transform for node packing. + * Bounds will be in the range of 0..1. + */ + static Transform compute_node_transform(const BoundBox& bounds, + const Transform& aligned_space); +protected: + /* List of objects BVH is being created for. */ + const vector<Object*>& objects_; +}; + +CCL_NAMESPACE_END + +#endif /* __BVH_UNALIGNED_H__ */ + diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 275ee028eb4..aed86d8d853 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -155,7 +155,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; kernel_tex_copy(&kernel_globals, name, mem.data_pointer, diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 9a78d055580..2d404918a38 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -493,7 +493,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; /* Check if we are on sm_30 or above. * We use arrays and bindles textures for storage there */ @@ -1366,6 +1368,7 @@ void device_cuda_info(vector<DeviceInfo>& devices) /* if device has a kernel timeout, assume it is used for display */ if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) { + info.description += " (Display)"; info.display_device = true; display_devices.push_back(info); } diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 8c32d03135e..5b5b4dc6802 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -150,6 +150,11 @@ template<> struct device_type_traits<float4> { static const int num_elements = 4; }; +template<> struct device_type_traits<half> { + static const DataType data_type = TYPE_HALF; + static const int num_elements = 1; +}; + template<> struct device_type_traits<half4> { static const DataType data_type = TYPE_HALF; static const int num_elements = 4; diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 434d0085d39..c4f8d9e16e0 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -175,7 +175,9 @@ public: interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; foreach(SubDevice& sub, devices) { mem.device_pointer = 0; diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index cf4a05de8fc..3eb5ad2d2db 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -168,7 +168,9 @@ public: InterpolationType interpolation, ExtensionType extension) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; thread_scoped_lock lock(rpc_lock); diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 1b4e5421b5a..50490f3a20e 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -795,7 +795,7 @@ public: bool load_binary(const string& /*kernel_path*/, const string& clbin, - string custom_kernel_build_options, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { @@ -848,7 +848,7 @@ public: } bool build_kernel(cl_program *kernel_program, - string custom_kernel_build_options, + const string& custom_kernel_build_options, const string *debug_src = NULL) { string build_options; @@ -881,30 +881,39 @@ public: return true; } - bool compile_kernel(const string& kernel_path, - string source, - string custom_kernel_build_options, + bool compile_kernel(const string& kernel_name, + const string& kernel_path, + const string& source, + const string& custom_kernel_build_options, cl_program *kernel_program, const string *debug_src = NULL) { - /* we compile kernels consisting of many files. unfortunately opencl + /* We compile kernels consisting of many files. unfortunately OpenCL * kernel caches do not seem to recognize changes in included files. - * so we force recompile on changes by adding the md5 hash of all files */ - source = path_source_replace_includes(source, kernel_path); + * so we force recompile on changes by adding the md5 hash of all files. + */ + string inlined_source = path_source_replace_includes(source, + kernel_path); - if(debug_src) - path_write_text(*debug_src, source); + if(debug_src) { + path_write_text(*debug_src, inlined_source); + } - size_t source_len = source.size(); - const char *source_str = source.c_str(); + size_t source_len = inlined_source.size(); + const char *source_str = inlined_source.c_str(); - *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr); + *kernel_program = clCreateProgramWithSource(cxContext, + 1, + &source_str, + &source_len, + &ciErr); - if(opencl_error(ciErr)) + if(opencl_error(ciErr)) { return false; + } double starttime = time_dt(); - printf("Compiling OpenCL kernel ...\n"); + printf("Compiling %s OpenCL kernel ...\n", kernel_name.c_str()); /* TODO(sergey): Report which kernel is being compiled * as well (megakernel or which of split kernels etc..). */ @@ -1004,7 +1013,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("base_kernel", + kernel_path, init_kernel_source, build_flags, &cpProgram, @@ -1187,7 +1197,9 @@ public: InterpolationType /*interpolation*/, ExtensionType /*extension*/) { - VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; + VLOG(1) << "Texture allocate: " << name << ", " + << string_human_readable_number(mem.memory_size()) << " bytes. (" + << string_human_readable_size(mem.memory_size()) << ")"; mem_alloc(mem, MEM_READ_ONLY); mem_copy_to(mem); assert(mem_map.find(name) == mem_map.end()); @@ -1222,18 +1234,28 @@ public: CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL); clGetDeviceInfo(cdDevice, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, max_work_items, NULL); - - /* try to divide evenly over 2 dimensions */ + + /* Try to divide evenly over 2 dimensions. */ size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1); size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size}; - /* some implementations have max size 1 on 2nd dimension */ + /* Some implementations have max size 1 on 2nd dimension. */ if(local_size[1] > max_work_items[1]) { local_size[0] = workgroup_size/max_work_items[1]; local_size[1] = max_work_items[1]; } - size_t global_size[2] = {global_size_round_up(local_size[0], w), global_size_round_up(local_size[1], h)}; + size_t global_size[2] = {global_size_round_up(local_size[0], w), + global_size_round_up(local_size[1], h)}; + + /* Vertical size of 1 is coming from bake/shade kernels where we should + * not round anything up because otherwise we'll either be doing too + * much work per pixel (if we don't check global ID on Y axis) or will + * be checking for global ID to always have Y of 0. + */ + if (h == 1) { + global_size[h] = 1; + } /* run kernel */ opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL)); @@ -1318,48 +1340,49 @@ public: else kernel = ckShaderKernel; - for(int sample = 0; sample < task.num_samples; sample++) { - - if(task.get_cancel()) - break; - - cl_int d_sample = sample; - - cl_uint start_arg_index = - kernel_set_args(kernel, - 0, - d_data, - d_input, - d_output); + cl_uint start_arg_index = + kernel_set_args(kernel, + 0, + d_data, + d_input, + d_output); - if(task.shader_eval_type < SHADER_EVAL_BAKE) { - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_output_luma); - } + if(task.shader_eval_type < SHADER_EVAL_BAKE) { + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_output_luma); + } #define KERNEL_TEX(type, ttype, name) \ - set_kernel_arg_mem(kernel, &start_arg_index, #name); + set_kernel_arg_mem(kernel, &start_arg_index, #name); #include "kernel_textures.h" #undef KERNEL_TEX + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_shader_eval_type); + if(task.shader_eval_type >= SHADER_EVAL_BAKE) { start_arg_index += kernel_set_args(kernel, start_arg_index, - d_shader_eval_type); - if(task.shader_eval_type >= SHADER_EVAL_BAKE) { - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_shader_filter); - } - start_arg_index += kernel_set_args(kernel, - start_arg_index, - d_shader_x, - d_shader_w, - d_offset, - d_sample); + d_shader_filter); + } + start_arg_index += kernel_set_args(kernel, + start_arg_index, + d_shader_x, + d_shader_w, + d_offset); + + for(int sample = 0; sample < task.num_samples; sample++) { + + if(task.get_cancel()) + break; + + kernel_set_args(kernel, start_arg_index, sample); enqueue_kernel(kernel, task.shader_w, 1); + clFinish(cqCommandQueue); + task.update_progress(NULL); } } @@ -1681,7 +1704,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("mega_kernel", + kernel_path, init_kernel_source, custom_kernel_build_options, &path_trace_program, @@ -2065,30 +2089,33 @@ public: /* TODO(sergey): Seems really close to load_kernel(), * could it be de-duplicated? */ - bool load_split_kernel(string kernel_path, - string kernel_init_source, - string clbin, - string custom_kernel_build_options, + bool load_split_kernel(const string& kernel_name, + const string& kernel_path, + const string& kernel_init_source, + const string& clbin, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { - if(!opencl_version_check()) + if(!opencl_version_check()) { return false; + } - clbin = path_user_get(path_join("cache", clbin)); + string cache_clbin = path_user_get(path_join("cache", clbin)); /* If exists already, try use it. */ - if(path_exists(clbin) && load_binary(kernel_path, - clbin, - custom_kernel_build_options, - program, - debug_src)) + if(path_exists(cache_clbin) && load_binary(kernel_path, + cache_clbin, + custom_kernel_build_options, + program, + debug_src)) { /* Kernel loaded from binary. */ } else { /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel(kernel_name, + kernel_path, kernel_init_source, custom_kernel_build_options, program, @@ -2097,7 +2124,7 @@ public: return false; } /* Save binary for reuse. */ - if(!save_binary(program, clbin)) { + if(!save_binary(program, cache_clbin)) { return false; } } @@ -2195,7 +2222,10 @@ public: clsrc = path_user_get(path_join("cache", clsrc)); \ debug_src = &clsrc; \ } \ - if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \ + if(!load_split_kernel(#name, \ + kernel_path, \ + kernel_init_source, \ + clbin, \ build_options, \ &GLUE(name, _program), \ debug_src)) \ diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index d482577b73b..3c228a716d5 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -36,12 +36,8 @@ Node::Node(const NodeType *type_, ustring name_) } /* initialize default values */ - typedef unordered_map<ustring, SocketType, ustringHash> map_type; - foreach(const map_type::value_type& it, type->inputs) { - const SocketType& socket = it.second; - const void *src = socket.default_value; - void *dst = ((char*)this) + socket.struct_offset; - memcpy(dst, src, socket.size()); + foreach(const SocketType& socket, type->inputs) { + set_default_value(socket); } } @@ -86,6 +82,12 @@ void Node::set(const SocketType& input, int value) get_socket_value<int>(this, input) = value; } +void Node::set(const SocketType& input, uint value) +{ + assert(input.type == SocketType::UINT); + get_socket_value<uint>(this, input) = value; +} + void Node::set(const SocketType& input, float value) { assert(input.type == SocketType::FLOAT); @@ -104,6 +106,11 @@ void Node::set(const SocketType& input, float3 value) get_socket_value<float3>(this, input) = value; } +void Node::set(const SocketType& input, const char *value) +{ + set(input, ustring(value)); +} + void Node::set(const SocketType& input, ustring value) { if(input.type == SocketType::STRING) { @@ -197,6 +204,12 @@ int Node::get_int(const SocketType& input) const return get_socket_value<int>(this, input); } +uint Node::get_uint(const SocketType& input) const +{ + assert(input.type == SocketType::UINT); + return get_socket_value<uint>(this, input); +} + float Node::get_float(const SocketType& input) const { assert(input.type == SocketType::FLOAT); @@ -292,7 +305,8 @@ const array<Node*>& Node::get_node_array(const SocketType& input) const return get_socket_value<array<Node*> >(this, input); } -/* default values */ +/* generic value operations */ + bool Node::has_default_value(const SocketType& input) const { const void *src = input.default_value; @@ -300,6 +314,48 @@ bool Node::has_default_value(const SocketType& input) const return memcmp(dst, src, input.size()) == 0; } +void Node::set_default_value(const SocketType& socket) +{ + const void *src = socket.default_value; + void *dst = ((char*)this) + socket.struct_offset; + memcpy(dst, src, socket.size()); +} + +template<typename T> +static void copy_array(const Node *node, const SocketType& socket, const Node *other, const SocketType& other_socket) +{ + const array<T>* src = (const array<T>*)(((char*)other) + other_socket.struct_offset); + array<T>* dst = (array<T>*)(((char*)node) + socket.struct_offset); + *dst = *src; +} + +void Node::copy_value(const SocketType& socket, const Node& other, const SocketType& other_socket) +{ + assert(socket.type == other_socket.type); + + if(socket.is_array()) { + switch(socket.type) { + case SocketType::BOOLEAN_ARRAY: copy_array<bool>(this, socket, &other, other_socket); break; + case SocketType::FLOAT_ARRAY: copy_array<float>(this, socket, &other, other_socket); break; + case SocketType::INT_ARRAY: copy_array<int>(this, socket, &other, other_socket); break; + case SocketType::COLOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::VECTOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::POINT_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::NORMAL_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break; + case SocketType::POINT2_ARRAY: copy_array<float2>(this, socket, &other, other_socket); break; + case SocketType::STRING_ARRAY: copy_array<ustring>(this, socket, &other, other_socket); break; + case SocketType::TRANSFORM_ARRAY: copy_array<Transform>(this, socket, &other, other_socket); break; + case SocketType::NODE_ARRAY: copy_array<void*>(this, socket, &other, other_socket); break; + default: assert(0); break; + } + } + else { + const void *src = ((char*)&other) + other_socket.struct_offset; + void *dst = ((char*)this) + socket.struct_offset; + memcpy(dst, src, socket.size()); + } +} + template<typename T> static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket) { @@ -308,48 +364,43 @@ static bool is_array_equal(const Node *node, const Node *other, const SocketType return *a == *b; } -/* modified */ -bool Node::modified(const Node& other) +bool Node::equals_value(const Node& other, const SocketType& socket) const +{ + if(socket.is_array()) { + switch(socket.type) { + case SocketType::BOOLEAN_ARRAY: return is_array_equal<bool>(this, &other, socket); + case SocketType::FLOAT_ARRAY: return is_array_equal<float>(this, &other, socket); + case SocketType::INT_ARRAY: return is_array_equal<int>(this, &other, socket); + case SocketType::COLOR_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::VECTOR_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::POINT_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::NORMAL_ARRAY: return is_array_equal<float3>(this, &other, socket); + case SocketType::POINT2_ARRAY: return is_array_equal<float2>(this, &other, socket); + case SocketType::STRING_ARRAY: return is_array_equal<ustring>(this, &other, socket); + case SocketType::TRANSFORM_ARRAY: return is_array_equal<Transform>(this, &other, socket); + case SocketType::NODE_ARRAY: return is_array_equal<void*>(this, &other, socket); + default: assert(0); return true; + } + } + else { + const void *a = ((char*)this) + socket.struct_offset; + const void *b = ((char*)&other) + socket.struct_offset; + return (memcmp(a, b, socket.size()) == 0); + } +} + +/* equals */ + +bool Node::equals(const Node& other) const { assert(type == other.type); - typedef unordered_map<ustring, SocketType, ustringHash> map_type; - foreach(const map_type::value_type& it, type->inputs) { - const SocketType& socket = it.second; - - if(socket.is_array()) { - bool equal = true; - - switch(socket.type) - { - case SocketType::BOOLEAN_ARRAY: equal = is_array_equal<bool>(this, &other, socket); break; - case SocketType::FLOAT_ARRAY: equal = is_array_equal<float>(this, &other, socket); break; - case SocketType::INT_ARRAY: equal = is_array_equal<int>(this, &other, socket); break; - case SocketType::COLOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::VECTOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::POINT_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::NORMAL_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break; - case SocketType::POINT2_ARRAY: equal = is_array_equal<float2>(this, &other, socket); break; - case SocketType::STRING_ARRAY: equal = is_array_equal<ustring>(this, &other, socket); break; - case SocketType::TRANSFORM_ARRAY: equal = is_array_equal<Transform>(this, &other, socket); break; - case SocketType::NODE_ARRAY: equal = is_array_equal<void*>(this, &other, socket); break; - default: assert(0); break; - } - - if(!equal) { - return true; - } - } - else { - const void *a = ((char*)this) + socket.struct_offset; - const void *b = ((char*)&other) + socket.struct_offset; - if(memcmp(a, b, socket.size()) != 0) { - return true; - } - } + foreach(const SocketType& socket, type->inputs) { + if(!equals_value(other, socket)) + return false; } - return false; + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index 33971fa714a..64410f4539b 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -38,9 +38,11 @@ struct Node /* set values */ void set(const SocketType& input, bool value); void set(const SocketType& input, int value); + void set(const SocketType& input, uint value); void set(const SocketType& input, float value); void set(const SocketType& input, float2 value); void set(const SocketType& input, float3 value); + void set(const SocketType& input, const char *value); void set(const SocketType& input, ustring value); void set(const SocketType& input, const Transform& value); void set(const SocketType& input, Node *value); @@ -59,6 +61,7 @@ struct Node /* get values */ bool get_bool(const SocketType& input) const; int get_int(const SocketType& input) const; + uint get_uint(const SocketType& input) const; float get_float(const SocketType& input) const; float2 get_float2(const SocketType& input) const; float3 get_float3(const SocketType& input) const; @@ -76,11 +79,14 @@ struct Node const array<Transform>& get_transform_array(const SocketType& input) const; const array<Node*>& get_node_array(const SocketType& input) const; - /* default values */ + /* generic values operations */ bool has_default_value(const SocketType& input) const; + void set_default_value(const SocketType& input); + bool equals_value(const Node& other, const SocketType& input) const; + void copy_value(const SocketType& input, const Node& other, const SocketType& other_input); - /* modified */ - bool modified(const Node& other); + /* equals */ + bool equals(const Node& other) const; ustring name; const NodeType *type; diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index dc879655d7f..5b98de778ad 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -41,6 +41,7 @@ size_t SocketType::size(Type type) case BOOLEAN: return sizeof(bool); case FLOAT: return sizeof(float); case INT: return sizeof(int); + case UINT: return sizeof(uint); case COLOR: return sizeof(float3); case VECTOR: return sizeof(float3); case POINT: return sizeof(float3); @@ -88,6 +89,7 @@ ustring SocketType::type_name(Type type) ustring("boolean"), ustring("float"), ustring("int"), + ustring("uint"), ustring("color"), ustring("vector"), ustring("point"), @@ -114,9 +116,15 @@ ustring SocketType::type_name(Type type) return names[(int)type]; } +bool SocketType::is_float3(Type type) +{ + return (type == COLOR || type == VECTOR || type == POINT || type == NORMAL); +} + /* Node Type */ -NodeType::NodeType() +NodeType::NodeType(Type type_) +: type(type_) { } @@ -137,7 +145,7 @@ void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type ty socket.enum_values = enum_values; socket.node_type = node_type; socket.flags = flags | extra_flags; - inputs[name] = socket; + inputs.push_back(socket); } void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type type) @@ -151,7 +159,29 @@ void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type t socket.enum_values = NULL; socket.node_type = NULL; socket.flags = SocketType::LINKABLE; - outputs[name] = socket; + outputs.push_back(socket); +} + +const SocketType *NodeType::find_input(ustring name) const +{ + foreach(const SocketType& socket, inputs) { + if(socket.name == name) { + return &socket; + } + } + + return NULL; +} + +const SocketType *NodeType::find_output(ustring name) const +{ + foreach(const SocketType& socket, outputs) { + if(socket.name == name) { + return &socket; + } + } + + return NULL; } /* Node Type Registry */ @@ -162,7 +192,7 @@ unordered_map<ustring, NodeType, ustringHash>& NodeType::types() return _types; } -NodeType *NodeType::add(const char *name_, CreateFunc create_) +NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_) { ustring name(name_); @@ -172,7 +202,7 @@ NodeType *NodeType::add(const char *name_, CreateFunc create_) return NULL; } - types()[name] = NodeType(); + types()[name] = NodeType(type_); NodeType *type = &types()[name]; type->name = name; diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 82ddd29da33..60c3244028d 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -21,6 +21,7 @@ #include "util_map.h" #include "util_param.h" #include "util_string.h" +#include "util_vector.h" CCL_NAMESPACE_BEGIN @@ -38,6 +39,7 @@ struct SocketType BOOLEAN, FLOAT, INT, + UINT, COLOR, VECTOR, POINT, @@ -94,13 +96,19 @@ struct SocketType static size_t max_size(); static ustring type_name(Type type); static void *zero_default_value(); + static bool is_float3(Type type); }; /* Node Type */ struct NodeType { - explicit NodeType(); + enum Type { + NONE, + SHADER + }; + + explicit NodeType(Type type = NONE); ~NodeType(); void register_input(ustring name, ustring ui_name, SocketType::Type type, @@ -110,15 +118,18 @@ struct NodeType int flags = 0, int extra_flags = 0); void register_output(ustring name, ustring ui_name, SocketType::Type type); + const SocketType *find_input(ustring name) const; + const SocketType *find_output(ustring name) const; + typedef Node *(*CreateFunc)(const NodeType *type); - typedef unordered_map<ustring, SocketType, ustringHash> SocketMap; ustring name; - SocketMap inputs; - SocketMap outputs; + Type type; + std::vector<SocketType> inputs; + std::vector<SocketType> outputs; CreateFunc create; - static NodeType *add(const char *name, CreateFunc create); + static NodeType *add(const char *name, CreateFunc create, Type type = NONE); static const NodeType *find(ustring name); static unordered_map<ustring, NodeType, ustringHash>& types(); }; @@ -144,7 +155,7 @@ const NodeType *structname::register_type() #define SOCKET_DEFINE(name, ui_name, default_value, datatype, TYPE, flags, ...) \ { \ static datatype defval = default_value; \ - assert(SOCKET_SIZEOF(T, name) == sizeof(datatype)); \ + CHECK_TYPE(((T *)1)->name, datatype); \ type->register_input(ustring(#name), ustring(ui_name), TYPE, SOCKET_OFFSETOF(T, name), &defval, NULL, NULL, flags, ##__VA_ARGS__); \ } @@ -152,6 +163,8 @@ const NodeType *structname::register_type() SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, 0, ##__VA_ARGS__) #define SOCKET_INT(name, ui_name, default_value, ...) \ SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, 0, ##__VA_ARGS__) +#define SOCKET_UINT(name, ui_name, default_value, ...) \ + SOCKET_DEFINE(name, ui_name, default_value, uint, SocketType::UINT, 0, ##__VA_ARGS__) #define SOCKET_FLOAT(name, ui_name, default_value, ...) \ SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, 0, ##__VA_ARGS__) #define SOCKET_COLOR(name, ui_name, default_value, ...) \ diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp index fe06a243998..590e09645ed 100644 --- a/intern/cycles/graph/node_xml.cpp +++ b/intern/cycles/graph/node_xml.cpp @@ -58,9 +58,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) node->name = ustring(name_attr.value()); } - foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) { - const SocketType& socket = it.second; - + foreach(const SocketType& socket, node->type->inputs) { if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } @@ -110,6 +108,11 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) node->set(socket, (int)atoi(attr.value())); break; } + case SocketType::UINT: + { + node->set(socket, (uint)atoi(attr.value())); + break; + } case SocketType::INT_ARRAY: { vector<string> tokens; @@ -117,8 +120,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) array<int> value; value.resize(tokens.size()); - for(size_t i = 0; i < value.size(); i++) + for(size_t i = 0; i < value.size(); i++) { value[i] = (int)atoi(attr.value()); + } node->set(socket, value); break; } @@ -127,7 +131,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) case SocketType::POINT: case SocketType::NORMAL: { - array<float> value; + array<float3> value; xml_read_float_array<3>(value, attr); if(value.size() == 1) { node->set(socket, value[0]); @@ -161,11 +165,21 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) break; } case SocketType::STRING: - case SocketType::ENUM: { node->set(socket, attr.value()); break; } + case SocketType::ENUM: + { + ustring value(attr.value()); + if(socket.enum_values->exists(value)) { + node->set(socket, value); + } + else { + fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", value.c_str(), socket.name.c_str()); + } + break; + } case SocketType::STRING_ARRAY: { vector<string> tokens; @@ -173,8 +187,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) array<ustring> value; value.resize(tokens.size()); - for(size_t i = 0; i < value.size(); i++) + for(size_t i = 0; i < value.size(); i++) { value[i] = ustring(tokens[i]); + } node->set(socket, value); break; } @@ -245,9 +260,7 @@ pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root) xml_node.append_attribute("name") = node->name.c_str(); - foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) { - const SocketType& socket = it.second; - + foreach(const SocketType& socket, node->type->inputs) { if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) { continue; } @@ -302,6 +315,11 @@ pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root) attr = node->get_int(socket); break; } + case SocketType::UINT: + { + attr = node->get_uint(socket); + break; + } case SocketType::INT_ARRAY: { std::stringstream ss; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index b8f8aa03510..28695a2ebf9 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -28,6 +28,22 @@ set(SRC kernels/cuda/kernel.cu ) +set(SRC_BVH_HEADERS + bvh/bvh.h + bvh/bvh_nodes.h + bvh/bvh_shadow_all.h + bvh/bvh_subsurface.h + bvh/bvh_traversal.h + bvh/bvh_volume.h + bvh/bvh_volume_all.h + bvh/qbvh_nodes.h + bvh/qbvh_shadow_all.h + bvh/qbvh_subsurface.h + bvh/qbvh_traversal.h + bvh/qbvh_volume.h + bvh/qbvh_volume_all.h +) + set(SRC_HEADERS kernel_accumulate.h kernel_bake.h @@ -71,11 +87,14 @@ set(SRC_KERNELS_CPU_HEADERS ) set(SRC_CLOSURE_HEADERS + closure/alloc.h closure/bsdf.h closure/bsdf_ashikhmin_velvet.h closure/bsdf_diffuse.h closure/bsdf_diffuse_ramp.h closure/bsdf_microfacet.h + closure/bsdf_microfacet_multi.h + closure/bsdf_microfacet_multi_impl.h closure/bsdf_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_reflection.h @@ -102,6 +121,7 @@ set(SRC_SVM_HEADERS svm/svm_closure.h svm/svm_convert.h svm/svm_checker.h + svm/svm_color_util.h svm/svm_brick.h svm/svm_displace.h svm/svm_fresnel.h @@ -125,6 +145,7 @@ set(SRC_SVM_HEADERS svm/svm_noisetex.h svm/svm_normal.h svm/svm_ramp.h + svm/svm_ramp_util.h svm/svm_sepcomb_hsv.h svm/svm_sepcomb_vector.h svm/svm_sky.h @@ -141,23 +162,12 @@ set(SRC_SVM_HEADERS set(SRC_GEOM_HEADERS geom/geom.h geom/geom_attribute.h - geom/geom_bvh.h - geom/geom_bvh_shadow.h - geom/geom_bvh_subsurface.h - geom/geom_bvh_traversal.h - geom/geom_bvh_volume.h - geom/geom_bvh_volume_all.h geom/geom_curve.h geom/geom_motion_curve.h geom/geom_motion_triangle.h geom/geom_object.h geom/geom_primitive.h - geom/geom_qbvh.h - geom/geom_qbvh_shadow.h - geom/geom_qbvh_subsurface.h - geom/geom_qbvh_traversal.h - geom/geom_qbvh_volume.h - geom/geom_qbvh_volume_all.h + geom/geom_subd_triangle.h geom/geom_triangle.h geom/geom_triangle_intersect.h geom/geom_volume.h @@ -213,7 +223,14 @@ if(WITH_CYCLES_CUDA_BINARIES) endif() # build for each arch - set(cuda_sources kernels/cuda/kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS}) + set(cuda_sources kernels/cuda/kernel.cu + ${SRC_HEADERS} + ${SRC_BVH_HEADERS} + ${SRC_SVM_HEADERS} + ${SRC_GEOM_HEADERS} + ${SRC_CLOSURE_HEADERS} + ${SRC_UTIL_HEADERS} + ) set(cuda_cubins) macro(CYCLES_CUDA_KERNEL_ADD arch experimental) @@ -238,6 +255,7 @@ if(WITH_CYCLES_CUDA_BINARIES) OUTPUT ${cuda_cubin} COMMAND ${CUDA_NVCC_EXECUTABLE} -arch=${arch} + ${CUDA_NVCC_FLAGS} -m${CUDA_BITS} --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda/kernel.cu -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} @@ -312,6 +330,7 @@ add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_KERNELS_CPU_HEADERS} + ${SRC_BVH_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} @@ -346,6 +365,7 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteratio delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_sum_all_radiance.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/bvh) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom) diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/bvh/bvh.h index 9eadc97386c..59881738195 100644 --- a/intern/cycles/kernel/geom/geom_bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -35,6 +35,13 @@ CCL_NAMESPACE_BEGIN # define ccl_device_intersect ccl_device_inline #endif +/* bottom-most stack entry, indicating the end of traversal */ +#define ENTRYPOINT_SENTINEL 0x76543210 + +/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ +#define BVH_STACK_SIZE 192 +#define BVH_QSTACK_SIZE 384 + /* BVH intersection function variations */ #define BVH_INSTANCING 1 @@ -48,73 +55,97 @@ CCL_NAMESPACE_BEGIN #define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0) +/* Debugging heleprs */ +#ifdef __KERNEL_DEBUG__ +# define BVH_DEBUG_INIT() \ + do { \ + isect->num_traversal_steps = 0; \ + isect->num_traversed_instances = 0; \ + } while(0) +# define BVH_DEBUG_NEXT_STEP() \ + do { \ + ++isect->num_traversal_steps; \ + } while(0) +# define BVH_DEBUG_NEXT_INSTANCE() \ + do { \ + ++isect->num_traversed_instances; \ + } while(0) +#else /* __KERNEL_DEBUG__ */ +# define BVH_DEBUG_INIT() +# define BVH_DEBUG_NEXT_STEP() +# define BVH_DEBUG_NEXT_INSTANCE() +#endif /* __KERNEL_DEBUG__ */ + + /* Common QBVH functions. */ #ifdef __QBVH__ -# include "geom_qbvh.h" +# include "qbvh_nodes.h" #endif /* Regular BVH traversal */ +#include "bvh_nodes.h" + #define BVH_FUNCTION_NAME bvh_intersect #define BVH_FUNCTION_FEATURES 0 -#include "geom_bvh_traversal.h" +#include "bvh_traversal.h" #if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif /* Subsurface scattering BVH traversal */ #if defined(__SUBSURFACE__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_subsurface.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_subsurface.h" #endif #if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion -# define BVH_FUNCTION_FEATURES BVH_MOTION -# include "geom_bvh_subsurface.h" +# define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR +# include "bvh_subsurface.h" #endif /* Volume BVH traversal */ #if defined(__VOLUME__) # define BVH_FUNCTION_NAME bvh_intersect_volume -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_volume.h" #endif #if defined(__VOLUME__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_instancing -# define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR +# include "bvh_volume.h" #endif #if defined(__VOLUME__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_motion -# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR +# include "bvh_volume.h" #endif /* Record all intersections - Shadow BVH traversal */ @@ -122,51 +153,51 @@ CCL_NAMESPACE_BEGIN #if defined(__SHADOW_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all # define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif /* Record all intersections - Volume BVH traversal */ #if defined(__VOLUME_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_volume_all.h" #endif #if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing -# define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR +# include "bvh_volume_all.h" #endif #if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion -# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR +# include "bvh_volume_all.h" #endif #undef BVH_FEATURE diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h new file mode 100644 index 00000000000..db2275b0ff8 --- /dev/null +++ b/intern/cycles/kernel/bvh/bvh_nodes.h @@ -0,0 +1,656 @@ +/* + * 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. + */ + +// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and +// 3-vector which might be faster. +ccl_device_inline Transform bvh_unaligned_node_fetch_space(KernelGlobals *kg, + int node_addr, + int child) +{ + Transform space; + const int child_addr = node_addr + child * 3; + space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1); + space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2); + space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3); + space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + return space; +} + +#if !defined(__KERNEL_SSE2__) +ccl_device_inline int bvh_aligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + + /* fetch node data */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1); + float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2); + float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3); + + /* intersect ray against child nodes */ + float c0lox = (node0.x - P.x) * idir.x; + float c0hix = (node0.z - P.x) * idir.x; + float c0loy = (node1.x - P.y) * idir.y; + float c0hiy = (node1.z - P.y) * idir.y; + float c0loz = (node2.x - P.z) * idir.z; + float c0hiz = (node2.z - P.z) * idir.z; + float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); + float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + + float c1lox = (node0.y - P.x) * idir.x; + float c1hix = (node0.w - P.x) * idir.x; + float c1loy = (node1.y - P.y) * idir.y; + float c1hiy = (node1.w - P.y) * idir.y; + float c1loz = (node2.y - P.z) * idir.z; + float c1hiz = (node2.w - P.z) * idir.z; + float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); + float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + + dist[0] = c0min; + dist[1] = c1min; + +#ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); +#else + return ((c0max >= c0min)? 1: 0) | + ((c1max >= c1min)? 2: 0); +#endif +} + +ccl_device_inline int bvh_aligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + + /* fetch node data */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1); + float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2); + float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3); + + /* intersect ray against child nodes */ + float c0lox = (node0.x - P.x) * idir.x; + float c0hix = (node0.z - P.x) * idir.x; + float c0loy = (node1.x - P.y) * idir.y; + float c0hiy = (node1.z - P.y) * idir.y; + float c0loz = (node2.x - P.z) * idir.z; + float c0hiz = (node2.z - P.z) * idir.z; + float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); + float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + + float c1lox = (node0.y - P.x) * idir.x; + float c1hix = (node0.w - P.x) * idir.x; + float c1loy = (node1.y - P.y) * idir.y; + float c1hiy = (node1.w - P.y) * idir.y; + float c1loz = (node2.y - P.z) * idir.z; + float c1hiz = (node2.w - P.z) * idir.z; + float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); + float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + + if(difl != 0.0f) { + float hdiff = 1.0f + difl; + float ldiff = 1.0f - difl; + if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { + c0min = max(ldiff * c0min, c0min - extmax); + c0max = min(hdiff * c0max, c0max + extmax); + } + if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { + c1min = max(ldiff * c1min, c1min - extmax); + c1max = min(hdiff * c1max, c1max + extmax); + } + } + + dist[0] = c0min; + dist[1] = c1min; + +#ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); +#else + return ((c0max >= c0min)? 1: 0) | + ((c1max >= c1min)? 2: 0); +#endif +} + +ccl_device_inline bool bvh_unaligned_node_intersect_child( + KernelGlobals *kg, + const float3 P, + const float3 dir, + const float t, + int node_addr, + int child, + float dist[2]) +{ + Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child); + float3 aligned_dir = transform_direction(&space, dir); + float3 aligned_P = transform_point(&space, P); + float3 nrdir = -bvh_inverse_direction(aligned_dir); + float3 lower_xyz = aligned_P * nrdir; + float3 upper_xyz = lower_xyz - nrdir; + const float near_x = min(lower_xyz.x, upper_xyz.x); + const float near_y = min(lower_xyz.y, upper_xyz.y); + const float near_z = min(lower_xyz.z, upper_xyz.z); + const float far_x = max(lower_xyz.x, upper_xyz.x); + const float far_y = max(lower_xyz.y, upper_xyz.y); + const float far_z = max(lower_xyz.z, upper_xyz.z); + const float tnear = max4(0.0f, near_x, near_y, near_z); + const float tfar = min4(t, far_x, far_y, far_z); + *dist = tnear; + return tnear <= tfar; +} + +ccl_device_inline bool bvh_unaligned_node_intersect_child_robust( + KernelGlobals *kg, + const float3 P, + const float3 dir, + const float t, + const float difl, + int node_addr, + int child, + float dist[2]) +{ + Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child); + float3 aligned_dir = transform_direction(&space, dir); + float3 aligned_P = transform_point(&space, P); + float3 nrdir = -bvh_inverse_direction(aligned_dir); + float3 tLowerXYZ = aligned_P * nrdir; + float3 tUpperXYZ = tLowerXYZ - nrdir; + const float near_x = min(tLowerXYZ.x, tUpperXYZ.x); + const float near_y = min(tLowerXYZ.y, tUpperXYZ.y); + const float near_z = min(tLowerXYZ.z, tUpperXYZ.z); + const float far_x = max(tLowerXYZ.x, tUpperXYZ.x); + const float far_y = max(tLowerXYZ.y, tUpperXYZ.y); + const float far_z = max(tLowerXYZ.z, tUpperXYZ.z); + const float tnear = max4(0.0f, near_x, near_y, near_z); + const float tfar = min4(t, far_x, far_y, far_z); + *dist = tnear; + if(difl != 0.0f) { + /* TODO(sergey): Same as for QBVH, needs a proper use. */ + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + return round_down*tnear <= round_up*tfar; + } + else { + return tnear <= tfar; + } +} + +ccl_device_inline int bvh_unaligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + int mask = 0; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.x) & visibility)) +#endif + { + mask |= 1; + } + } + if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.y) & visibility)) +#endif + { + mask |= 2; + } + } + return mask; +} + +ccl_device_inline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + int mask = 0; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 0, &dist[0])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.x) & visibility)) +#endif + { + mask |= 1; + } + } + if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 1, &dist[1])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.y) & visibility)) +#endif + { + mask |= 2; + } + } + return mask; +} + +ccl_device_inline int bvh_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect(kg, + P, + dir, + idir, + t, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect(kg, + P, + idir, + t, + node_addr, + visibility, + dist); + } +} + +ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect_robust(kg, + P, + dir, + idir, + t, + difl, + extmax, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect_robust(kg, + P, + idir, + t, + difl, + extmax, + node_addr, + visibility, + dist); + } +} +#else /* !defined(__KERNEL_SSE2__) */ + +int ccl_device_inline bvh_aligned_node_intersect( + KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const int node_addr, + const uint visibility, + float dist[2]) +{ + /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); + + /* fetch node data */ + const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + node_addr; + + /* intersect ray against child nodes */ + const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; + const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; + const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; + + /* calculate { c0min, c1min, -c0max, -c1max} */ + ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); + const ssef tminmax = minmax ^ pn; + const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); + + dist[0] = tminmax[0]; + dist[1] = tminmax[1]; + + int mask = movemask(lrhit); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_aligned_node_intersect_robust( + KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const float difl, + const float extmax, + const int nodeAddr, + const uint visibility, + float dist[2]) +{ + /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); + + /* fetch node data */ + const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr; + + /* intersect ray against child nodes */ + const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; + const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; + const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; + + /* calculate { c0min, c1min, -c0max, -c1max} */ + ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); + const ssef tminmax = minmax ^ pn; + + if(difl != 0.0f) { + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0); + float4 *tminmaxview = (float4*)&tminmax; + float& c0min = tminmaxview->x, &c1min = tminmaxview->y; + float& c0max = tminmaxview->z, &c1max = tminmaxview->w; + float hdiff = 1.0f + difl; + float ldiff = 1.0f - difl; + if(__float_as_int(cnodes.x) & PATH_RAY_CURVE) { + c0min = max(ldiff * c0min, c0min - extmax); + c0max = min(hdiff * c0max, c0max + extmax); + } + if(__float_as_int(cnodes.y) & PATH_RAY_CURVE) { + c1min = max(ldiff * c1min, c1min - extmax); + c1max = min(hdiff * c1max, c1max + extmax); + } + } + + const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); + + dist[0] = tminmax[0]; + dist[1] = tminmax[1]; + + int mask = movemask(lrhit); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_unaligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const int node_addr, + const uint visibility, + float dist[2]) +{ + Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); + Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); + + float3 aligned_dir0 = transform_direction(&space0, dir), + aligned_dir1 = transform_direction(&space1, dir);; + float3 aligned_P0 = transform_point(&space0, P), + aligned_P1 = transform_point(&space1, P); + float3 nrdir0 = -bvh_inverse_direction(aligned_dir0), + nrdir1 = -bvh_inverse_direction(aligned_dir1); + + ssef lower_x = ssef(aligned_P0.x * nrdir0.x, + aligned_P1.x * nrdir1.x, + 0.0f, 0.0f), + lower_y = ssef(aligned_P0.y * nrdir0.y, + aligned_P1.y * nrdir1.y, + 0.0f, + 0.0f), + lower_z = ssef(aligned_P0.z * nrdir0.z, + aligned_P1.z * nrdir1.z, + 0.0f, + 0.0f); + + ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f), + upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f), + upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f); + + ssef tnear_x = min(lower_x, upper_x); + ssef tnear_y = min(lower_y, upper_y); + ssef tnear_z = min(lower_z, upper_z); + ssef tfar_x = max(lower_x, upper_x); + ssef tfar_y = max(lower_y, upper_y); + ssef tfar_z = max(lower_z, upper_z); + + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + sseb vmask = tnear <= tfar; + dist[0] = tnear.f[0]; + dist[1] = tnear.f[1]; + + int mask = (int)movemask(vmask); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_unaligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const float difl, + const int node_addr, + const uint visibility, + float dist[2]) +{ + Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); + Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); + + float3 aligned_dir0 = transform_direction(&space0, dir), + aligned_dir1 = transform_direction(&space1, dir);; + float3 aligned_P0 = transform_point(&space0, P), + aligned_P1 = transform_point(&space1, P); + float3 nrdir0 = -bvh_inverse_direction(aligned_dir0), + nrdir1 = -bvh_inverse_direction(aligned_dir1); + + ssef lower_x = ssef(aligned_P0.x * nrdir0.x, + aligned_P1.x * nrdir1.x, + 0.0f, 0.0f), + lower_y = ssef(aligned_P0.y * nrdir0.y, + aligned_P1.y * nrdir1.y, + 0.0f, + 0.0f), + lower_z = ssef(aligned_P0.z * nrdir0.z, + aligned_P1.z * nrdir1.z, + 0.0f, + 0.0f); + + ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f), + upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f), + upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f); + + ssef tnear_x = min(lower_x, upper_x); + ssef tnear_y = min(lower_y, upper_y); + ssef tnear_z = min(lower_z, upper_z); + ssef tfar_x = max(lower_x, upper_x); + ssef tfar_y = max(lower_y, upper_y); + ssef tfar_z = max(lower_z, upper_z); + + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + sseb vmask; + if(difl != 0.0f) { + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + vmask = round_down*tnear <= round_up*tfar; + } + else { + vmask = tnear <= tfar; + } + + dist[0] = tnear.f[0]; + dist[1] = tnear.f[1]; + + int mask = (int)movemask(vmask); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +ccl_device_inline int bvh_node_intersect(KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect(kg, + P, + dir, + isect_near, + isect_far, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect(kg, + P, + dir, + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); + } +} + +ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect_robust(kg, + P, + dir, + isect_near, + isect_far, + difl, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect_robust(kg, + P, + dir, + tsplat, + Psplat, + idirsplat, + shufflexyz, + difl, + extmax, + node_addr, + visibility, + dist); + } +} +#endif /* !defined(__KERNEL_SSE2__) */ diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 4005489f77d..1d6fa303d3e 100644 --- a/intern/cycles/kernel/geom/geom_bvh_shadow.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_shadow.h" +# include "qbvh_shadow_all.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function, where various features can be @@ -41,14 +47,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, * - likely and unlikely for if() statements * - test restrict attribute for pointers */ - + /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ const float tmax = ray->t; @@ -72,9 +78,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -93,130 +102,87 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_ahild1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW); - traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW); -# else - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, # endif - + idir, + isect_t, + node_addr, + PATH_RAY_SHADOW, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW); - traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW); -# else - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, # endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + PATH_RAY_SHADOW, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_ahild1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_ahild1; + node_addr_ahild1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_ahild1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_ahild1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ - while(primAddr < primAddr2) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + while(prim_addr < prim_addr2) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; @@ -226,22 +192,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #endif #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); - else - hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } + else { + hit = bvh_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } break; } #endif @@ -293,13 +294,13 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_array->t = isect_t; } - primAddr++; + prim_addr++; } } #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); @@ -317,21 +318,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -369,15 +373,18 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return false; } @@ -410,3 +417,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h index 915e9415c93..18978efcfa3 100644 --- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h +++ b/intern/cycles/kernel/bvh/bvh_subsurface.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_subsurface.h" +# include "qbvh_subsurface.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for subsurface scattering, where @@ -44,12 +50,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object); + int stack_ptr = 0; + int node_addr = kernel_tex_fetch(__object_node, subsurface_object); /* ray parameters in registers */ float3 P = ray->P; @@ -84,6 +90,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -100,127 +109,94 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* traversal loop */ do { - do - { + do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect_t, + node_addr, + PATH_RAY_ALL_VISIBILITY, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + PATH_RAY_ALL_VISIBILITY, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, &isect_precalc, ss_isect, P, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -230,15 +206,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); motion_triangle_intersect_subsurface(kg, ss_isect, P, dir, ray->time, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -251,8 +227,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } } } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); } ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, @@ -286,3 +262,4 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index 8560612addc..68a11b65ad7 100644 --- a/intern/cycles/kernel/geom/geom_bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -18,7 +18,15 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_traversal.h" +# include "qbvh_traversal.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +# define NODE_INTERSECT_ROBUST bvh_node_intersect_robust +#else +# define NODE_INTERSECT bvh_aligned_node_intersect +# define NODE_INTERSECT_ROBUST bvh_aligned_node_intersect_robust #endif /* This is a template BVH traversal function, where various features can be @@ -49,14 +57,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, * - likely and unlikely for if() statements * - test restrict attribute for pointers */ - + /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ float3 P = ray->P; @@ -74,17 +82,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect->prim = PRIM_NONE; isect->object = OBJECT_NONE; -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps = 0; - isect->num_traversed_instances = 0; -#endif + BVH_DEBUG_INIT(); #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect->t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -103,179 +111,148 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - # if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { - float hdiff = 1.0f + difl; - float ldiff = 1.0f - difl; - if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { - c0min = max(ldiff * c0min, c0min - extmax); - c0max = min(hdiff * c0max, c0max + extmax); - } - if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { - c1min = max(ldiff * c1min, c1min - extmax); - c1max = min(hdiff * c1max, c1max + extmax); - } + traverse_mask = NODE_INTERSECT_ROBUST(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + difl, + extmax, + node_addr, + visibility, + dist); } + else # endif - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility); - traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility); -# else - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); -# endif - + { + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + node_addr, + visibility, + dist); + } #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - # if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { - float4 *tminmaxview = (float4*)&tminmax; - float &c0min = tminmaxview->x, &c1min = tminmaxview->y; - float &c0max = tminmaxview->z, &c1max = tminmaxview->w; - - float hdiff = 1.0f + difl; - float ldiff = 1.0f - difl; - if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { - c0min = max(ldiff * c0min, c0min - extmax); - c0max = min(hdiff * c0max, c0max + extmax); - } - if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { - c1min = max(ldiff * c1min, c1min - extmax); - c1max = min(hdiff * c1max, c1max + extmax); - } + traverse_mask = NODE_INTERSECT_ROBUST(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + difl, + extmax, + node_addr, + visibility, + dist); } + else # endif - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility); - traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility); -# else - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); -# endif + { + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); + } #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } - -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif + BVH_DEBUG_NEXT_STEP(); } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr)) + { /* shadow ray early termination */ #if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif #else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -286,17 +263,26 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr)) + { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif # else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -309,22 +295,47 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - else - hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + else { + hit = bvh_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } if(hit) { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif # else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -339,7 +350,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); @@ -354,26 +365,27 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); -# if defined(__KERNEL_DEBUG__) - isect->num_traversed_instances++; -# endif + BVH_DEBUG_NEXT_INSTANCE(); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* instance pop */ @@ -390,16 +402,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } @@ -447,3 +462,5 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT +#undef NODE_INTERSECT_ROBUST diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h index f3edf85d723..03499e94347 100644 --- a/intern/cycles/kernel/geom/geom_bvh_volume.h +++ b/intern/cycles/kernel/bvh/bvh_volume.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -#include "geom_qbvh_volume.h" +# include "qbvh_volume.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for volumes, where @@ -43,12 +49,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ float3 P = ray->P; @@ -69,9 +75,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect->t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -90,143 +99,124 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + node_addr, + visibility, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr); + triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr); } break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr); + motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr); } break; } @@ -239,7 +229,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -258,29 +248,32 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* pop */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* instance pop */ @@ -298,16 +291,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_MOTION) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } @@ -337,3 +333,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index ec837212471..7eddc2891d0 100644 --- a/intern/cycles/kernel/geom/geom_bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -#include "geom_qbvh_volume_all.h" +# include "qbvh_volume_all.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for volumes, where @@ -44,12 +50,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ const float tmax = ray->t; @@ -73,9 +79,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -94,129 +103,103 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_array->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect_t, + node_addr, + visibility, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif - - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); bool hit; /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + visibility, + object, + prim_addr); if(hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -246,15 +229,22 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + visibility, + object, + prim_addr); if(hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -290,7 +280,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -311,29 +301,32 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* pop */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -368,16 +361,19 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_MOTION) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return num_hits; } @@ -410,3 +406,4 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h new file mode 100644 index 00000000000..4d8695bedec --- /dev/null +++ b/intern/cycles/kernel/bvh/qbvh_nodes.h @@ -0,0 +1,433 @@ +/* + * Copyright 2011-2014, 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. + */ + +struct QBVHStackItem { + int addr; + float dist; +}; + +/* TOOD(sergey): Investigate if using intrinsics helps for both + * stack item swap and float comparison. + */ +ccl_device_inline void qbvh_item_swap(QBVHStackItem *ccl_restrict a, + QBVHStackItem *ccl_restrict b) +{ + QBVHStackItem tmp = *a; + *a = *b; + *b = tmp; +} + +ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1, + QBVHStackItem *ccl_restrict s2, + QBVHStackItem *ccl_restrict s3) +{ + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } + if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } +} + +ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1, + QBVHStackItem *ccl_restrict s2, + QBVHStackItem *ccl_restrict s3, + QBVHStackItem *ccl_restrict s4) +{ + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } + if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); } + if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); } + if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); } + if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } +} + +/* Axis-aligned nodes intersection */ + +ccl_device_inline int qbvh_aligned_node_intersect(KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#else + const sse3f& org, +#endif + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr + 1; +#ifdef __KERNEL_AVX2__ + const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x); + const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y); + const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z); + const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x); + const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y); + const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z); +#else + const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x; + const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y; + const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z; + const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x; + const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y; + const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z; +#endif + +#ifdef __KERNEL_SSE41__ + const ssef tnear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, isect_near)); + const ssef tfar = mini(mini(tfar_x, tfar_y), mini(tfar_z, isect_far)); + const sseb vmask = cast(tnear) > cast(tfar); + int mask = (int)movemask(vmask)^0xf; +#else + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const sseb vmask = tnear <= tfar; + int mask = (int)movemask(vmask); +#endif + *dist = tnear; + return mask; +} + +ccl_device_inline int qbvh_aligned_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#else + const sse3f& P, +#endif + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr + 1; +#ifdef __KERNEL_AVX2__ + const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x); + const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y); + const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z); + const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x); + const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y); + const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z); +#else + const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x; + const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y; + const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z; + const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x; + const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y; + const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z; +#endif + + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const sseb vmask = round_down*tnear <= round_up*tfar; + *dist = tnear; + return (int)movemask(vmask); +} + +/* Unaligned nodes intersection */ + +ccl_device_inline int qbvh_unaligned_node_intersect( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#endif + const sse3f& org, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1); + const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2); + const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3); + + const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4); + const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5); + const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6); + + const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7); + const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8); + const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9); + + const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10); + const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11); + const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12); + + const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z, + aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z, + aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z; + + const ssef aligned_P_x = org.x*tfm_x_x + org.y*tfm_x_y + org.z*tfm_x_z + tfm_t_x, + aligned_P_y = org.x*tfm_y_x + org.y*tfm_y_y + org.z*tfm_y_z + tfm_t_y, + aligned_P_z = org.x*tfm_z_x + org.y*tfm_z_y + org.z*tfm_z_z + tfm_t_z; + + const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f); + const ssef nrdir_x = neg_one / aligned_dir_x, + nrdir_y = neg_one / aligned_dir_y, + nrdir_z = neg_one / aligned_dir_z; + + const ssef tlower_x = aligned_P_x * nrdir_x, + tlower_y = aligned_P_y * nrdir_y, + tlower_z = aligned_P_z * nrdir_z; + + const ssef tupper_x = tlower_x - nrdir_x, + tupper_y = tlower_y - nrdir_y, + tupper_z = tlower_z - nrdir_z; + +#ifdef __KERNEL_SSE41__ + const ssef tnear_x = mini(tlower_x, tupper_x); + const ssef tnear_y = mini(tlower_y, tupper_y); + const ssef tnear_z = mini(tlower_z, tupper_z); + const ssef tfar_x = maxi(tlower_x, tupper_x); + const ssef tfar_y = maxi(tlower_y, tupper_y); + const ssef tfar_z = maxi(tlower_z, tupper_z); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = tnear <= tfar; + *dist = tnear; + return movemask(vmask); +#else + const ssef tnear_x = min(tlower_x, tupper_x); + const ssef tnear_y = min(tlower_y, tupper_y); + const ssef tnear_z = min(tlower_z, tupper_z); + const ssef tfar_x = max(tlower_x, tupper_x); + const ssef tfar_y = max(tlower_y, tupper_y); + const ssef tfar_z = max(tlower_z, tupper_z); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = tnear <= tfar; + *dist = tnear; + return movemask(vmask); +#endif +} + +ccl_device_inline int qbvh_unaligned_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#endif + const sse3f& P, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1); + const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2); + const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3); + + const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4); + const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5); + const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6); + + const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7); + const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8); + const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9); + + const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10); + const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11); + const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12); + + const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z, + aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z, + aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z; + + const ssef aligned_P_x = P.x*tfm_x_x + P.y*tfm_x_y + P.z*tfm_x_z + tfm_t_x, + aligned_P_y = P.x*tfm_y_x + P.y*tfm_y_y + P.z*tfm_y_z + tfm_t_y, + aligned_P_z = P.x*tfm_z_x + P.y*tfm_z_y + P.z*tfm_z_z + tfm_t_z; + + const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f); + const ssef nrdir_x = neg_one / aligned_dir_x, + nrdir_y = neg_one / aligned_dir_y, + nrdir_z = neg_one / aligned_dir_z; + + const ssef tlower_x = aligned_P_x * nrdir_x, + tlower_y = aligned_P_y * nrdir_y, + tlower_z = aligned_P_z * nrdir_z; + + const ssef tupper_x = tlower_x - nrdir_x, + tupper_y = tlower_y - nrdir_y, + tupper_z = tlower_z - nrdir_z; + + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + +#ifdef __KERNEL_SSE41__ + const ssef tnear_x = mini(tlower_x, tupper_x); + const ssef tnear_y = mini(tlower_y, tupper_y); + const ssef tnear_z = mini(tlower_z, tupper_z); + const ssef tfar_x = maxi(tlower_x, tupper_x); + const ssef tfar_y = maxi(tlower_y, tupper_y); + const ssef tfar_z = maxi(tlower_z, tupper_z); +#else + const ssef tnear_x = min(tlower_x, tupper_x); + const ssef tnear_y = min(tlower_y, tupper_y); + const ssef tnear_z = min(tlower_z, tupper_z); + const ssef tfar_x = max(tlower_x, tupper_x); + const ssef tfar_y = max(tlower_y, tupper_y); + const ssef tfar_z = max(tlower_z, tupper_z); +#endif + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = round_down*tnear <= round_up*tfar; + *dist = tnear; + return movemask(vmask); +} + +/* Intersectors wrappers. + * + * They'll check node type and call appropriate intersection code. + */ + +ccl_device_inline int qbvh_node_intersect( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#endif + const sse3f& org, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const float4 node = kernel_tex_fetch(__bvh_nodes, offset); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return qbvh_unaligned_node_intersect(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + org_idir, +#endif + org, + dir, + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + dist); + } + else { + return qbvh_aligned_node_intersect(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + org_idir, +#else + org, +#endif + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + dist); + } +} + +ccl_device_inline int qbvh_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#endif + const sse3f& P, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const float4 node = kernel_tex_fetch(__bvh_nodes, offset); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return qbvh_unaligned_node_intersect_robust(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + P_idir, +#endif + P, + dir, + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + dist); + } + else { + return qbvh_aligned_node_intersect_robust(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + P_idir, +#else + P, +#endif + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + dist); + } +} diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index edb5b5c78c3..3a728b388eb 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -27,6 +27,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, @@ -39,12 +45,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ const float tmax = ray->t; @@ -72,13 +78,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(tmax); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -96,29 +106,53 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +# endif +# if BVH_FEATURE(BVH_HAIR) + dir4, +# endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -127,24 +161,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -152,86 +186,86 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); #ifdef __VISIBILITY_FLAG__ if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) { /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } #endif - int primAddr = __float_as_int(leaf.x); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ - while(primAddr < primAddr2) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + while(prim_addr < prim_addr2) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; @@ -241,22 +275,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #endif #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); - else - hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } + else { + hit = bvh_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } break; } #endif @@ -308,13 +377,13 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_array->t = isect_t; } - primAddr++; + prim_addr++; } } #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); @@ -329,28 +398,33 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -383,21 +457,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(tmax); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return false; } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h index 84512a8783c..03794e3a882 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h @@ -25,6 +25,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, SubsurfaceIntersection *ss_isect, @@ -41,12 +47,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object); + int stack_ptr = 0; + int node_addr = kernel_tex_fetch(__object_node, subsurface_object); /* Ray parameters in registers. */ float3 P = ray->P; @@ -82,13 +88,17 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(isect_t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -106,29 +116,43 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); + if(child_mask != 0) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -137,24 +161,24 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -162,82 +186,82 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* Intersect ray against primitive, */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, &isect_precalc, ss_isect, P, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -247,15 +271,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* Intersect ray against primitive. */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); motion_triangle_intersect_subsurface(kg, ss_isect, P, dir, ray->time, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -267,6 +291,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, break; } } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h new file mode 100644 index 00000000000..f82ff661495 --- /dev/null +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -0,0 +1,505 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation, + * and code copyright 2009-2012 Intel Corporation + * + * Modifications Copyright 2011-2014, 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. + */ + +/* This is a template BVH traversal function, where various features can be + * enabled/disabled. This way we can compile optimized versions for each case + * without new features slowing things down. + * + * BVH_INSTANCING: object instancing + * BVH_HAIR: hair curve rendering + * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width + * BVH_MOTION: motion blur rendering + * + */ + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +# define NODE_INTERSECT_ROBUST qbvh_node_intersect_robust +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +# define NODE_INTERSECT_ROBUST qbvh_aligned_node_intersect_robust +#endif + +ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, + const Ray *ray, + Intersection *isect, + const uint visibility +#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) + ,uint *lcg_state, + float difl, + float extmax +#endif + ) +{ + /* TODO(sergey): + * - Test if pushing distance on the stack helps (for non shadow rays). + * - Separate version for shadow rays. + * - Likely and unlikely for if() statements. + * - Test restrict attribute for pointers. + */ + + /* Traversal stack in CUDA thread-local memory. */ + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; + traversal_stack[0].dist = -FLT_MAX; + + /* Traversal variables in registers. */ + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; + float node_dist = -FLT_MAX; + + /* Ray parameters in registers. */ + float3 P = ray->P; + float3 dir = bvh_clamp_direction(ray->D); + float3 idir = bvh_inverse_direction(dir); + int object = OBJECT_NONE; + +#if BVH_FEATURE(BVH_MOTION) + Transform ob_itfm; +#endif + +#ifndef __KERNEL_SSE41__ + if(!isfinite(P.x)) { + return false; + } +#endif + + isect->t = ray->t; + isect->u = 0.0f; + isect->v = 0.0f; + isect->prim = PRIM_NONE; + isect->object = OBJECT_NONE; + + BVH_DEBUG_INIT(); + + ssef tnear(0.0f), tfar(ray->t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif + sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); + +#ifdef __KERNEL_AVX2__ + float3 P_idir = P*idir; + sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +#endif + + /* Offsets to select the side that becomes the lower or upper bound. */ + int near_x, near_y, near_z; + int far_x, far_y, far_z; + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + + IsectPrecalc isect_precalc; + triangle_intersect_precalc(dir, &isect_precalc); + + /* Traversal loop. */ + do { + do { + /* Traverse internal nodes. */ + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + + if(UNLIKELY(node_dist > isect->t) +#ifdef __VISIBILITY_FLAG__ + || (__float_as_uint(inodes.x) & visibility) == 0) +#endif + { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + int child_mask; + ssef dist; + + BVH_DEBUG_NEXT_STEP(); + +#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) + if(difl != 0.0f) { + /* NOTE: We extend all the child BB instead of fetching + * and checking visibility flags for each of the, + * + * Need to test if doing opposite would be any faster. + */ + child_mask = NODE_INTERSECT_ROBUST(kg, + tnear, + tfar, +# ifdef __KERNEL_AVX2__ + P_idir4, +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +# endif +# if BVH_FEATURE(BVH_HAIR) + dir4, +# endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + &dist); + } + else +#endif /* BVH_HAIR_MINIMUM_WIDTH */ + { + child_mask = NODE_INTERSECT(kg, + tnear, + tfar, +#ifdef __KERNEL_AVX2__ + P_idir4, +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + } + + if(child_mask != 0) { + float4 cnodes; + /* TODO(sergey): Investigate whether moving cnodes upwards + * gives a speedup (will be different cache pattern but will + * avoid extra check here), + */ +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } + + /* One child is hit, continue with that child. */ + int r = __bscf(child_mask); + float d0 = ((float*)&dist)[r]; + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); + node_dist = d0; + continue; + } + + /* Two children are hit, push far child, and continue with + * closer child. + */ + int c0 = __float_as_int(cnodes[r]); + r = __bscf(child_mask); + int c1 = __float_as_int(cnodes[r]); + float d1 = ((float*)&dist)[r]; + if(child_mask == 0) { + if(d1 < d0) { + node_addr = c1; + node_dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; + continue; + } + else { + node_addr = c0; + node_dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + continue; + } + } + + /* Here starts the slow path for 3 or 4 hit children. We push + * all nodes onto the stack to sort them there. + */ + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; + + /* Three children are hit, push all onto stack and sort 3 + * stack items, continue with closest child. + */ + r = __bscf(child_mask); + int c2 = __float_as_int(cnodes[r]); + float d2 = ((float*)&dist)[r]; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + /* Four children are hit, push all onto stack and sort 4 + * stack items, continue with closest child. + */ + r = __bscf(child_mask); + int c3 = __float_as_int(cnodes[r]); + float d3 = ((float*)&dist)[r]; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); + } + + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + } + + /* If node is leaf, fetch triangle list. */ + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + +#ifdef __VISIBILITY_FLAG__ + if(UNLIKELY((node_dist > isect->t) || + ((__float_as_uint(leaf.z) & visibility) == 0))) +#else + if(UNLIKELY((node_dist > isect->t))) +#endif + { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + int prim_addr = __float_as_int(leaf.x); + +#if BVH_FEATURE(BVH_INSTANCING) + if(prim_addr >= 0) { +#endif + int prim_addr2 = __float_as_int(leaf.y); + const uint type = __float_as_int(leaf.w); + + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + + /* Primitive intersection. */ + switch(type & PRIMITIVE_ALL) { + case PRIMITIVE_TRIANGLE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr)) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#if BVH_FEATURE(BVH_MOTION) + case PRIMITIVE_MOTION_TRIANGLE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr)) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#endif /* BVH_FEATURE(BVH_MOTION) */ +#if BVH_FEATURE(BVH_HAIR) + case PRIMITIVE_CURVE: + case PRIMITIVE_MOTION_CURVE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + bool hit; + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + else { + hit = bvh_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + if(hit) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#endif /* BVH_FEATURE(BVH_HAIR) */ + } + } +#if BVH_FEATURE(BVH_INSTANCING) + else { + /* Instance push. */ + object = kernel_tex_fetch(__prim_object, -prim_addr-1); + +# if BVH_FEATURE(BVH_MOTION) + qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist, &ob_itfm); +# else + qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist); +# endif + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif + idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# ifdef __KERNEL_AVX2__ + P_idir = P*idir; + P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + + triangle_intersect_precalc(dir, &isect_precalc); + + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; + traversal_stack[stack_ptr].dist = -FLT_MAX; + + node_addr = kernel_tex_fetch(__object_node, object); + + BVH_DEBUG_NEXT_INSTANCE(); + } + } +#endif /* FEATURE(BVH_INSTANCING) */ + } while(node_addr != ENTRYPOINT_SENTINEL); + +#if BVH_FEATURE(BVH_INSTANCING) + if(stack_ptr >= 0) { + kernel_assert(object != OBJECT_NONE); + + /* Instance pop. */ +# if BVH_FEATURE(BVH_MOTION) + bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); +# else + bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); +# endif + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif + idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# ifdef __KERNEL_AVX2__ + P_idir = P*idir; + P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + + triangle_intersect_precalc(dir, &isect_precalc); + + object = OBJECT_NONE; + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + } +#endif /* FEATURE(BVH_INSTANCING) */ + } while(node_addr != ENTRYPOINT_SENTINEL); + + return (isect->prim != PRIM_NONE); +} + +#undef NODE_INTERSECT +#undef NODE_INTERSECT_ROBUST diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index ab2e530dd20..b4f334eb842 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -26,6 +26,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect, @@ -38,12 +44,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ float3 P = ray->P; @@ -68,13 +74,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect->object = OBJECT_NONE; ssef tnear(0.0f), tfar(ray->t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -92,29 +102,52 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { +#ifdef __VISIBILITY_FLAG__ + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if((__float_as_uint(inodes.x) & visibility) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -123,24 +156,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -148,102 +181,102 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(p_type) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr); + triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, prim_addr); } break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr); + motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, prim_addr); } break; } @@ -253,7 +286,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -268,34 +301,39 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* Pop. */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* Instance pop. */ @@ -309,21 +347,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index 5546471b0e3..4d3028b37bf 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -26,6 +26,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, @@ -39,12 +45,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ const float tmax = ray->t; @@ -72,13 +78,17 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(isect_t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -96,29 +106,52 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { +#ifdef __VISIBILITY_FLAG__ + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if((__float_as_uint(inodes.x) & visibility) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -127,24 +160,24 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -152,88 +185,88 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; bool hit; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(p_type) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr); + hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr); if(hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -262,16 +295,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr); + hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, prim_addr); if(hit) { /* Move on to next entry in intersections array. */ isect_array++; @@ -304,7 +337,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -320,35 +353,40 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); num_hits_in_instance = 0; isect_array->t = isect_t; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* Pop. */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* Instance pop. */ @@ -379,23 +417,30 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); isect_t = tmax; isect_array->t = isect_t; object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return num_hits; } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h new file mode 100644 index 00000000000..b7abc1ec507 --- /dev/null +++ b/intern/cycles/kernel/closure/alloc.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +ccl_device ShaderClosure *closure_alloc(ShaderData *sd, int size, ClosureType type, float3 weight) +{ + kernel_assert(size <= sizeof(ShaderClosure)); + + int num_closure = ccl_fetch(sd, num_closure); + int num_closure_extra = ccl_fetch(sd, num_closure_extra); + if(num_closure + num_closure_extra >= MAX_CLOSURE) + return NULL; + + ShaderClosure *sc = &ccl_fetch(sd, closure)[num_closure]; + + sc->type = type; + sc->weight = weight; + + ccl_fetch(sd, num_closure)++; + + return sc; +} + +ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size) +{ + /* Allocate extra space for closure that need more parameters. We allocate + * in chunks of sizeof(ShaderClosure) starting from the end of the closure + * array. + * + * This lets us keep the same fast array iteration over closures, as we + * found linked list iteration and iteration with skipping to be slower. */ + int num_extra = ((size + sizeof(ShaderClosure) - 1) / sizeof(ShaderClosure)); + int num_closure = ccl_fetch(sd, num_closure); + int num_closure_extra = ccl_fetch(sd, num_closure_extra) + num_extra; + + if(num_closure + num_closure_extra > MAX_CLOSURE) { + /* Remove previous closure. */ + ccl_fetch(sd, num_closure)--; + ccl_fetch(sd, num_closure_extra)++; + return NULL; + } + + ccl_fetch(sd, num_closure_extra) = num_closure_extra; + return (ccl_addr_space void*)(ccl_fetch(sd, closure) + MAX_CLOSURE - num_closure_extra); +} + +ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight) +{ + ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); + + if(!sc) + return NULL; + + float sample_weight = fabsf(average(weight)); + sc->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; +} + +#ifdef __OSL__ +ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd, int size, float3 weight, void *data) +{ + ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight); + + if(!sc) + return NULL; + + memcpy(sc, data, size); + + float sample_weight = fabsf(average(weight)); + sc->weight = weight; + sc->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL; +} +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 1f225e1e96c..72096f4d873 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -20,6 +20,7 @@ #include "../closure/bsdf_phong_ramp.h" #include "../closure/bsdf_diffuse_ramp.h" #include "../closure/bsdf_microfacet.h" +#include "../closure/bsdf_microfacet_multi.h" #include "../closure/bsdf_reflection.h" #include "../closure/bsdf_refraction.h" #include "../closure/bsdf_transparent.h" @@ -39,15 +40,10 @@ CCL_NAMESPACE_BEGIN -ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) { int label; -#ifdef __OSL__ - if(kg->osl && sc->prim) - return OSLShader::bsdf_sample(sd, sc, randu, randv, *eval, *omega_in, *domega_in, *pdf); -#endif - switch(sc->type) { case CLOSURE_BSDF_DIFFUSE_ID: case CLOSURE_BSDF_BSSRDF_ID: @@ -59,14 +55,16 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_oren_nayar_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; - /*case CLOSURE_BSDF_PHONG_RAMP_ID: +#ifdef __OSL__ + case CLOSURE_BSDF_PHONG_RAMP_ID: label = bsdf_phong_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; case CLOSURE_BSDF_DIFFUSE_RAMP_ID: label = bsdf_diffuse_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); - break;*/ + break; +#endif case CLOSURE_BSDF_TRANSLUCENT_ID: label = bsdf_translucent_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); @@ -89,6 +87,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -129,10 +135,10 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_disney_sheen_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; - case CLOSURE_BSDF_DISNEY_SPECULAR_ID: + /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID: label = bsdf_disney_specular_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); - break; + break;*/ case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID: label = bsdf_disney_clearcoat_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); @@ -151,15 +157,10 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader return label; } -ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) { float3 eval; -#ifdef __OSL__ - if(kg->osl && sc->prim) - return OSLShader::bsdf_eval(sd, sc, omega_in, *pdf); -#endif - if(dot(ccl_fetch(sd, Ng), omega_in) >= 0.0f) { switch(sc->type) { case CLOSURE_BSDF_DIFFUSE_ID: @@ -170,12 +171,14 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_OREN_NAYAR_ID: eval = bsdf_oren_nayar_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; - /*case CLOSURE_BSDF_PHONG_RAMP_ID: +#ifdef __OSL__ + case CLOSURE_BSDF_PHONG_RAMP_ID: eval = bsdf_phong_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; case CLOSURE_BSDF_DIFFUSE_RAMP_ID: eval = bsdf_diffuse_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); - break;*/ + break; +#endif case CLOSURE_BSDF_TRANSLUCENT_ID: eval = bsdf_translucent_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; @@ -193,6 +196,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -224,9 +233,9 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_DISNEY_SHEEN_ID: eval = bsdf_disney_sheen_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; - case CLOSURE_BSDF_DISNEY_SPECULAR_ID: + /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID: eval = bsdf_disney_specular_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); - break; + break;*/ case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID: eval = bsdf_disney_clearcoat_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; @@ -268,6 +277,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -299,9 +314,9 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_DISNEY_SHEEN_ID: eval = bsdf_disney_sheen_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; - case CLOSURE_BSDF_DISNEY_SPECULAR_ID: + /*case CLOSURE_BSDF_DISNEY_SPECULAR_ID: eval = bsdf_disney_specular_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); - break; + break;*/ case CLOSURE_BSDF_DISNEY_CLEARCOAT_ID: eval = bsdf_disney_clearcoat_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; @@ -322,17 +337,13 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) { -/* ToDo: do we want to blur volume closures? */ - -#ifdef __OSL__ - if(kg->osl && sc->prim) { - OSLShader::bsdf_blur(sc, roughness); - return; - } -#endif - + /* ToDo: do we want to blur volume closures? */ #ifdef __SVM__ switch(sc->type) { + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + bsdf_microfacet_multi_ggx_blur(sc, roughness); + break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: @@ -353,5 +364,48 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) #endif } +ccl_device bool bsdf_merge(ShaderClosure *a, ShaderClosure *b) +{ +#ifdef __SVM__ + switch(a->type) { + case CLOSURE_BSDF_TRANSPARENT_ID: + return true; + case CLOSURE_BSDF_DIFFUSE_ID: + case CLOSURE_BSDF_BSSRDF_ID: + case CLOSURE_BSDF_TRANSLUCENT_ID: + return bsdf_diffuse_merge(a, b); + case CLOSURE_BSDF_OREN_NAYAR_ID: + return bsdf_oren_nayar_merge(a, b); + case CLOSURE_BSDF_REFLECTION_ID: + case CLOSURE_BSDF_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: + return bsdf_microfacet_merge(a, b); + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + return bsdf_ashikhmin_velvet_merge(a, b); + case CLOSURE_BSDF_DIFFUSE_TOON_ID: + case CLOSURE_BSDF_GLOSSY_TOON_ID: + return bsdf_toon_merge(a, b); + case CLOSURE_BSDF_HAIR_REFLECTION_ID: + case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: + return bsdf_hair_merge(a, b); +#ifdef __VOLUME__ + case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: + return volume_henyey_greenstein_merge(a, b); +#endif + default: + return false; + } +#endif +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h index 8d7d533d6f8..8ed76bea525 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h @@ -31,28 +31,30 @@ Other than that, the implementation directly follows the paper. CCL_NAMESPACE_BEGIN -ccl_device int bsdf_ashikhmin_shirley_setup(ShaderClosure *sc) +ccl_device int bsdf_ashikhmin_shirley_setup(MicrofacetBsdf *bsdf) { - sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); - sc->data1 = sc->data0; + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; - sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_ashikhmin_shirley_aniso_setup(ShaderClosure *sc) +ccl_device int bsdf_ashikhmin_shirley_aniso_setup(MicrofacetBsdf *bsdf) { - sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); - sc->data1 = clamp(sc->data1, 1e-4f, 1.0f); + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); - sc->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device void bsdf_ashikhmin_shirley_blur(ShaderClosure *sc, float roughness) { - sc->data0 = fmaxf(roughness, sc->data0); /* clamp roughness */ - sc->data1 = fmaxf(roughness, sc->data1); + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float roughness) @@ -62,14 +64,15 @@ ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float rough ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 N = bsdf->N; float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */ float NdotO = dot(N, omega_in); /* and consequently we use for O omaga_in ;) */ float out = 0.0f; - if(fmaxf(sc->data0, sc->data1) <= 1e-4f) + if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) return make_float3(0.0f, 0.0f, 0.0f); if(NdotI > 0.0f && NdotO > 0.0f) { @@ -82,8 +85,8 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c float pump = 1.0f / fmaxf(1e-6f, (HdotI*fmaxf(NdotO, NdotI))); /* pump from original paper (first derivative disc., but cancels the HdotI in the pdf nicely) */ /*float pump = 1.0f / fmaxf(1e-4f, ((NdotO + NdotI) * (NdotO*NdotI))); */ /* pump from d-brdf paper */ - float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data0); - float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1); + float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); + float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); if(n_x == n_y) { /* isotropic */ @@ -97,12 +100,18 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c else { /* anisotropic */ float3 X, Y; - make_orthonormals_tangent(N, sc->T, &X, &Y); + make_orthonormals_tangent(N, bsdf->T, &X, &Y); float HdotX = dot(H, X); float HdotY = dot(H, Y); - float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN); - float lobe = powf(HdotN, e); + float lobe; + if(HdotN < 1.0f) { + float e = (n_x * HdotX*HdotX + n_y * HdotY*HdotY) / (1.0f - HdotN*HdotN); + lobe = powf(HdotN, e); + } + else { + lobe = 1.0f; + } float norm = sqrtf((n_x + 1.0f)*(n_y + 1.0f)) / (8.0f * M_PI_F); out = NdotO * norm * lobe * pump; @@ -128,13 +137,14 @@ ccl_device_inline void bsdf_ashikhmin_shirley_sample_first_quadrant(float n_x, f ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 N = bsdf->N; float NdotI = dot(N, I); if(NdotI > 0.0f) { - float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data0); - float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(sc->data1); + float n_x = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_x); + float n_y = bsdf_ashikhmin_shirley_roughness_to_exponent(bsdf->alpha_y); /* get x,y basis on the surface for anisotropy */ float3 X, Y; @@ -142,7 +152,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, if(n_x == n_y) make_orthonormals(N, &X, &Y); else - make_orthonormals_tangent(N, sc->T, &X, &Y); + make_orthonormals_tangent(N, bsdf->T, &X, &Y); /* sample spherical coords for h in tangent space */ float phi; @@ -193,7 +203,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, /* reflect I on H to get omega_in */ *omega_in = -I + (2.0f * HdotI) * H; - if(fmaxf(sc->data0, sc->data1) <= 1e-4f) { + if(fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) { /* Some high number for MIS. */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h index f1a26650078..7e0f5a7ec75 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h @@ -35,20 +35,38 @@ CCL_NAMESPACE_BEGIN -ccl_device int bsdf_ashikhmin_velvet_setup(ShaderClosure *sc) +typedef ccl_addr_space struct VelvetBsdf { + SHADER_CLOSURE_BASE; + + float sigma; + float invsigma2; + float3 N; +} VelvetBsdf; + +ccl_device int bsdf_ashikhmin_velvet_setup(VelvetBsdf *bsdf) { - float sigma = fmaxf(sc->data0, 0.01f); - sc->data0 = 1.0f/(sigma * sigma); /* m_invsigma2 */ + float sigma = fmaxf(bsdf->sigma, 0.01f); + bsdf->invsigma2 = 1.0f/(sigma * sigma); - sc->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + bsdf->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device bool bsdf_ashikhmin_velvet_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const VelvetBsdf *bsdf_a = (const VelvetBsdf*)a; + const VelvetBsdf *bsdf_b = (const VelvetBsdf*)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && + (bsdf_a->sigma == bsdf_b->sigma); +} + ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float m_invsigma2 = sc->data0; - float3 N = sc->N; + const VelvetBsdf *bsdf = (const VelvetBsdf*)sc; + float m_invsigma2 = bsdf->invsigma2; + float3 N = bsdf->N; float cosNO = dot(N, I); float cosNI = dot(N, omega_in); @@ -90,8 +108,9 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, c ccl_device int bsdf_ashikhmin_velvet_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float m_invsigma2 = sc->data0; - float3 N = sc->N; + const VelvetBsdf *bsdf = (const VelvetBsdf*)sc; + float m_invsigma2 = bsdf->invsigma2; + float3 N = bsdf->N; // we are viewing the surface from above - send a ray out with uniform // distribution over the hemisphere diff --git a/intern/cycles/kernel/closure/bsdf_diffuse.h b/intern/cycles/kernel/closure/bsdf_diffuse.h index 4b29bb096d1..dcd187f9305 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse.h @@ -35,17 +35,31 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct DiffuseBsdf { + SHADER_CLOSURE_BASE; + float3 N; +} DiffuseBsdf; + /* DIFFUSE */ -ccl_device int bsdf_diffuse_setup(ShaderClosure *sc) +ccl_device int bsdf_diffuse_setup(DiffuseBsdf *bsdf) { - sc->type = CLOSURE_BSDF_DIFFUSE_ID; + bsdf->type = CLOSURE_BSDF_DIFFUSE_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device bool bsdf_diffuse_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const DiffuseBsdf *bsdf_a = (const DiffuseBsdf*)a; + const DiffuseBsdf *bsdf_b = (const DiffuseBsdf*)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)); +} + ccl_device float3 bsdf_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = sc->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; + float3 N = bsdf->N; float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; *pdf = cos_pi; @@ -59,7 +73,8 @@ ccl_device float3 bsdf_diffuse_eval_transmit(const ShaderClosure *sc, const floa ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; + float3 N = bsdf->N; // distribution over the hemisphere sample_cos_hemisphere(N, randu, randv, omega_in, pdf); @@ -80,9 +95,9 @@ ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc, float3 Ng, float3 I, /* TRANSLUCENT */ -ccl_device int bsdf_translucent_setup(ShaderClosure *sc) +ccl_device int bsdf_translucent_setup(DiffuseBsdf *bsdf) { - sc->type = CLOSURE_BSDF_TRANSLUCENT_ID; + bsdf->type = CLOSURE_BSDF_TRANSLUCENT_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } @@ -93,7 +108,8 @@ ccl_device float3 bsdf_translucent_eval_reflect(const ShaderClosure *sc, const f ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = sc->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; + float3 N = bsdf->N; float cos_pi = fmaxf(-dot(N, omega_in), 0.0f) * M_1_PI_F; *pdf = cos_pi; @@ -102,7 +118,8 @@ ccl_device float3 bsdf_translucent_eval_transmit(const ShaderClosure *sc, const ccl_device int bsdf_translucent_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; + float3 N = bsdf->N; // we are viewing the surface from the right side - send a ray out with cosine // distribution over the hemisphere diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h index e0287e7655a..2d982a95fe4 100644 --- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h +++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h @@ -35,7 +35,16 @@ CCL_NAMESPACE_BEGIN -ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos) +#ifdef __OSL__ + +typedef ccl_addr_space struct DiffuseRampBsdf { + SHADER_CLOSURE_BASE; + + float3 N; + float3 *colors; +} DiffuseRampBsdf; + +ccl_device float3 bsdf_diffuse_ramp_get_color(const float3 colors[8], float pos) { int MAXCOLORS = 8; @@ -49,11 +58,9 @@ ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const flo return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset; } -ccl_device int bsdf_diffuse_ramp_setup(ShaderClosure *sc) +ccl_device int bsdf_diffuse_ramp_setup(DiffuseRampBsdf *bsdf) { - sc->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID; - sc->data0 = 0.0f; - sc->data1 = 0.0f; + bsdf->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } @@ -61,29 +68,31 @@ ccl_device void bsdf_diffuse_ramp_blur(ShaderClosure *sc, float roughness) { } -ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = sc->N; + const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc; + float3 N = bsdf->N; float cos_pi = fmaxf(dot(N, omega_in), 0.0f); *pdf = cos_pi * M_1_PI_F; - return bsdf_diffuse_ramp_get_color(sc, colors, cos_pi) * M_1_PI_F; + return bsdf_diffuse_ramp_get_color(bsdf->colors, cos_pi) * M_1_PI_F; } -ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_diffuse_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 colors[8], float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + const DiffuseRampBsdf *bsdf = (const DiffuseRampBsdf*)sc; + float3 N = bsdf->N; // distribution over the hemisphere sample_cos_hemisphere(N, randu, randv, omega_in, pdf); if(dot(Ng, *omega_in) > 0.0f) { - *eval = bsdf_diffuse_ramp_get_color(sc, colors, *pdf * M_PI_F) * M_1_PI_F; + *eval = bsdf_diffuse_ramp_get_color(bsdf->colors, *pdf * M_PI_F) * M_1_PI_F; #ifdef __RAY_DIFFERENTIALS__ *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; @@ -95,6 +104,8 @@ ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc, const float3 co return LABEL_REFLECT|LABEL_DIFFUSE; } +#endif /* __OSL__ */ + CCL_NAMESPACE_END #endif /* __BSDF_DIFFUSE_RAMP_H__ */ diff --git a/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h b/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h index 377d21939b7..cdb8b3e0cff 100644 --- a/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h +++ b/intern/cycles/kernel/closure/bsdf_disney_clearcoat.h @@ -35,22 +35,30 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct DisneyClearcoatBsdf { + SHADER_CLOSURE_BASE; -ccl_device int bsdf_disney_clearcoat_setup(ShaderClosure *sc) + float clearcoat, clearcoatGloss, clearcoatRoughness; + float3 N; +} DisneyClearcoatBsdf; + +ccl_device int bsdf_disney_clearcoat_setup(DisneyClearcoatBsdf *bsdf) { /* clearcoat roughness */ - sc->custom1 = 0.1f * (1.0f - sc->data1/*clearcoatGloss*/) + 0.001f * sc->data1/*clearcoatGloss*/; // lerp(0.1f, 0.001f, sc->data1/*clearcoatGloss*/); // + bsdf->clearcoatRoughness = 0.1f * (1.0f - bsdf->clearcoatGloss) + 0.001f * bsdf->clearcoatGloss; // lerp(0.1f, 0.001f, sc->data1/*clearcoatGloss*/); // - sc->type = CLOSURE_BSDF_DISNEY_CLEARCOAT_ID; + bsdf->type = CLOSURE_BSDF_DISNEY_CLEARCOAT_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device float3 bsdf_disney_clearcoat_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - if (sc->data0 > 0.0f) { - float alpha = sc->custom1; - float3 N = sc->N; + const DisneyClearcoatBsdf *bsdf = (const DisneyClearcoatBsdf *)sc; + + if (bsdf->clearcoat > 0.0f) { + float alpha = bsdf->clearcoatRoughness; + float3 N = bsdf->N; if (alpha <= 1e-4f) return make_float3(0.0f, 0.0f, 0.0f); @@ -81,7 +89,7 @@ ccl_device float3 bsdf_disney_clearcoat_eval_reflect(const ShaderClosure *sc, co float common = D * 0.25f / cosNO; float FH = schlick_fresnel(dot(omega_in, m)); - float3 F = (0.04f * (1.0f - FH) + 1.0f * FH) * 0.25f * sc->data0/*clearcoat*/ * make_float3(1.0f, 1.0f, 1.0f); // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH); + float3 F = (0.04f * (1.0f - FH) + 1.0f * FH) * 0.25f * bsdf->clearcoat * make_float3(1.0f, 1.0f, 1.0f); // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH); float3 out = F * G * common; @@ -110,9 +118,11 @@ ccl_device int bsdf_disney_clearcoat_sample(const ShaderClosure *sc, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - if (sc->data0 > 0.0f) { - float alpha = sc->custom1; - float3 N = sc->N; + const DisneyClearcoatBsdf *bsdf = (const DisneyClearcoatBsdf *)sc; + + if (bsdf->clearcoat > 0.0f) { + float alpha = bsdf->clearcoatRoughness; + float3 N = bsdf->N; float cosNO = dot(N, I); if (cosNO > 0) { @@ -168,8 +178,8 @@ ccl_device int bsdf_disney_clearcoat_sample(const ShaderClosure *sc, float FH = schlick_fresnel(dot(*omega_in, m)); float3 F = make_float3(0.04f, 0.04f, 0.04f) * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(make_float3(0.04f, 0.04f, 0.04f), make_float3(1.0f, 1.0f, 1.0f), FH); - - *eval = G1i * common * F * 0.25f * sc->data0/*clearcoat*/; + + *eval = G1i * common * F * 0.25f * bsdf->clearcoat; } #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h index ac5032f3377..faeb00197c7 100644 --- a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h @@ -36,8 +36,15 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct DisneyDiffuseBsdf { + SHADER_CLOSURE_BASE; -ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc, + float roughness; + float3 N; + float3 baseColor; +} DisneyDiffuseBsdf; + +ccl_device float3 calculate_disney_diffuse_brdf(const DisneyDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf) { float NdotL = max(dot(N, L), 0.0f); @@ -51,10 +58,10 @@ ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc, float LdotH = dot(L, H); float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); - const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * sc->data0/*roughness*/; + const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * bsdf->roughness; float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV); //lerp(1.0f, Fd90, FL) * lerp(1.0f, Fd90, FV); - float3 value = M_1_PI_F * Fd * sc->color0/*baseColor*/; + float3 value = M_1_PI_F * Fd * bsdf->baseColor; *pdf = M_1_PI_F * 0.5f; @@ -63,22 +70,24 @@ ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc, return value; } -ccl_device int bsdf_disney_diffuse_setup(ShaderClosure *sc) +ccl_device int bsdf_disney_diffuse_setup(DisneyDiffuseBsdf *bsdf) { - sc->type = CLOSURE_BSDF_DISNEY_DIFFUSE_ID; + bsdf->type = CLOSURE_BSDF_DISNEY_DIFFUSE_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device float3 bsdf_disney_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = normalize(sc->N); + const DisneyDiffuseBsdf *bsdf = (const DisneyDiffuseBsdf *)sc; + + float3 N = normalize(bsdf->N); float3 V = I; // outgoing float3 L = omega_in; // incoming float3 H = normalize(L + V); - if (dot(sc->N, omega_in) > 0.0f) { - float3 value = calculate_disney_diffuse_brdf(sc, N, V, L, H, pdf); + if (dot(bsdf->N, omega_in) > 0.0f) { + float3 value = calculate_disney_diffuse_brdf(bsdf, N, V, L, H, pdf); return value; } @@ -99,14 +108,16 @@ ccl_device int bsdf_disney_diffuse_sample(const ShaderClosure *sc, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = normalize(sc->N); + const DisneyDiffuseBsdf *bsdf = (const DisneyDiffuseBsdf *)sc; + + float3 N = normalize(bsdf->N); sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); if (dot(Ng, *omega_in) > 0) { float3 H = normalize(I + *omega_in); - *eval = calculate_disney_diffuse_brdf(sc, N, I, *omega_in, H, pdf); + *eval = calculate_disney_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the diffuse bounce diff --git a/intern/cycles/kernel/closure/bsdf_disney_sheen.h b/intern/cycles/kernel/closure/bsdf_disney_sheen.h index 2806ecfc951..478ecaba324 100644 --- a/intern/cycles/kernel/closure/bsdf_disney_sheen.h +++ b/intern/cycles/kernel/closure/bsdf_disney_sheen.h @@ -36,14 +36,21 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct DisneySheenBsdf { + SHADER_CLOSURE_BASE; -ccl_device float3 calculate_disney_sheen_brdf(const ShaderClosure *sc, + float sheen, sheenTint; + float3 N; + float3 baseColor, csheen0; +} DisneySheenBsdf; + +ccl_device float3 calculate_disney_sheen_brdf(const DisneySheenBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf) { float NdotL = dot(N, L); float NdotV = dot(N, V); - if (NdotL < 0 || NdotV < 0 || sc->data0 == 0.0f) { + if (NdotL < 0 || NdotV < 0 || bsdf->sheen == 0.0f) { *pdf = 0.0f; return make_float3(0.0f, 0.0f, 0.0f); } @@ -54,36 +61,38 @@ ccl_device float3 calculate_disney_sheen_brdf(const ShaderClosure *sc, float FH = schlick_fresnel(LdotH); - float3 value = FH * sc->data0/*sheen*/ * sc->custom_color0/*csheen0*/; + float3 value = FH * bsdf->sheen * bsdf->csheen0; value *= NdotL; return value; } -ccl_device int bsdf_disney_sheen_setup(ShaderClosure *sc) +ccl_device int bsdf_disney_sheen_setup(DisneySheenBsdf *bsdf) { - float m_cdlum = 0.3f * sc->color0.x + 0.6f * sc->color0.y + 0.1f * sc->color0.z; // luminance approx. + float m_cdlum = 0.3f * bsdf->baseColor.x + 0.6f * bsdf->baseColor.y + 0.1f * bsdf->baseColor.z; // luminance approx. - float3 m_ctint = m_cdlum > 0.0f ? sc->color0 / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat + float3 m_ctint = m_cdlum > 0.0f ? bsdf->baseColor / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat /* csheen0 */ - sc->custom_color0 = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sc->data1/*sheenTint*/) + m_ctint * sc->data1/*sheenTint*/; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data1/*sheenTint*/); + bsdf->csheen0 = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - bsdf->sheenTint) + m_ctint * bsdf->sheenTint; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data1/*sheenTint*/); - sc->type = CLOSURE_BSDF_DISNEY_SHEEN_ID; + bsdf->type = CLOSURE_BSDF_DISNEY_SHEEN_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device float3 bsdf_disney_sheen_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float3 N = normalize(sc->N); + const DisneySheenBsdf *bsdf = (const DisneySheenBsdf *)sc; + + float3 N = normalize(bsdf->N); float3 V = I; // outgoing float3 L = omega_in; // incoming float3 H = normalize(L + V); - if (dot(sc->N, omega_in) > 0.0f) { - float3 value = calculate_disney_sheen_brdf(sc, N, V, L, H, pdf); + if (dot(bsdf->N, omega_in) > 0.0f) { + float3 value = calculate_disney_sheen_brdf(bsdf, N, V, L, H, pdf); return value; } @@ -104,14 +113,16 @@ ccl_device int bsdf_disney_sheen_sample(const ShaderClosure *sc, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = normalize(sc->N); + const DisneySheenBsdf *bsdf = (const DisneySheenBsdf *)sc; + + float3 N = normalize(bsdf->N); sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); if (dot(Ng, *omega_in) > 0) { float3 H = normalize(I + *omega_in); - *eval = calculate_disney_sheen_brdf(sc, N, I, *omega_in, H, pdf); + *eval = calculate_disney_sheen_brdf(bsdf, N, I, *omega_in, H, pdf); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the diffuse bounce diff --git a/intern/cycles/kernel/closure/bsdf_disney_specular.h b/intern/cycles/kernel/closure/bsdf_disney_specular.h index cbcfc4106c5..7e8139fd040 100644 --- a/intern/cycles/kernel/closure/bsdf_disney_specular.h +++ b/intern/cycles/kernel/closure/bsdf_disney_specular.h @@ -35,40 +35,47 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct DisneySpecularBsdf { + SHADER_CLOSURE_BASE; -ccl_device int bsdf_disney_specular_setup(ShaderClosure *sc) + float specular, specularTint, roughness, metallic, anisotropic, alpha_x, alpha_y, rough_g; + float3 N, T; + float3 baseColor, cspec0; +} DisneySpecularBsdf; + +ccl_device int bsdf_disney_specular_setup(DisneySpecularBsdf *bsdf) { - float m_cdlum = 0.3f * sc->color0.x + 0.6f * sc->color0.y + 0.1f * sc->color0.z; // luminance approx. + float m_cdlum = 0.3f * bsdf->baseColor.x + 0.6f * bsdf->baseColor.y + 0.1f * bsdf->baseColor.z; // luminance approx. - float3 m_ctint = m_cdlum > 0.0f ? sc->color0/*baseColor*/ / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat + float3 m_ctint = m_cdlum > 0.0f ? bsdf->baseColor / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat - float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sc->data2/*specularTint*/) + m_ctint * sc->data2/*specularTint*/; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data2/*specularTint*/); - sc->custom_color0/*cspec0*/ = (sc->data1/*specular*/ * 0.08f * tmp_col) * (1.0f - sc->data0/*metallic*/) + sc->color0/*baseColor*/ * sc->data0/*metallic*/; // lerp(sc->data1/*specular*/ * 0.08f * tmp_col, sc->color0/*baseColor*/, sc->data0/*metallic*/); + float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - bsdf->specularTint) + m_ctint * bsdf->specularTint; // lerp(make_float3(1.0f, 1.0f, 1.0f), m_ctint, sc->data2/*specularTint*/); + bsdf->cspec0 = (bsdf->specular * 0.08f * tmp_col) * (1.0f - bsdf->metallic) + bsdf->baseColor * bsdf->metallic; // lerp(sc->data1/*specular*/ * 0.08f * tmp_col, sc->color0/*baseColor*/, sc->data0/*metallic*/); - float aspect = safe_sqrtf(1.0f - sc->data4/*anisotropic*/ * 0.9f); - float r2 = sqr(sc->data3/*roughness*/); + float aspect = safe_sqrtf(1.0f - bsdf->anisotropic * 0.9f); + float r2 = sqr(bsdf->roughness); /* ax */ - sc->custom1 = fmaxf(0.001f, r2 / aspect); + bsdf->alpha_x = fmaxf(0.001f, r2 / aspect); /* ay */ - sc->custom2 = fmaxf(0.001f, r2 * aspect); + bsdf->alpha_y = fmaxf(0.001f, r2 * aspect); /* rough_g */ - sc->custom3 = sqr(sc->data3/*roughness*/ * 0.5f + 0.5f); + bsdf->rough_g = sqr(bsdf->roughness * 0.5f + 0.5f); - sc->type = CLOSURE_BSDF_DISNEY_SPECULAR_ID; + bsdf->type = CLOSURE_BSDF_DISNEY_SPECULAR_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float alpha_x = sc->custom1; - float alpha_y = sc->custom2; - float3 N = sc->N; + const DisneySpecularBsdf *bsdf = (const DisneySpecularBsdf *)sc; + + float3 N = bsdf->N; - if (fmaxf(alpha_x, alpha_y) <= 1e-4f) + if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -77,10 +84,10 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con if (cosNI > 0 && cosNO > 0) { /* get half vector */ float3 m = normalize(omega_in + I); - float alpha2 = alpha_x * alpha_y; + float alpha2 = bsdf->alpha_x * bsdf->alpha_y; float D, G1o, G1i; - if (alpha_x == alpha_y) { + if (bsdf->alpha_x == bsdf->alpha_y) { /* isotropic * eq. 20: (F*G*D)/(4*in*on) * eq. 33: first we calculate D(m) */ @@ -97,12 +104,12 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con else { /* anisotropic */ float3 X, Y, Z = N; - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); // distribution float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); + float slope_x = -local_m.x/(local_m.z*bsdf->alpha_x); + float slope_y = -local_m.y/(local_m.z*bsdf->alpha_y); float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; float cosThetaM = local_m.z; @@ -116,7 +123,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con float cosPhiO = dot(I, X); float sinPhiO = dot(I, Y); - float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); + float alphaO2 = (cosPhiO*cosPhiO)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiO*sinPhiO)*(bsdf->alpha_y*bsdf->alpha_y); alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2)); @@ -125,7 +132,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con float cosPhiI = dot(omega_in, X); float sinPhiI = dot(omega_in, Y); - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); + float alphaI2 = (cosPhiI*cosPhiI)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiI*sinPhiI)*(bsdf->alpha_y*bsdf->alpha_y); alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); @@ -137,7 +144,7 @@ ccl_device float3 bsdf_disney_specular_eval_reflect(const ShaderClosure *sc, con float common = D * 0.25f / cosNO; float FH = schlick_fresnel(dot(omega_in, m)); - float3 F = sc->custom_color0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + float3 F = bsdf->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); float3 out = F * G * common; @@ -166,18 +173,18 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float alpha_x = sc->custom1; - float alpha_y = sc->custom2; - float3 N = sc->N; + const DisneySpecularBsdf *bsdf = (const DisneySpecularBsdf *)sc; + + float3 N = bsdf->N; float cosNO = dot(N, I); if(cosNO > 0) { float3 X, Y, Z = N; - if(alpha_x == alpha_y) + if (bsdf->alpha_x == bsdf->alpha_y) make_orthonormals(Z, &X, &Y); else - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); /* importance sampling with distribution of visible normals. vectors are * transformed to local space before and after */ @@ -186,7 +193,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, float3 m; float G1o; - local_m = importance_sample_microfacet_stretched(local_I, alpha_x, alpha_y, + local_m = importance_sample_microfacet_stretched(local_I, bsdf->alpha_x, bsdf->alpha_y, randu, randv, false, &G1o); m = X*local_m.x + Y*local_m.y + Z*local_m.z; @@ -200,7 +207,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -208,10 +215,10 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, else { /* microfacet normal is visible to this ray */ /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; + float alpha2 = bsdf->alpha_x * bsdf->alpha_y; float D, G1i; - if(alpha_x == alpha_y) { + if (bsdf->alpha_x == bsdf->alpha_y) { float cosThetaM2 = cosThetaM * cosThetaM; float cosThetaM4 = cosThetaM2 * cosThetaM2; float tanThetaM2 = 1/(cosThetaM2) - 1; @@ -225,8 +232,8 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, } else { /* anisotropic distribution */ - float slope_x = -local_m.x/(local_m.z*alpha_x); - float slope_y = -local_m.y/(local_m.z*alpha_y); + float slope_x = -local_m.x / (local_m.z*bsdf->alpha_x); + float slope_y = -local_m.y / (local_m.z*bsdf->alpha_y); float slope_len = 1 + slope_x*slope_x + slope_y*slope_y; float cosThetaM = local_m.z; @@ -242,7 +249,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, float cosPhiI = dot(*omega_in, X); float sinPhiI = dot(*omega_in, Y); - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); + float alphaI2 = (cosPhiI*cosPhiI)*(bsdf->alpha_x*bsdf->alpha_x) + (sinPhiI*sinPhiI)*(bsdf->alpha_y*bsdf->alpha_y); alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); @@ -253,7 +260,7 @@ ccl_device int bsdf_disney_specular_sample(const ShaderClosure *sc, *pdf = common; float FH = schlick_fresnel(dot(*omega_in, m)); - float3 F = sc->custom_color0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + float3 F = bsdf->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); *eval = G1i * common * F; } diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h index 1e81617a7d3..bede5f45e7e 100644 --- a/intern/cycles/kernel/closure/bsdf_hair.h +++ b/intern/cycles/kernel/closure/bsdf_hair.h @@ -35,29 +35,49 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct HairBsdf { + SHADER_CLOSURE_BASE; -ccl_device int bsdf_hair_reflection_setup(ShaderClosure *sc) + float3 T; + float roughness1; + float roughness2; + float offset; +} HairBsdf; + +ccl_device int bsdf_hair_reflection_setup(HairBsdf *bsdf) { - sc->type = CLOSURE_BSDF_HAIR_REFLECTION_ID; - sc->data0 = clamp(sc->data0, 0.001f, 1.0f); - sc->data1 = clamp(sc->data1, 0.001f, 1.0f); + bsdf->type = CLOSURE_BSDF_HAIR_REFLECTION_ID; + bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); + bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_hair_transmission_setup(ShaderClosure *sc) +ccl_device int bsdf_hair_transmission_setup(HairBsdf *bsdf) { - sc->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; - sc->data0 = clamp(sc->data0, 0.001f, 1.0f); - sc->data1 = clamp(sc->data1, 0.001f, 1.0f); + bsdf->type = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; + bsdf->roughness1 = clamp(bsdf->roughness1, 0.001f, 1.0f); + bsdf->roughness2 = clamp(bsdf->roughness2, 0.001f, 1.0f); return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device bool bsdf_hair_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const HairBsdf *bsdf_a = (const HairBsdf*)a; + const HairBsdf *bsdf_b = (const HairBsdf*)b; + + return (isequal_float3(bsdf_a->T, bsdf_b->T)) && + (bsdf_a->roughness1 == bsdf_b->roughness1) && + (bsdf_a->roughness2 == bsdf_b->roughness2) && + (bsdf_a->offset == bsdf_b->offset); +} + ccl_device float3 bsdf_hair_reflection_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float offset = sc->data2; - float3 Tg = sc->T; - float roughness1 = sc->data0; - float roughness2 = sc->data1; + const HairBsdf *bsdf = (const HairBsdf*)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; float Iz = dot(Tg, I); float3 locy = normalize(I - Tg * Iz); @@ -107,10 +127,11 @@ ccl_device float3 bsdf_hair_reflection_eval_transmit(const ShaderClosure *sc, co ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float offset = sc->data2; - float3 Tg = sc->T; - float roughness1 = sc->data0; - float roughness2 = sc->data1; + const HairBsdf *bsdf = (const HairBsdf*)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; float Iz = dot(Tg, I); float3 locy = normalize(I - Tg * Iz); @@ -148,10 +169,11 @@ ccl_device float3 bsdf_hair_transmission_eval_transmit(const ShaderClosure *sc, ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float offset = sc->data2; - float3 Tg = sc->T; - float roughness1 = sc->data0; - float roughness2 = sc->data1; + const HairBsdf *bsdf = (const HairBsdf*)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; float Iz = dot(Tg, I); float3 locy = normalize(I - Tg * Iz); float3 locx = cross(locy, Tg); @@ -198,10 +220,11 @@ ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc, float3 Ng, f ccl_device int bsdf_hair_transmission_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float offset = sc->data2; - float3 Tg = sc->T; - float roughness1 = sc->data0; - float roughness2 = sc->data1; + const HairBsdf *bsdf = (const HairBsdf*)sc; + float offset = bsdf->offset; + float3 Tg = bsdf->T; + float roughness1 = bsdf->roughness1; + float roughness2 = bsdf->roughness2; float Iz = dot(Tg, I); float3 locy = normalize(I - Tg * Iz); float3 locx = cross(locy, Tg); diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 2a0e8f62e7c..7173ecd64de 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -35,6 +35,20 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct MicrofacetExtra { + float3 color, cspec0; + bool use_fresnel; +} MicrofacetExtra; + +typedef ccl_addr_space struct MicrofacetBsdf { + SHADER_CLOSURE_BASE; + + float alpha_x, alpha_y, ior; + MicrofacetExtra *extra; + float3 T; + float3 N; +} MicrofacetBsdf; + /* Beckmann and GGX microfacet importance sampling. */ ccl_device_inline void microfacet_beckmann_sample_slopes( @@ -233,50 +247,92 @@ ccl_device_inline float3 microfacet_sample_stretched( * Anisotropy is only supported for reflection currently, but adding it for * transmission is just a matter of copying code from reflection if needed. */ -ccl_device int bsdf_microfacet_ggx_setup(ShaderClosure *sc) +ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = sc->data0; /* alpha_y */ + if (bsdf->extra) { + bsdf->extra->use_fresnel = use_fresnel; + + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + } + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_microfacet_ggx_aniso_setup(ShaderClosure *sc) +ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = saturate(sc->data1); /* alpha_y */ + const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf*)a; + const MicrofacetBsdf *bsdf_b = (const MicrofacetBsdf*)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && + (bsdf_a->alpha_x == bsdf_b->alpha_x) && + (bsdf_a->alpha_y == bsdf_b->alpha_y) && + (isequal_float3(bsdf_a->T, bsdf_b->T)) && + (bsdf_a->ior == bsdf_b->ior) && + ((!bsdf_a->extra && !bsdf_b->extra) || + ((bsdf_a->extra && bsdf_b->extra) && + (isequal_float3(bsdf_a->extra->color, bsdf_b->extra->color)))); +} + +ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) +{ + if (bsdf->extra) { + bsdf->extra->use_fresnel = use_fresnel; + + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + } + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); - sc->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_microfacet_ggx_refraction_setup(ShaderClosure *sc) +ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = sc->data0; /* alpha_y */ + if (bsdf->extra) { + bsdf->extra->use_fresnel = use_fresnel; + + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + } + + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness) { - sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */ - sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); } ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -305,7 +361,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons else { /* anisotropic */ float3 X, Y, Z = N; - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); /* distribution */ float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); @@ -343,7 +399,17 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons /* eq. 20 */ float common = D * 0.25f / cosNO; - float out = G * common; + + float3 F = make_float3(1.0f, 1.0f, 1.0f); + if (bsdf->extra) { + if (bsdf->extra->use_fresnel) { + float FH = schlick_fresnel(dot(omega_in, m)); + + F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + } + } + + float3 out = F * G * common; /* eq. 2 in distribution of visible normals sampling * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ @@ -353,7 +419,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons * pdf = pm * 0.25 / dot(m, I); */ *pdf = G1o * common; - return make_float3(out, out, out); + return out; } return make_float3(0.0f, 0.0f, 0.0f); @@ -361,13 +427,14 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - float m_eta = sc->data2; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = sc->N; - - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + float m_eta = bsdf->ior; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; + + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -407,18 +474,29 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; + + float3 F = make_float3(1.0f, 1.0f, 1.0f); + if (bsdf->extra) { + if (bsdf->extra->use_fresnel) { + float FH = schlick_fresnel(dot(omega_in, Ht)); + + F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + } + } + + float3 out = G * fabsf(cosHI * cosHO) * common * F; *pdf = G1o * fabsf(cosHO * cosHI) * common; - return make_float3(out, out, out); + return out; } ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 N = bsdf->N; float cosNO = dot(N, I); if(cosNO > 0) { @@ -427,7 +505,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure if(alpha_x == alpha_y) make_orthonormals(Z, &X, &Y); else - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); /* importance sampling with distribution of visible normals. vectors are * transformed to local space before and after */ @@ -450,7 +528,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -502,10 +580,18 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* see eval function for derivation */ float common = (G1o * D) * 0.25f / cosNO; - float out = G1i * common; *pdf = common; - *eval = make_float3(out, out, out); + float3 F = make_float3(1.0f, 1.0f, 1.0f); + if (bsdf->extra) { + if (bsdf->extra->use_fresnel) { + float FH = schlick_fresnel(dot(*omega_in, m)); + + F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + } + } + + *eval = G1i * common * F; } #ifdef __RAY_DIFFERENTIALS__ @@ -522,7 +608,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure #ifdef __RAY_DIFFERENTIALS__ float3 dRdx, dRdy, dTdx, dTdy; #endif - float m_eta = sc->data2, fresnel; + float m_eta = bsdf->ior, fresnel; bool inside; fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, @@ -539,7 +625,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -566,10 +652,20 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* see eval function for derivation */ float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2); - float out = G1i * fabsf(cosHI * cosHO) * common; + + float3 F = make_float3(1.0f, 1.0f, 1.0f); + if (bsdf->extra) { + if (bsdf->extra->use_fresnel) { + float FH = schlick_fresnel(dot(*omega_in, m)); + + F = bsdf->extra->cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH; // lerp(sc->custom_color0, make_float3(1.0f, 1.0f, 1.0f), FH); + } + } + + float3 out = G1i * fabsf(cosHI * cosHO) * common * F; *pdf = cosHO * fabsf(cosHI) * common; - *eval = make_float3(out, out, out); + *eval = out; } } } @@ -582,47 +678,80 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure * Microfacet Models for Refraction through Rough Surfaces * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */ -ccl_device int bsdf_microfacet_beckmann_setup(ShaderClosure *sc) +ccl_device int bsdf_microfacet_beckmann_setup(MicrofacetBsdf *bsdf) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = sc->data0; /* alpha_y */ + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_microfacet_beckmann_aniso_setup(ShaderClosure *sc) +ccl_device int bsdf_microfacet_beckmann_aniso_setup(MicrofacetBsdf *bsdf) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = saturate(sc->data1); /* alpha_y */ + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = saturate(bsdf->alpha_y); - sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device int bsdf_microfacet_beckmann_refraction_setup(ShaderClosure *sc) +ccl_device int bsdf_microfacet_beckmann_refraction_setup(MicrofacetBsdf *bsdf) { - sc->data0 = saturate(sc->data0); /* alpha_x */ - sc->data1 = sc->data0; /* alpha_y */ + bsdf->alpha_x = saturate(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; - sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness) { - sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */ - sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); +} + +ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) +{ + cos_n *= cos_n; + float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); +} + +ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) +{ + cos_n *= cos_n; + sin_phi *= sin_phi; + cos_phi *= cos_phi; + alpha_x *= alpha_x; + alpha_y *= alpha_y; + + float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi); + float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); } ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -646,15 +775,13 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_G1(alpha_x, cosNO); + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic */ float3 X, Y, Z = N; - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); /* distribution */ float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); @@ -668,24 +795,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) and G1(o,m) */ - float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); - float cosPhiO = dot(I, X); - float sinPhiO = dot(I, Y); - - float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); - alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(omega_in, X); - float sinPhiI = dot(omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2)); - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); } float G = G1o * G1i; @@ -710,13 +821,14 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - float m_eta = sc->data2; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = sc->N; - - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + float m_eta = bsdf->ior; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; + + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -740,10 +852,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1o = bsdf_beckmann_G1(alpha_x, cosNO); + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* probability */ @@ -763,10 +873,11 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float alpha_x = sc->data0; - float alpha_y = sc->data1; - bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; float cosNO = dot(N, I); if(cosNO > 0) { @@ -775,7 +886,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl if(alpha_x == alpha_y) make_orthonormals(Z, &X, &Y); else - make_orthonormals_tangent(Z, sc->T, &X, &Y); + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); /* importance sampling with distribution of visible normals. vectors are * transformed to local space before and after */ @@ -798,7 +909,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -820,8 +931,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic distribution */ @@ -836,16 +946,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) */ - float cosNI = dot(N, *omega_in); - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(*omega_in, X); - float sinPhiI = dot(*omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); } float G = G1o * G1i; @@ -872,7 +973,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl #ifdef __RAY_DIFFERENTIALS__ float3 dRdx, dRdy, dTdx, dTdy; #endif - float m_eta = sc->data2, fresnel; + float m_eta = bsdf->ior, fresnel; bool inside; fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, @@ -889,7 +990,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -906,8 +1007,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* eq. 21 */ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h new file mode 100644 index 00000000000..38c645cba87 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -0,0 +1,507 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */ + +/* === GGX Microfacet distribution functions === */ + +/* Isotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx(float3 wm, float alpha) +{ + wm.z *= wm.z; + alpha *= alpha; + float tmp = (1.0f - wm.z) + alpha * wm.z; + return alpha / max(M_PI_F * tmp*tmp, 1e-7f); +} + +/* Anisotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) +{ + float slope_x = -wm.x/alpha.x; + float slope_y = -wm.y/alpha.y; + float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y; + + return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f); +} + +/* Sample slope distribution (based on page 14 of the supplemental implementation). */ +ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU) +{ + if(cosI > 0.9999f || cosI < 1e-6f) { + const float r = sqrtf(randU.x / (1.0f - randU.x)); + const float phi = M_2PI_F * randU.y; + return make_float2(r*cosf(phi), r*sinf(phi)); + } + + const float sinI = sqrtf(1.0f - cosI*cosI); + const float tanI = sinI/cosI; + const float projA = 0.5f * (cosI + 1.0f); + if(projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f*randU.x*projA / cosI - 1.0f; + float tmp = A*A-1.0f; + if(fabsf(tmp) < 1e-7f) + return make_float2(0.0f, 0.0f); + tmp = 1.0f / tmp; + const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp); + + const float slopeX2 = tanI*tmp + D; + const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; + + float U2; + if(randU.y >= 0.5f) + U2 = 2.0f*(randU.y - 0.5f); + else + U2 = 2.0f*(0.5f - randU.y); + const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); + const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); + + if(randU.y >= 0.5f) + return make_float2(slopeX, slopeY); + else + return make_float2(slopeX, -slopeY); +} + +/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ +ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU) +{ + const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU); + + const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y)); + const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); + const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); + + kernel_assert(isfinite(slope_x)); + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); +} + +/* === Phase functions: Glossy, Diffuse and Glass === */ + +/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm) +{ + if(n && k) + *weight *= fresnel_conductor(dot(wi, wm), *n, *k); + + return -wi + 2.0f * wm * dot(wi, wm); +} + +ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + + const float dotW_WH = dot(-w, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); + if(alpha.x == alpha.y) + phase *= D_ggx(wh, alpha.x); + else + phase *= D_ggx_aniso(wh, alpha); + + if(n && k) { + /* Apply conductive fresnel term. */ + return phase * fresnel_conductor(dotW_WH, *n, *k); + } + + return make_float3(phase, phase, phase); +} + +/* Phase function for rough lambertian diffuse surfaces. */ +ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv) +{ + float3 tm, bm; + make_orthonormals(wm, &tm, &bm); + + float2 disk = concentric_sample_disk(randu, randv); + return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm; +} + +ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm) +{ + const float v = max(0.0f, dot(w, wm)) * M_1_PI_F; + return make_float3(v, v, v); +} + +/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if(randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f/eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta); + return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta); +} + +ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float v; + if(wo_outside) { + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo*eta - w); + if(wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta*dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); +} + +/* === Utility functions for the random walks === */ + +/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ +ccl_device_inline float mf_lambda(const float3 w, const float2 alpha) +{ + if(w.z > 0.9999f) + return 0.0f; + else if(w.z < -0.9999f) + return -0.9999f; + + const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f); + const float2 wa = make_float2(w.x, w.y)*alpha; + float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); + if(w.z <= 0.0f) + v = -v; + + return 0.5f*(v - 1.0f); +} + +/* Height distribution CDF (based on page 4 of the supplemental implementation). */ +ccl_device_inline float mf_invC1(const float h) +{ + return 2.0f * saturate(h) - 1.0f; +} + +ccl_device_inline float mf_C1(const float h) +{ + return saturate(0.5f * (h + 1.0f)); +} + +/* Masking function (based on page 16 of the supplemental implementation). */ +ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda) +{ + if(w.z > 0.9999f) + return 1.0f; + if(w.z < 1e-5f) + return 0.0f; + return powf(C1, lambda); +} + +/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */ +ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if(w.z > 0.9999f) + return false; + if(w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if(fabsf(w.z) >= 0.0001f) { + if(U > 1.0f - *G1) + return false; + if(*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f-U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; +} + +/* === PDF approximations for the different phase functions. === + * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */ + +/* Approximation for the albedo of the single-scattering GGX distribution, + * the missing energy is then approximated as a diffuse reflection for the PDF. */ +ccl_device_inline float mf_ggx_albedo(float r) +{ + float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f; + albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f; + return saturate(albedo); +} + +ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) +{ + float D = D_ggx(normalize(wi+wo), alpha); + float lambda = mf_lambda(wi, make_float2(alpha, alpha)); + float albedo = mf_ggx_albedo(alpha); + return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z; +} + +ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) +{ + return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z; +} + +ccl_device_inline float mf_diffuse_pdf(const float3 wo) +{ + return M_1_PI_F * wo.z; +} + +ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta) +{ + float3 wh; + float fresnel; + if(wi.z*wo.z > 0.0f) { + wh = normalize(wi + wo); + fresnel = fresnel_dielectric_cos(dot(wi, wh), eta); + } + else { + wh = normalize(wi + wo*eta); + fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta); + } + if(wh.z < 0.0f) + wh = -wh; + float3 r_wi = (wi.z < 0.0f)? -wi: wi; + return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z); +} + +/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */ + +#define MF_NAME_JOIN(x,y) x ## _ ## y +#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y) +#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) + +#define MF_PHASE_FUNCTION glass +#define MF_MULTI_GLASS +#include "bsdf_microfacet_multi_impl.h" + +/* The diffuse phase function is not implemented as a node yet. */ +#if 0 +#define MF_PHASE_FUNCTION diffuse +#define MF_MULTI_DIFFUSE +#include "bsdf_microfacet_multi_impl.h" +#endif + +#define MF_PHASE_FUNCTION glossy +#define MF_MULTI_GLOSSY +#include "bsdf_microfacet_multi_impl.h" + +ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) +{ + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)sc; + + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); +} + +/* === Closure implementations === */ + +/* Multiscattering GGX Glossy closure */ + +ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) +{ + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->use_fresnel = use_fresnel; + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; +} + +ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) +{ + if(is_zero(bsdf->T)) + bsdf->T = make_float3(1.0f, 0.0f, 0.0f); + + return bsdf_microfacet_multi_ggx_common_setup(bsdf, use_fresnel); +} + +ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) +{ + bsdf->alpha_y = bsdf->alpha_x; + + return bsdf_microfacet_multi_ggx_common_setup(bsdf, use_fresnel); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); + float3 X, Y, Z; + Z = bsdf->N; + if(is_aniso) + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); + else + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL); +} + +ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); + float3 X, Y, Z; + Z = bsdf->N; + if(is_aniso) + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL); + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); + else + *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; +#endif + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* Multiscattering GGX Glass closure */ + +ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf, bool use_fresnel = false) +{ + bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); + bsdf->alpha_y = bsdf->alpha_x; + bsdf->ior = max(0.0f, bsdf->ior); + bsdf->extra->color.x = saturate(bsdf->extra->color.x); + bsdf->extra->color.y = saturate(bsdf->extra->color.y); + bsdf->extra->color.z = saturate(bsdf->extra->color.z); + bsdf->extra->use_fresnel = use_fresnel; + bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x); + bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y); + bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z); + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 X, Y, Z; + Z = bsdf->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior); + *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + if(localO.z*localI.z > 0.0f) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx; + *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy; +#endif + return LABEL_REFLECT|LABEL_GLOSSY; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + float cosI = dot(Z, I); + float dnp = max(sqrtf(1.0f - (bsdf->ior * bsdf->ior * (1.0f - cosI*cosI))), 1e-7f); + *domega_in_dx = -(bsdf->ior * dIdx) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z; + *domega_in_dy = -(bsdf->ior * dIdy) + ((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z; +#endif + + return LABEL_TRANSMIT|LABEL_GLOSSY; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h new file mode 100644 index 00000000000..afd4a8da62a --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* Evaluate the BSDF from wi to wo. + * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF, + * which is evaluated stochastically through a random walk. At each bounce (except for the first one), + * the amount of reflection from here towards wo is evaluated before bouncing again. + * + * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to + * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined + * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered + * energy is used. In combination with MIS, that is enough to produce an unbiased result, although + * the balance heuristic isn't necessarily optimal anymore. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint* lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ + bool swapped = false; +#ifdef MF_MULTI_GLASS + if(wi.z*wo.z < 0.0f) { + /* Glass transmission is a special case and requires the directions to change hemisphere. */ + if(-wo.z < wi.z) { + swapped = true; + float3 tmp = -wo; + wo = -wi; + wi = tmp; + } + } + else +#endif + if(wo.z < wi.z) { + swapped = true; + float3 tmp = wo; + wo = wi; + wi = tmp; + } + + if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) + return make_float3(0.0f, 0.0f, 0.0f); + + const float2 alpha = make_float2(alpha_x, alpha_y); + + float lambda_r = mf_lambda(-wi, alpha); + float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha); + + /* Analytically compute single scattering for lower noise. */ + float3 eval; +#ifdef MF_MULTI_GLASS + eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); + if(wo_outside) + eval *= -lambda_r / (shadowing_lambda - lambda_r); + else + eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); +#elif defined(MF_MULTI_DIFFUSE) + /* Diffuse has no special closed form for the single scattering bounce */ + eval = make_float3(0.0f, 0.0f, 0.0f); +#else /* MF_MULTI_GLOSSY */ + const float3 wh = normalize(wi+wo); + const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); + float val = G2 * 0.25f / wi.z; + if(alpha.x == alpha.y) + val *= D_ggx(wh, alpha.x); + else + val *= D_ggx_aniso(wh, alpha); + if(n && k) { + eval = fresnel_conductor(dot(wh, wi), *n, *k) * val; + } + else { + eval = make_float3(val, val, val); + } +#endif + + float3 wr = -wi; + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + + for(int order = 0; order < 10; order++) { + /* Sample microfacet height and normal */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) + break; + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + +#ifdef MF_MULTI_DIFFUSE + if(order == 0) { + /* Compute single-scattering for diffuse. */ + const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r); + eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm); + } +#endif + if(order > 0) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; +#ifdef MF_MULTI_GLASS + if(outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta); +#elif defined(MF_MULTI_DIFFUSE) + phase = mf_eval_phase_diffuse(wo, wm); +#else /* MF_MULTI_GLOSSY */ + phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput; +#endif + eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda); + } + if(order+1 < 10) { + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + outside = !outside; + wr = -wr; + hr = -hr; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + lambda_r = mf_lambda(wr, alpha); + + throughput *= color; + + C1_r = mf_C1(hr); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + } + + if(swapped) + eval *= fabsf(wi.z / wo.z); + return eval; +} + +/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk + * escaped the surface in wo. The function returns the throughput between wi and wo. + * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + const float2 alpha = make_float2(alpha_x, alpha_y); + + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 wr = -wi; + float lambda_r = mf_lambda(wr, alpha); + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + + int order; + for(order = 0; order < 10; order++) { + /* Sample microfacet height. */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) { + /* The random walk has left the surface. */ + *wo = outside? wr: -wr; + return throughput; + } + /* Sample microfacet normal. */ + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + + /* First-bounce color is already accounted for in mix weight. */ + if(order > 0) + throughput *= color; + + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + hr = -hr; + wr = -wr; + outside = !outside; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + /* Update random walk parameters. */ + lambda_r = mf_lambda(wr, alpha); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + *wo = make_float3(0.0f, 0.0f, 1.0f); + return make_float3(0.0f, 0.0f, 0.0f); +} + +#undef MF_MULTI_GLASS +#undef MF_MULTI_DIFFUSE +#undef MF_MULTI_GLOSSY +#undef MF_PHASE_FUNCTION diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h index 61b7cb11b02..cb342a026ef 100644 --- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h +++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h @@ -19,39 +19,59 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct OrenNayarBsdf { + SHADER_CLOSURE_BASE; + + float3 N; + float roughness; + float a; + float b; +} OrenNayarBsdf; + ccl_device float3 bsdf_oren_nayar_get_intensity(const ShaderClosure *sc, float3 n, float3 v, float3 l) { + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; float nl = max(dot(n, l), 0.0f); float nv = max(dot(n, v), 0.0f); float t = dot(l, v) - nl * nv; if(t > 0.0f) t /= max(nl, nv) + FLT_MIN; - float is = nl * (sc->data0 + sc->data1 * t); + float is = nl * (bsdf->a + bsdf->b * t); return make_float3(is, is, is); } -ccl_device int bsdf_oren_nayar_setup(ShaderClosure *sc) +ccl_device int bsdf_oren_nayar_setup(OrenNayarBsdf *bsdf) { - float sigma = sc->data0; + float sigma = bsdf->roughness; - sc->type = CLOSURE_BSDF_OREN_NAYAR_ID; + bsdf->type = CLOSURE_BSDF_OREN_NAYAR_ID; sigma = saturate(sigma); float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma); - sc->data0 = 1.0f * div; - sc->data1 = sigma * div; + bsdf->a = 1.0f * div; + bsdf->b = sigma * div; return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device bool bsdf_oren_nayar_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const OrenNayarBsdf *bsdf_a = (const OrenNayarBsdf*)a; + const OrenNayarBsdf *bsdf_b = (const OrenNayarBsdf*)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && + (bsdf_a->roughness == bsdf_b->roughness); +} + ccl_device float3 bsdf_oren_nayar_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - if(dot(sc->N, omega_in) > 0.0f) { + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; + if(dot(bsdf->N, omega_in) > 0.0f) { *pdf = 0.5f * M_1_PI_F; - return bsdf_oren_nayar_get_intensity(sc, sc->N, I, omega_in); + return bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, omega_in); } else { *pdf = 0.0f; @@ -66,15 +86,16 @@ ccl_device float3 bsdf_oren_nayar_eval_transmit(const ShaderClosure *sc, const f ccl_device int bsdf_oren_nayar_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - sample_uniform_hemisphere(sc->N, randu, randv, omega_in, pdf); + const OrenNayarBsdf *bsdf = (const OrenNayarBsdf*)sc; + sample_uniform_hemisphere(bsdf->N, randu, randv, omega_in, pdf); if(dot(Ng, *omega_in) > 0.0f) { - *eval = bsdf_oren_nayar_get_intensity(sc, sc->N, I, *omega_in); + *eval = bsdf_oren_nayar_get_intensity(sc, bsdf->N, I, *omega_in); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the bounce - *domega_in_dx = (2.0f * dot(sc->N, dIdx)) * sc->N - dIdx; - *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy; + *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif } else { diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h index 1ab15eee954..e152a8780db 100644 --- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h +++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h @@ -35,7 +35,17 @@ CCL_NAMESPACE_BEGIN -ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float3 colors[8], float pos) +#ifdef __OSL__ + +typedef ccl_addr_space struct PhongRampBsdf { + SHADER_CLOSURE_BASE; + + float3 N; + float exponent; + float3 *colors; +} PhongRampBsdf; + +ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos) { int MAXCOLORS = 8; @@ -49,57 +59,54 @@ ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float return colors[ipos] * (1.0f - offset) + colors[ipos+1] * offset; } -ccl_device int bsdf_phong_ramp_setup(ShaderClosure *sc) +ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf) { - sc->type = CLOSURE_BSDF_PHONG_RAMP_ID; - sc->data0 = max(sc->data0, 0.0f); - sc->data1 = 0.0f; + bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID; + bsdf->exponent = max(bsdf->exponent, 0.0f); return SD_BSDF|SD_BSDF_HAS_EVAL; } -ccl_device void bsdf_phong_ramp_blur(ShaderClosure *sc, float roughness) -{ -} - -ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float m_exponent = sc->data0; - float cosNI = dot(sc->N, omega_in); - float cosNO = dot(sc->N, I); + const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc; + float m_exponent = bsdf->exponent; + float cosNI = dot(bsdf->N, omega_in); + float cosNO = dot(bsdf->N, I); if(cosNI > 0 && cosNO > 0) { // reflect the view vector - float3 R = (2 * cosNO) * sc->N - I; + float3 R = (2 * cosNO) * bsdf->N - I; float cosRI = dot(R, omega_in); if(cosRI > 0) { float cosp = powf(cosRI, m_exponent); float common = 0.5f * M_1_PI_F * cosp; float out = cosNI * (m_exponent + 2) * common; *pdf = (m_exponent + 1) * common; - return bsdf_phong_ramp_get_color(sc, colors, cosp) * out; + return bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; } } return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, const float3 colors[8], const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colors[8], float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float cosNO = dot(sc->N, I); - float m_exponent = sc->data0; + const PhongRampBsdf *bsdf = (const PhongRampBsdf*)sc; + float cosNO = dot(bsdf->N, I); + float m_exponent = bsdf->exponent; if(cosNO > 0) { // reflect the view vector - float3 R = (2 * cosNO) * sc->N - I; + float3 R = (2 * cosNO) * bsdf->N - I; #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx; - *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->N - dIdy; + *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif float3 T, B; @@ -114,7 +121,7 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo if(dot(Ng, *omega_in) > 0.0f) { // common terms for pdf and eval - float cosNI = dot(sc->N, *omega_in); + float cosNI = dot(bsdf->N, *omega_in); // make sure the direction we chose is still in the right hemisphere if(cosNI > 0) { @@ -122,13 +129,14 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc, const float3 colo float common = 0.5f * M_1_PI_F * cosp; *pdf = (m_exponent + 1) * common; float out = cosNI * (m_exponent + 2) * common; - *eval = bsdf_phong_ramp_get_color(sc, colors, cosp) * out; + *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out; } } } return LABEL_REFLECT|LABEL_GLOSSY; } +#endif /* __OSL__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_reflection.h b/intern/cycles/kernel/closure/bsdf_reflection.h index 303f4c9ce34..1d21614ecee 100644 --- a/intern/cycles/kernel/closure/bsdf_reflection.h +++ b/intern/cycles/kernel/closure/bsdf_reflection.h @@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN /* REFLECTION */ -ccl_device int bsdf_reflection_setup(ShaderClosure *sc) +ccl_device int bsdf_reflection_setup(MicrofacetBsdf *bsdf) { - sc->type = CLOSURE_BSDF_REFLECTION_ID; + bsdf->type = CLOSURE_BSDF_REFLECTION_ID; return SD_BSDF; } @@ -55,7 +55,8 @@ ccl_device float3 bsdf_reflection_eval_transmit(const ShaderClosure *sc, const f ccl_device int bsdf_reflection_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float3 N = bsdf->N; // only one direction is possible float cosNO = dot(N, I); diff --git a/intern/cycles/kernel/closure/bsdf_refraction.h b/intern/cycles/kernel/closure/bsdf_refraction.h index c78a4b67134..050a4e76fa9 100644 --- a/intern/cycles/kernel/closure/bsdf_refraction.h +++ b/intern/cycles/kernel/closure/bsdf_refraction.h @@ -37,9 +37,9 @@ CCL_NAMESPACE_BEGIN /* REFRACTION */ -ccl_device int bsdf_refraction_setup(ShaderClosure *sc) +ccl_device int bsdf_refraction_setup(MicrofacetBsdf *bsdf) { - sc->type = CLOSURE_BSDF_REFRACTION_ID; + bsdf->type = CLOSURE_BSDF_REFRACTION_ID; return SD_BSDF; } @@ -55,8 +55,9 @@ ccl_device float3 bsdf_refraction_eval_transmit(const ShaderClosure *sc, const f ccl_device int bsdf_refraction_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float m_eta = sc->data0; - float3 N = sc->N; + const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; + float m_eta = bsdf->ior; + float3 N = bsdf->N; float3 R, T; #ifdef __RAY_DIFFERENTIALS__ diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h index e5b6ab93a64..28e775bcbc8 100644 --- a/intern/cycles/kernel/closure/bsdf_toon.h +++ b/intern/cycles/kernel/closure/bsdf_toon.h @@ -35,17 +35,35 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct ToonBsdf { + SHADER_CLOSURE_BASE; + + float3 N; + float size; + float smooth; +} ToonBsdf; + /* DIFFUSE TOON */ -ccl_device int bsdf_diffuse_toon_setup(ShaderClosure *sc) +ccl_device int bsdf_diffuse_toon_setup(ToonBsdf *bsdf) { - sc->type = CLOSURE_BSDF_DIFFUSE_TOON_ID; - sc->data0 = saturate(sc->data0); - sc->data1 = saturate(sc->data1); + bsdf->type = CLOSURE_BSDF_DIFFUSE_TOON_ID; + bsdf->size = saturate(bsdf->size); + bsdf->smooth = saturate(bsdf->smooth); return SD_BSDF|SD_BSDF_HAS_EVAL; } +ccl_device bool bsdf_toon_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const ToonBsdf *bsdf_a = (const ToonBsdf*)a; + const ToonBsdf *bsdf_b = (const ToonBsdf*)b; + + return (isequal_float3(bsdf_a->N, bsdf_b->N)) && + (bsdf_a->size == bsdf_b->size) && + (bsdf_a->smooth == bsdf_b->smooth); +} + ccl_device float3 bsdf_toon_get_intensity(float max_angle, float smooth, float angle) { float is; @@ -67,9 +85,10 @@ ccl_device float bsdf_toon_get_sample_angle(float max_angle, float smooth) ccl_device float3 bsdf_diffuse_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float max_angle = sc->data0*M_PI_2_F; - float smooth = sc->data1*M_PI_2_F; - float angle = safe_acosf(fmaxf(dot(sc->N, omega_in), 0.0f)); + const ToonBsdf *bsdf = (const ToonBsdf*)sc; + float max_angle = bsdf->size*M_PI_2_F; + float smooth = bsdf->smooth*M_PI_2_F; + float angle = safe_acosf(fmaxf(dot(bsdf->N, omega_in), 0.0f)); float3 eval = bsdf_toon_get_intensity(max_angle, smooth, angle); @@ -90,21 +109,22 @@ ccl_device float3 bsdf_diffuse_toon_eval_transmit(const ShaderClosure *sc, const ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float max_angle = sc->data0*M_PI_2_F; - float smooth = sc->data1*M_PI_2_F; + const ToonBsdf *bsdf = (const ToonBsdf*)sc; + float max_angle = bsdf->size*M_PI_2_F; + float smooth = bsdf->smooth*M_PI_2_F; float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); float angle = sample_angle*randu; if(sample_angle > 0.0f) { - sample_uniform_cone(sc->N, sample_angle, randu, randv, omega_in, pdf); + sample_uniform_cone(bsdf->N, sample_angle, randu, randv, omega_in, pdf); if(dot(Ng, *omega_in) > 0.0f) { *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the bounce - *domega_in_dx = (2.0f * dot(sc->N, dIdx)) * sc->N - dIdx; - *domega_in_dy = (2.0f * dot(sc->N, dIdy)) * sc->N - dIdy; + *domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif } else @@ -117,25 +137,26 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, floa /* GLOSSY TOON */ -ccl_device int bsdf_glossy_toon_setup(ShaderClosure *sc) +ccl_device int bsdf_glossy_toon_setup(ToonBsdf *bsdf) { - sc->type = CLOSURE_BSDF_GLOSSY_TOON_ID; - sc->data0 = saturate(sc->data0); - sc->data1 = saturate(sc->data1); + bsdf->type = CLOSURE_BSDF_GLOSSY_TOON_ID; + bsdf->size = saturate(bsdf->size); + bsdf->smooth = saturate(bsdf->smooth); return SD_BSDF|SD_BSDF_HAS_EVAL; } ccl_device float3 bsdf_glossy_toon_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { - float max_angle = sc->data0*M_PI_2_F; - float smooth = sc->data1*M_PI_2_F; - float cosNI = dot(sc->N, omega_in); - float cosNO = dot(sc->N, I); + const ToonBsdf *bsdf = (const ToonBsdf*)sc; + float max_angle = bsdf->size*M_PI_2_F; + float smooth = bsdf->smooth*M_PI_2_F; + float cosNI = dot(bsdf->N, omega_in); + float cosNO = dot(bsdf->N, I); if(cosNI > 0 && cosNO > 0) { /* reflect the view vector */ - float3 R = (2 * cosNO) * sc->N - I; + float3 R = (2 * cosNO) * bsdf->N - I; float cosRI = dot(R, omega_in); float angle = safe_acosf(fmaxf(cosRI, 0.0f)); @@ -157,13 +178,14 @@ ccl_device float3 bsdf_glossy_toon_eval_transmit(const ShaderClosure *sc, const ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float max_angle = sc->data0*M_PI_2_F; - float smooth = sc->data1*M_PI_2_F; - float cosNO = dot(sc->N, I); + const ToonBsdf *bsdf = (const ToonBsdf*)sc; + float max_angle = bsdf->size*M_PI_2_F; + float smooth = bsdf->smooth*M_PI_2_F; + float cosNO = dot(bsdf->N, I); if(cosNO > 0) { /* reflect the view vector */ - float3 R = (2 * cosNO) * sc->N - I; + float3 R = (2 * cosNO) * bsdf->N - I; float sample_angle = bsdf_toon_get_sample_angle(max_angle, smooth); float angle = sample_angle*randu; @@ -171,15 +193,15 @@ ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc, float3 Ng, float sample_uniform_cone(R, sample_angle, randu, randv, omega_in, pdf); if(dot(Ng, *omega_in) > 0.0f) { - float cosNI = dot(sc->N, *omega_in); + float cosNI = dot(bsdf->N, *omega_in); /* make sure the direction we chose is still in the right hemisphere */ if(cosNI > 0) { *eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle); #ifdef __RAY_DIFFERENTIALS__ - *domega_in_dx = (2 * dot(sc->N, dIdx)) * sc->N - dIdx; - *domega_in_dy = (2 * dot(sc->N, dIdy)) * sc->N - dIdy; + *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx; + *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy; #endif } else diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index f99e0c3dca7..397d642c35a 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric( return 1; // total internal reflection } else { - float dnp = sqrtf(arg); + float dnp = max(sqrtf(arg), 1e-7f); float nK = (neta * cos)- dnp; *T = -(neta * I)+(nK * Nn); #ifdef __RAY_DIFFERENTIALS__ @@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta) return 1.0f; // TIR(no refracted component) } -#if 0 ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) { - float3 cosi2 = make_float3(cosi*cosi); + float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi); float3 one = make_float3(1.0f, 1.0f, 1.0f); float3 tmp_f = eta * eta + k * k; float3 tmp = tmp_f * cosi2; @@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k (tmp_f + (2.0f * eta * cosi) + cosi2); return(Rparl2 + Rperp2) * 0.5f; } -#endif ccl_device float schlick_fresnel(float u) { diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index a1920841e6e..e31d790dd84 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -19,6 +19,19 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct Bssrdf { + SHADER_CLOSURE_BASE; + + float radius; + float sharpness; + float d; + float texture_blur; + float albedo; + float roughness; + float3 N; + float3 baseColor; +} Bssrdf; + /* Planar Truncated Gaussian * * Note how this is different from the typical gaussian, this one integrates @@ -28,11 +41,12 @@ CCL_NAMESPACE_BEGIN /* paper suggests 1/12.46 which is much too small, suspect it's *12.46 */ #define GAUSS_TRUNCATE 12.46f -ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_eval(const ShaderClosure *sc, float r) { /* integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) from 0 to Rm * = 1 - exp(-Rm*Rm/(2*v)) */ - const float v = sc->data0*sc->data0*(0.25f*0.25f); + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); if(r >= Rm) @@ -41,7 +55,7 @@ ccl_device float bssrdf_gaussian_eval(ShaderClosure *sc, float r) return expf(-r*r/(2.0f*v))/(2.0f*M_PI_F*v); } -ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r) +ccl_device float bssrdf_gaussian_pdf(const ShaderClosure *sc, float r) { /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ const float area_truncated = 1.0f - expf(-0.5f*GAUSS_TRUNCATE); @@ -49,12 +63,12 @@ ccl_device float bssrdf_gaussian_pdf(ShaderClosure *sc, float r) return bssrdf_gaussian_eval(sc, r) * (1.0f/(area_truncated)); } -ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_gaussian_sample(const ShaderClosure *sc, float xi, float *r, float *h) { /* xi = integrate (2*pi*r * exp(-r*r/(2*v)))/(2*pi*v)) = -exp(-r^2/(2*v)) * r = sqrt(-2*v*logf(xi)) */ - - const float v = sc->data0*sc->data0*(0.25f*0.25f); + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float v = bssrdf->radius*bssrdf->radius*(0.25f*0.25f); const float Rm = sqrtf(v*GAUSS_TRUNCATE); /* 1.0 - expf(-Rm*Rm/(2*v)) simplified */ @@ -75,12 +89,13 @@ ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, fl * far as I can tell has no closed form solution. So we get an iterative solution * instead with newton-raphson. */ -ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_eval(const ShaderClosure *sc, float r) { - const float sharpness = sc->T.x; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float sharpness = bssrdf->sharpness; if(sharpness == 0.0f) { - const float Rm = sc->data0; + const float Rm = bssrdf->radius; if(r >= Rm) return 0.0f; @@ -94,7 +109,7 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r) } else { - float Rm = sc->data0*(1.0f + sharpness); + float Rm = bssrdf->radius*(1.0f + sharpness); if(r >= Rm) return 0.0f; @@ -122,7 +137,7 @@ ccl_device float bssrdf_cubic_eval(ShaderClosure *sc, float r) } } -ccl_device float bssrdf_cubic_pdf(ShaderClosure *sc, float r) +ccl_device float bssrdf_cubic_pdf(const ShaderClosure *sc, float r) { return bssrdf_cubic_eval(sc, r); } @@ -155,12 +170,13 @@ ccl_device float bssrdf_cubic_quintic_root_find(float xi) return x; } -ccl_device void bssrdf_cubic_sample(ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_cubic_sample(const ShaderClosure *sc, float xi, float *r, float *h) { - float Rm = sc->data0; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float sharpness = bssrdf->sharpness; + float Rm = bssrdf->radius; float r_ = bssrdf_cubic_quintic_root_find(xi); - const float sharpness = sc->T.x; if(sharpness != 0.0f) { r_ = powf(r_, 1.0f + sharpness); Rm *= (1.0f + sharpness); @@ -198,21 +214,22 @@ ccl_device_inline float bssrdf_burley_compatible_mfp(float r) return 0.25f * M_1_PI_F * r; } -ccl_device void bssrdf_burley_setup(ShaderClosure *sc) +ccl_device void bssrdf_burley_setup(Bssrdf *bssrdf) { /* Mean free path length. */ - const float l = bssrdf_burley_compatible_mfp(sc->data0); + const float l = bssrdf_burley_compatible_mfp(bssrdf->radius); /* Surface albedo. */ - const float A = sc->data2; + const float A = bssrdf->albedo; const float s = bssrdf_burley_fitting(A); const float d = l / s; - sc->custom1 = d; + bssrdf->d = d; } -ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_eval(const ShaderClosure *sc, float r) { - const float d = sc->custom1; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; if(r >= Rm) @@ -231,7 +248,7 @@ ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r) return (exp_r_d + exp_r_3_d) / (4.0f*d); } -ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r) +ccl_device float bssrdf_burley_pdf(const ShaderClosure *sc, float r) { return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF); } @@ -276,12 +293,13 @@ ccl_device float bssrdf_burley_root_find(float xi) return r; } -ccl_device void bssrdf_burley_sample(ShaderClosure *sc, +ccl_device void bssrdf_burley_sample(const ShaderClosure *sc, float xi, float *r, float *h) { - const float d = sc->custom1; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float d = bssrdf->d; const float Rm = BURLEY_TRUNCATE * d; const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d; @@ -295,26 +313,29 @@ ccl_device void bssrdf_burley_sample(ShaderClosure *sc, * * Samples distributed over disk with no falloff, for reference. */ -ccl_device float bssrdf_none_eval(ShaderClosure *sc, float r) +ccl_device float bssrdf_none_eval(const ShaderClosure *sc, float r) { - const float Rm = sc->data0; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float Rm = bssrdf->radius; return (r < Rm)? 1.0f: 0.0f; } -ccl_device float bssrdf_none_pdf(ShaderClosure *sc, float r) +ccl_device float bssrdf_none_pdf(const ShaderClosure *sc, float r) { /* integrate (2*pi*r)/(pi*Rm*Rm) from 0 to Rm = 1 */ - const float Rm = sc->data0; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float Rm = bssrdf->radius; const float area = (M_PI_F*Rm*Rm); return bssrdf_none_eval(sc, r) / area; } -ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_none_sample(const ShaderClosure *sc, float xi, float *r, float *h) { /* xi = integrate (2*pi*r)/(pi*Rm*Rm) = r^2/Rm^2 * r = sqrt(xi)*Rm */ - const float Rm = sc->data0; + const Bssrdf *bssrdf = (const Bssrdf*)sc; + const float Rm = bssrdf->radius; const float r_ = sqrtf(xi)*Rm; *r = r_; @@ -325,40 +346,54 @@ ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float /* Generic */ -ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type) +ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) +{ + Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight); + + if(!bssrdf) + return NULL; + + float sample_weight = fabsf(average(weight)); + bssrdf->sample_weight = sample_weight; + return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL; +} + +ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type) { - if(sc->data0 < BSSRDF_MIN_RADIUS) { + if(bssrdf->radius < BSSRDF_MIN_RADIUS) { /* revert to diffuse BSDF if radius too small */ int flag; if (type == CLOSURE_BSSRDF_DISNEY_ID) { - sc->data0 = sc->data3; - sc->data1 = 0.0f; - flag = bsdf_disney_diffuse_setup(sc); - sc->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID; + DisneyDiffuseBsdf *bsdf = (DisneyDiffuseBsdf*)bssrdf; + bsdf->N = bssrdf->N; + bsdf->roughness = bssrdf->roughness; + bsdf->baseColor = bssrdf->baseColor; + flag = bsdf_disney_diffuse_setup(bsdf); + bsdf->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID; } else { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - flag = bsdf_diffuse_setup(sc); - sc->type = CLOSURE_BSDF_BSSRDF_ID; + DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf; + bsdf->N = bssrdf->N; + flag = bsdf_diffuse_setup(bsdf); + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; } return flag; } else { - sc->data1 = saturate(sc->data1); /* texture blur */ - sc->T.x = saturate(sc->T.x); /* sharpness */ - sc->type = type; + bssrdf->texture_blur = saturate(bssrdf->texture_blur); + bssrdf->sharpness = saturate(bssrdf->sharpness); + bssrdf->type = type; if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_DISNEY_ID) { - bssrdf_burley_setup(sc); + bssrdf_burley_setup(bssrdf); } return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF; } } -ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h) +ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float *h) { if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) bssrdf_cubic_sample(sc, xi, r, h); @@ -368,7 +403,7 @@ ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h) bssrdf_burley_sample(sc, xi, r, h); } -ccl_device float bssrdf_pdf(ShaderClosure *sc, float r) +ccl_device float bssrdf_pdf(const ShaderClosure *sc, float r) { if(sc->type == CLOSURE_BSSRDF_CUBIC_ID) return bssrdf_cubic_pdf(sc, r); diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h index 4d71ba50ec3..01e67c7c2fd 100644 --- a/intern/cycles/kernel/closure/volume.h +++ b/intern/cycles/kernel/closure/volume.h @@ -19,6 +19,12 @@ CCL_NAMESPACE_BEGIN +typedef ccl_addr_space struct HenyeyGreensteinVolume { + SHADER_CLOSURE_BASE; + + float g; +} HenyeyGreensteinVolume; + /* HENYEY-GREENSTEIN CLOSURE */ /* Given cosine between rays, return probability density that a photon bounces @@ -29,19 +35,28 @@ ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g) return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * (M_1_PI_F * 0.25f); }; -ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc) +ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume) { - sc->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; /* clamp anisotropy to avoid delta function */ - sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f); + volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f); return SD_SCATTER; } +ccl_device bool volume_henyey_greenstein_merge(const ShaderClosure *a, const ShaderClosure *b) +{ + const HenyeyGreensteinVolume *volume_a = (const HenyeyGreensteinVolume*)a; + const HenyeyGreensteinVolume *volume_b = (const HenyeyGreensteinVolume*)b; + + return (volume_a->g == volume_b->g); +} + ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf) { - float g = sc->data0; + const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc; + float g = volume->g; /* note that I points towards the viewer */ if(fabsf(g) < 1e-3f) { @@ -58,7 +73,8 @@ ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, c ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) { - float g = sc->data0; + const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume*)sc; + float g = volume->g; float cos_phi, sin_phi, cos_theta; /* match pdf for small g */ diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index c94a5384d1f..493afdc4f62 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -15,35 +15,14 @@ * limitations under the License. */ -/* bottom-most stack entry, indicating the end of traversal */ -#define ENTRYPOINT_SENTINEL 0x76543210 - -/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ -#define BVH_STACK_SIZE 192 -#define BVH_QSTACK_SIZE 384 -#define BVH_NODE_SIZE 4 -#define BVH_NODE_LEAF_SIZE 1 -#define BVH_QNODE_SIZE 7 -#define BVH_QNODE_LEAF_SIZE 1 -#define TRI_NODE_SIZE 3 - -/* silly workaround for float extended precision that happens when compiling - * without sse support on x86, it results in different results for float ops - * that you would otherwise expect to compare correctly */ -#if !defined(__i386__) || defined(__SSE__) -# define NO_EXTENDED_PRECISION -#else -# define NO_EXTENDED_PRECISION volatile -#endif - #include "geom_attribute.h" #include "geom_object.h" #include "geom_triangle.h" +#include "geom_subd_triangle.h" #include "geom_triangle_intersect.h" #include "geom_motion_triangle.h" #include "geom_motion_curve.h" #include "geom_curve.h" #include "geom_volume.h" #include "geom_primitive.h" -#include "geom_bvh.h" diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h index c7364e9edac..5d78cf8f9fc 100644 --- a/intern/cycles/kernel/geom/geom_attribute.h +++ b/intern/cycles/kernel/geom/geom_attribute.h @@ -25,6 +25,24 @@ CCL_NAMESPACE_BEGIN * Lookup of attributes is different between OSL and SVM, as OSL is ustring * based while for SVM we use integer ids. */ +ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd); + +ccl_device_inline uint attribute_primitive_type(KernelGlobals *kg, const ShaderData *sd) +{ +#ifdef __HAIR__ + if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { + return ATTR_PRIM_CURVE; + } + else +#endif + if(subd_triangle_patch(kg, sd) != ~0) { + return ATTR_PRIM_SUBD; + } + else { + return ATTR_PRIM_TRIANGLE; + } +} + /* Find attribute based on ID */ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) @@ -34,9 +52,7 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui /* for SVM, find attribute by unique id */ uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride; -#ifdef __HAIR__ - attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; -#endif + attr_offset += attribute_primitive_type(kg, sd); uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); while(attr_map.x != id) { diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 8894843997c..292e1bfca0e 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -450,8 +450,8 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect else if(level == 1) { /* the maximum recursion depth is reached. - * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. - * dP* is reversed if necessary.*/ + * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. + * dP* is reversed if necessary.*/ float t = isect->t; float u = 0.0f; float gd = 0.0f; diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index ffe55529110..dabba3fb1f0 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -47,13 +47,13 @@ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; } -ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3]) +ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3]) { if(step == numsteps) { /* center step: regular vertex location */ - verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + verts[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + verts[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + verts[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); } else { /* center step not store in this array */ @@ -62,19 +62,19 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 offset += step*numverts; - verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); + verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); + verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); } } -ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3]) +ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3]) { if(step == numsteps) { /* center step: regular vertex location */ - normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); - normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); - normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); + normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); + normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); } else { /* center step not stored in this array */ @@ -83,9 +83,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float offset += step*numverts; - normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); + normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); + normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); } } @@ -107,7 +107,7 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i /* fetch vertex coordinates */ float3 next_verts[3]; - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); @@ -259,7 +259,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD /* fetch vertex coordinates */ float3 verts[3], next_verts[3]; - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim))); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); @@ -387,6 +387,12 @@ ccl_device_inline void motion_triangle_intersect_subsurface( float t, u, v; if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) { + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; int hit; diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index b1b1e919e00..44734d1b70d 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -26,7 +26,10 @@ CCL_NAMESPACE_BEGIN ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) { if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) { - return triangle_attribute_float(kg, sd, elem, offset, dx, dy); + if(subd_triangle_patch(kg, sd) == ~0) + return triangle_attribute_float(kg, sd, elem, offset, dx, dy); + else + return subd_triangle_attribute_float(kg, sd, elem, offset, dx, dy); } #ifdef __HAIR__ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { @@ -48,7 +51,10 @@ ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData * ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) { if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) { - return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); + if(subd_triangle_patch(kg, sd) == ~0) + return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); + else + return subd_triangle_attribute_float3(kg, sd, elem, offset, dx, dy); } #ifdef __HAIR__ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h deleted file mode 100644 index 2a2d7822eee..00000000000 --- a/intern/cycles/kernel/geom/geom_qbvh.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2011-2014, 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. - */ - -struct QBVHStackItem { - int addr; - float dist; -}; - -/* TOOD(sergey): Investigate if using intrinsics helps for both - * stack item swap and float comparison. - */ -ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a, - QBVHStackItem *__restrict b) -{ - QBVHStackItem tmp = *a; - *a = *b; - *b = tmp; -} - -ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1, - QBVHStackItem *__restrict s2, - QBVHStackItem *__restrict s3) -{ - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } - if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } -} - -ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1, - QBVHStackItem *__restrict s2, - QBVHStackItem *__restrict s3, - QBVHStackItem *__restrict s4) -{ - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } - if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); } - if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); } - if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); } - if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } -} - -ccl_device_inline int qbvh_node_intersect(KernelGlobals *__restrict kg, - const ssef& tnear, - const ssef& tfar, -#ifdef __KERNEL_AVX2__ - const sse3f& org_idir, -#else - const sse3f& org, -#endif - const sse3f& idir, - const int near_x, - const int near_y, - const int near_z, - const int far_x, - const int far_y, - const int far_z, - const int nodeAddr, - ssef *__restrict dist) -{ - const int offset = nodeAddr*BVH_QNODE_SIZE; -#ifdef __KERNEL_AVX2__ - const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x); - const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y); - const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z); - const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x); - const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y); - const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z); -#else - const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x; - const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y; - const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z; - const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x; - const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y; - const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z; -#endif - -#ifdef __KERNEL_SSE41__ - const ssef tNear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, tnear)); - const ssef tFar = mini(mini(tfar_x, tfar_y), mini(tfar_z, tfar)); - const sseb vmask = cast(tNear) > cast(tFar); - int mask = (int)movemask(vmask)^0xf; -#else - const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear); - const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar); - const sseb vmask = tNear <= tFar; - int mask = (int)movemask(vmask); -#endif - *dist = tNear; - return mask; -} - -ccl_device_inline int qbvh_node_intersect_robust(KernelGlobals *__restrict kg, - const ssef& tnear, - const ssef& tfar, -#ifdef __KERNEL_AVX2__ - const sse3f& P_idir, -#else - const sse3f& P, -#endif - const sse3f& idir, - const int near_x, - const int near_y, - const int near_z, - const int far_x, - const int far_y, - const int far_z, - const int nodeAddr, - const float difl, - ssef *__restrict dist) -{ - const int offset = nodeAddr*BVH_QNODE_SIZE; -#ifdef __KERNEL_AVX2__ - const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x); - const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y); - const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z); - const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x); - const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y); - const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z); -#else - const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x; - const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y; - const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z; - const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x; - const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y; - const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z; -#endif - - const float round_down = 1.0f - difl; - const float round_up = 1.0f + difl; - const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear); - const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar); - const sseb vmask = round_down*tNear <= round_up*tFar; - *dist = tNear; - return (int)movemask(vmask); -} diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h deleted file mode 100644 index ce3bbbdf957..00000000000 --- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Adapted from code Copyright 2009-2010 NVIDIA Corporation, - * and code copyright 2009-2012 Intel Corporation - * - * Modifications Copyright 2011-2014, 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. - */ - -/* This is a template BVH traversal function, where various features can be - * enabled/disabled. This way we can compile optimized versions for each case - * without new features slowing things down. - * - * BVH_INSTANCING: object instancing - * BVH_HAIR: hair curve rendering - * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width - * BVH_MOTION: motion blur rendering - * - */ - -ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, - const Ray *ray, - Intersection *isect, - const uint visibility -#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) - ,uint *lcg_state, - float difl, - float extmax -#endif - ) -{ - /* TODO(sergey): - * - Test if pushing distance on the stack helps (for non shadow rays). - * - Separate version for shadow rays. - * - Likely and unlikely for if() statements. - * - Test restrict attribute for pointers. - */ - - /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; - traversalStack[0].dist = -FLT_MAX; - - /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; - float nodeDist = -FLT_MAX; - - /* Ray parameters in registers. */ - float3 P = ray->P; - float3 dir = bvh_clamp_direction(ray->D); - float3 idir = bvh_inverse_direction(dir); - int object = OBJECT_NONE; - -#if BVH_FEATURE(BVH_MOTION) - Transform ob_itfm; -#endif - -#ifndef __KERNEL_SSE41__ - if(!isfinite(P.x)) { - return false; - } -#endif - - isect->t = ray->t; - isect->u = 0.0f; - isect->v = 0.0f; - isect->prim = PRIM_NONE; - isect->object = OBJECT_NONE; - -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps = 0; - isect->num_traversed_instances = 0; -#endif - - ssef tnear(0.0f), tfar(ray->t); - sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); - -#ifdef __KERNEL_AVX2__ - float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -#endif - - /* Offsets to select the side that becomes the lower or upper bound. */ - int near_x, near_y, near_z; - int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - - /* Traversal loop. */ - do { - do { - /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - if(UNLIKELY(nodeDist > isect->t)) { - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - int traverseChild; - ssef dist; - -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif - -#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) - if(difl != 0.0f) { - /* NOTE: We extend all the child BB instead of fetching - * and checking visibility flags for each of the, - * - * Need to test if doing opposite would be any faster. - */ - traverseChild = qbvh_node_intersect_robust(kg, - tnear, - tfar, -# ifdef __KERNEL_AVX2__ - P_idir4, -# else - org, -# endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - difl, - &dist); - } - else -#endif /* BVH_HAIR_MINIMUM_WIDTH */ - { - traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, -#ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, -#endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - } - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); - - /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - float d0 = ((float*)&dist)[r]; - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); - nodeDist = d0; - continue; - } - - /* Two children are hit, push far child, and continue with - * closer child. - */ - int c0 = __float_as_int(cnodes[r]); - r = __bscf(traverseChild); - int c1 = __float_as_int(cnodes[r]); - float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { - if(d1 < d0) { - nodeAddr = c1; - nodeDist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; - continue; - } - else { - nodeAddr = c0; - nodeDist = d0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - continue; - } - } - - /* Here starts the slow path for 3 or 4 hit children. We push - * all nodes onto the stack to sort them there. - */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; - - /* Three children are hit, push all onto stack and sort 3 - * stack items, continue with closest child. - */ - r = __bscf(traverseChild); - int c2 = __float_as_int(cnodes[r]); - float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - /* Four children are hit, push all onto stack and sort 4 - * stack items, continue with closest child. - */ - r = __bscf(traverseChild); - int c3 = __float_as_int(cnodes[r]); - float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); - } - - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - } - - /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - -#ifdef __VISIBILITY_FLAG__ - if(UNLIKELY((nodeDist > isect->t) || ((__float_as_uint(leaf.z) & visibility) == 0))) -#else - if(UNLIKELY((nodeDist > isect->t))) -#endif - { - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - int primAddr = __float_as_int(leaf.x); - -#if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { -#endif - int primAddr2 = __float_as_int(leaf.y); - const uint type = __float_as_int(leaf.w); - - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - - /* Primitive intersection. */ - switch(type & PRIMITIVE_ALL) { - case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { -#if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -#endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#if BVH_FEATURE(BVH_MOTION) - case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#endif /* BVH_FEATURE(BVH_MOTION) */ -#if BVH_FEATURE(BVH_HAIR) - case PRIMITIVE_CURVE: - case PRIMITIVE_MOTION_CURVE: { - for(; primAddr < primAddr2; primAddr++) { -# if defined(__KERNEL_DEBUG__) - isect->num_traversal_steps++; -# endif - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - bool hit; - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - else - hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - if(hit) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#endif /* BVH_FEATURE(BVH_HAIR) */ - } - } -#if BVH_FEATURE(BVH_INSTANCING) - else { - /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); - -# if BVH_FEATURE(BVH_MOTION) - qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_itfm); -# else - qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist); -# endif - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - tfar = ssef(isect->t); - idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); -# ifdef __KERNEL_AVX2__ - P_idir = P*idir; - P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -# endif - triangle_intersect_precalc(dir, &isect_precalc); - - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; - traversalStack[stackPtr].dist = -FLT_MAX; - - nodeAddr = kernel_tex_fetch(__object_node, object); - -# if defined(__KERNEL_DEBUG__) - isect->num_traversed_instances++; -# endif - } - } -#endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); - -#if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { - kernel_assert(object != OBJECT_NONE); - - /* Instance pop. */ -# if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); -# else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); -# endif - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - tfar = ssef(isect->t); - idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); -# ifdef __KERNEL_AVX2__ - P_idir = P*idir; - P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -# endif - triangle_intersect_precalc(dir, &isect_precalc); - - object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - } -#endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); - - return (isect->prim != PRIM_NONE); -} diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h new file mode 100644 index 00000000000..e4597aba56e --- /dev/null +++ b/intern/cycles/kernel/geom/geom_subd_triangle.h @@ -0,0 +1,262 @@ +/* + * 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. + */ + +/* Functions for retrieving attributes on triangles produced from subdivision meshes */ + +CCL_NAMESPACE_BEGIN + +/* Patch index for triangle, -1 if not subdivision triangle */ + +ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd) +{ + return kernel_tex_fetch(__tri_patch, ccl_fetch(sd, prim)); +} + +/* UV coords of triangle within patch */ + +ccl_device_inline void subd_triangle_patch_uv(KernelGlobals *kg, const ShaderData *sd, float2 uv[3]) +{ + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + + uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x); + uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y); + uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z); +} + +/* Vertex indices of patch */ + +ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals *kg, int patch) +{ + uint4 indices; + + indices.x = kernel_tex_fetch(__patches, patch+0); + indices.y = kernel_tex_fetch(__patches, patch+1); + indices.z = kernel_tex_fetch(__patches, patch+2); + indices.w = kernel_tex_fetch(__patches, patch+3); + + return indices; +} + +/* Originating face for patch */ + +ccl_device_inline uint subd_triangle_patch_face(KernelGlobals *kg, int patch) +{ + return kernel_tex_fetch(__patches, patch+4); +} + +/* Number of corners on originating face */ + +ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals *kg, int patch) +{ + return kernel_tex_fetch(__patches, patch+5) & 0xffff; +} + +/* Indices of the four corners that are used by the patch */ + +ccl_device_inline void subd_triangle_patch_corners(KernelGlobals *kg, int patch, int corners[4]) +{ + uint4 data; + + data.x = kernel_tex_fetch(__patches, patch+4); + data.y = kernel_tex_fetch(__patches, patch+5); + data.z = kernel_tex_fetch(__patches, patch+6); + data.w = kernel_tex_fetch(__patches, patch+7); + + int num_corners = data.y & 0xffff; + + if(num_corners == 4) { + /* quad */ + corners[0] = data.z; + corners[1] = data.z+1; + corners[2] = data.z+2; + corners[3] = data.z+3; + } + else { + /* ngon */ + int c = data.y >> 16; + + corners[0] = data.z + c; + corners[1] = data.z + mod(c+1, num_corners); + corners[2] = data.w; + corners[3] = data.z + mod(c-1, num_corners); + } +} + +/* Reading attributes on various subdivision triangle elements */ + +ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + int patch = subd_triangle_patch(kg, sd); + + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return kernel_tex_fetch(__attributes_float, offset + subd_triangle_patch_face(kg, patch)); + } + else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + uint4 v = subd_triangle_patch_indices(kg, patch); + + float a, b, c; + + float f0 = kernel_tex_fetch(__attributes_float, offset + v.x); + float f1 = kernel_tex_fetch(__attributes_float, offset + v.y); + float f2 = kernel_tex_fetch(__attributes_float, offset + v.z); + float f3 = kernel_tex_fetch(__attributes_float, offset + v.w); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int corners[4]; + subd_triangle_patch_corners(kg, patch, corners); + + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + + float a, b, c; + + float f0 = kernel_tex_fetch(__attributes_float, corners[0] + offset); + float f1 = kernel_tex_fetch(__attributes_float, corners[1] + offset); + float f2 = kernel_tex_fetch(__attributes_float, corners[2] + offset); + float f3 = kernel_tex_fetch(__attributes_float, corners[3] + offset); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return 0.0f; + } +} + +ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + int patch = subd_triangle_patch(kg, sd); + + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + subd_triangle_patch_face(kg, patch))); + } + else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + uint4 v = subd_triangle_patch_indices(kg, patch); + + float3 a, b, c; + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.x)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.y)); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.z)); + float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.w)); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) { + int corners[4]; + subd_triangle_patch_corners(kg, patch, corners); + + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + + float3 a, b, c; + float3 f0, f1, f2, f3; + + if(elem == ATTR_ELEMENT_CORNER) { + f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + offset)); + f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + offset)); + f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + offset)); + f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + offset)); + } + else { + f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + offset)); + f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + offset)); + f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + offset)); + f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + offset)); + } + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h index 995dfac5b09..0c2351e1d1b 100644 --- a/intern/cycles/kernel/geom/geom_triangle.h +++ b/intern/cycles/kernel/geom/geom_triangle.h @@ -27,12 +27,11 @@ CCL_NAMESPACE_BEGIN ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + const float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + const float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); - float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); - /* return normal */ if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) return normalize(cross(v2 - v0, v1 - v0)); @@ -44,11 +43,10 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int prim, float u, float v, float3 *P, float3 *Ng, int *shader) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* compute point */ float t = 1.0f - u - v; @@ -71,11 +69,10 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3]) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); } /* Interpolate smooth vertex normal from vertices */ @@ -83,11 +80,10 @@ ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3 ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, float u, float v) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); - float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); - float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); + float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); + float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); return normalize((1.0f - u - v)*n2 + u*n0 + v*n1); } @@ -97,11 +93,10 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, flo ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_space float3 *dPdu, ccl_addr_space float3 *dPdv) { /* fetch triangle vertex coordinates */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + const float3 p0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + const float3 p1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + const float3 p2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* compute derivatives of P w.r.t. uv */ *dPdu = (p0 - p2); @@ -119,11 +114,11 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim)); } else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); - float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x)); - float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y)); - float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z)); + float f0 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.x); + float f1 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.y); + float f2 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.z); #ifdef __RAY_DIFFERENTIALS__ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2; @@ -162,11 +157,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim))); } else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); #ifdef __RAY_DIFFERENTIALS__ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2; diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index d2957ad5474..dd5328220ab 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -106,9 +106,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); @@ -159,16 +160,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility) #endif { -#ifdef __KERNEL_GPU__ - float4 a = tri_b - tri_a, b = tri_c - tri_a; - if(len_squared(make_float3(a.y*b.z - a.z*b.y, - a.z*b.x - a.x*b.z, - a.x*b.y - a.y*b.x)) == 0.0f) - { +#ifdef __KERNEL_CUDA__ + if(A == B && B == C) { return false; } #endif - /* Normalize U, V, W, and T. */ const float inv_det = 1.0f / det; isect->prim = triAddr; @@ -207,9 +203,10 @@ ccl_device_inline void triangle_intersect_subsurface( const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); @@ -258,6 +255,13 @@ ccl_device_inline void triangle_intersect_subsurface( /* Normalize U, V, W, and T. */ const float inv_det = 1.0f / det; + const float t = T * inv_det; + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; int hit; @@ -280,7 +284,7 @@ ccl_device_inline void triangle_intersect_subsurface( isect->type = PRIMITIVE_TRIANGLE; isect->u = U * inv_det; isect->v = V * inv_det; - isect->t = T * inv_det; + isect->t = t; /* Record geometric normal. */ /* TODO(sergey): Use float4_to_float3() on just an edges. */ @@ -329,17 +333,25 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg, P = P + D*t; - const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); float3 qvec = cross(tvec, edge1); float3 pvec = cross(D, edge2); - float rt = dot(edge2, qvec) / dot(edge1, pvec); - - P = P + D*rt; + float det = dot(edge1, pvec); + if(det != 0.0f) { + /* If determinant is zero it means ray lies in the plane of + * the triangle. It is possible in theory due to watertight + * nature of triangle intersection. For such cases we simply + * don't refine intersection hoping it'll go all fine. + */ + float rt = dot(edge2, qvec) / det; + P = P + D*rt; + } if(isect->object != OBJECT_NONE) { # ifdef __OBJECT_MOTION__ @@ -386,17 +398,25 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, P = P + D*t; #ifdef __INTERSECTION_REFINE__ - const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); float3 qvec = cross(tvec, edge1); float3 pvec = cross(D, edge2); - float rt = dot(edge2, qvec) / dot(edge1, pvec); - - P = P + D*rt; + float det = dot(edge1, pvec); + if(det != 0.0f) { + /* If determinant is zero it means ray lies in the plane of + * the triangle. It is possible in theory due to watertight + * nature of triangle intersection. For such cases we simply + * don't refine intersection hoping it'll go all fine. + */ + float rt = dot(edge2, qvec) / det; + P = P + D*rt; + } #endif /* __INTERSECTION_REFINE__ */ if(isect->object != OBJECT_NONE) { diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 5f5a3609ded..0e13b22bd2c 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -50,7 +50,7 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v else eval->diffuse = value; #else - *eval = value; + eval->diffuse = value; #endif } @@ -80,7 +80,7 @@ void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value) else eval->diffuse += value; #else - *eval += value; + eval->diffuse += value; #endif } @@ -98,7 +98,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) else return is_zero(eval->diffuse); #else - return is_zero(*eval); + return is_zero(eval->diffuse); #endif } @@ -117,7 +117,7 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value) else eval->diffuse *= value; #else - *eval *= value; + eval->diffuse *= value; #endif } @@ -172,7 +172,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) else L->emission = make_float3(0.0f, 0.0f, 0.0f); #else - *L = make_float3(0.0f, 0.0f, 0.0f); + L->emission = make_float3(0.0f, 0.0f, 0.0f); #endif } @@ -207,7 +207,7 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space else *throughput *= bsdf_eval->diffuse*inverse_pdf; #else - *throughput *= *bsdf_eval*inverse_pdf; + *throughput *= bsdf_eval->diffuse*inverse_pdf; #endif } @@ -225,7 +225,7 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -246,7 +246,7 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput else L->emission += throughput*bsdf*ao; #else - *L += throughput*bsdf*ao; + L->emission += throughput*bsdf*ao; #endif } @@ -277,7 +277,7 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through else L->emission += throughput*bsdf_eval->diffuse*shadow; #else - *L += throughput*(*bsdf_eval)*shadow; + L->emission += throughput*bsdf_eval->diffuse*shadow; #endif } @@ -295,7 +295,7 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -441,7 +441,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi else L_sum = L->emission; #else - L_sum = *L; + L_sum = L->emission; #endif /* Reject invalid value */ @@ -477,7 +477,7 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance L->shadow += L_sample->shadow*fac; L->mist += L_sample->mist*fac; #else - *L += *L_sample * fac; + L->emission += L_sample->emission * fac; #endif } diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 77982ee548a..9ee0b09529e 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -30,8 +30,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian Ray ray; float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - /* emission shader data memory used by various functions */ - ShaderData emission_sd; + /* emission and indirect shader data memory used by various functions */ + ShaderData emission_sd, indirect_sd; ray.P = sd->P + sd->Ng; ray.D = -sd->Ng; @@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* evaluate surface shader */ float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF); - shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* TODO, disable the closures we won't need */ @@ -94,6 +94,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian &L_sample, &throughput); kernel_path_indirect(kg, + &indirect_sd, &emission_sd, &rng, &ray, @@ -117,7 +118,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian state.ray_t = 0.0f; #endif /* compute indirect light */ - kernel_path_indirect(kg, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample); + kernel_path_indirect(kg, &indirect_sd, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample); /* sum and reset indirect light pass variables for the next samples */ path_radiance_sum_indirect(&L_sample); @@ -144,7 +145,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* sample subsurface scattering */ if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) { /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ - kernel_branched_path_subsurface_scatter(kg, sd, &emission_sd, &L_sample, &state, &rng, &ray, throughput); + kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd, + &emission_sd, &L_sample, &state, &rng, &ray, throughput); } #endif @@ -161,7 +163,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* indirect light */ kernel_branched_path_surface_indirect_light(kg, &rng, - sd, &emission_sd, throughput, 1.0f, &state, &L_sample); + sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample); } } #endif @@ -218,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg, ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, ShaderData *sd, + RNG *rng, PathState *state, float3 direct, float3 indirect, @@ -237,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, } else { /* surface color of the pass only */ - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); return kernel_bake_shader_bsdf(kg, sd, type); } } else { - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); color = kernel_bake_shader_bsdf(kg, sd, type); } @@ -334,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, case SHADER_EVAL_NORMAL: { if((sd.flag & SD_HAS_BUMP)) { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN); } /* compression: normal = (2 * color) - 1 */ @@ -348,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } case SHADER_EVAL_EMISSION: { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); out = shader_emissive_eval(kg, &sd); break; } @@ -401,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_diffuse, L.indirect_diffuse, @@ -412,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_glossy, L.indirect_glossy, @@ -423,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_transmission, L.indirect_transmission, @@ -435,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, #ifdef __SUBSURFACE__ out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_subsurface, L.indirect_subsurface, @@ -480,12 +487,10 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } /* write output */ - float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f; + const float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f; + const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; - if(sample == 0) - output[i] = make_float4(out.x, out.y, out.z, 1.0f) * output_fac; - else - output[i] += make_float4(out.x, out.y, out.z, 1.0f) * output_fac; + output[i] = (sample == 0)? scaled_result: output[i] + scaled_result; } #endif /* __BAKING__ */ diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index bb303b32705..c882b477c35 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -122,6 +122,17 @@ template<typename T> struct texture_image { return make_float4(r, r, r, 1.0f); } + ccl_always_inline float4 read(half4 r) + { + return half4_to_float4(r); + } + + ccl_always_inline float4 read(half r) + { + float f = half_to_float(r); + return make_float4(f, f, f, 1.0f); + } + ccl_always_inline int wrap_periodic(int x, int width) { x %= width; @@ -486,8 +497,10 @@ typedef texture<uint4> texture_uint4; typedef texture<uchar4> texture_uchar4; typedef texture_image<float> texture_image_float; typedef texture_image<uchar> texture_image_uchar; +typedef texture_image<half> texture_image_half; typedef texture_image<float4> texture_image_float4; typedef texture_image<uchar4> texture_image_uchar4; +typedef texture_image<half4> texture_image_half4; /* Macros to handle different memory storage on different devices */ diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index 42314756f02..08f6f457805 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -42,6 +42,7 @@ #define ccl_constant #define ccl_may_alias #define ccl_addr_space +#define ccl_restrict __restrict__ /* No assert supported for CUDA */ diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index a5708448e23..8505cb85576 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -39,6 +39,7 @@ #define ccl_global __global #define ccl_local __local #define ccl_private __private +#define ccl_restrict restrict #ifdef __SPLIT_KERNEL__ # define ccl_addr_space __global diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 4de8e0f698a..149ac3ed4f9 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, /* no path flag, we're evaluating this for all closures. that's weak but * we'd have to do multiple evaluations otherwise */ path_state_modify_bounce(state, true); - shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); path_state_modify_bounce(state, false); /* evaluate emissive closure */ @@ -124,8 +124,10 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, #ifdef __PASSES__ /* use visibility flag to skip lights */ if(ls->shader & SHADER_EXCLUDE_ANY) { - if(ls->shader & SHADER_EXCLUDE_DIFFUSE) + if(ls->shader & SHADER_EXCLUDE_DIFFUSE) { eval->diffuse = make_float3(0.0f, 0.0f, 0.0f); + eval->subsurface = make_float3(0.0f, 0.0f, 0.0f); + } if(ls->shader & SHADER_EXCLUDE_GLOSSY) eval->glossy = make_float3(0.0f, 0.0f, 0.0f); if(ls->shader & SHADER_EXCLUDE_TRANSMIT) diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index 7e6cdf93fb9..8e66a3a0340 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -35,10 +35,12 @@ struct Intersection; struct VolumeStep; typedef struct KernelGlobals { - texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_IMAGES_CPU]; - texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_IMAGES_CPU]; - texture_image_float texture_float_images[TEX_NUM_FLOAT_IMAGES_CPU]; - texture_image_uchar texture_byte_images[TEX_NUM_BYTE_IMAGES_CPU]; + texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU]; + texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU]; + texture_image_half4 texture_half4_images[TEX_NUM_HALF4_CPU]; + texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU]; + texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU]; + texture_image_half texture_half_images[TEX_NUM_HALF_CPU]; # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 675eacfc5ee..93c4bd3f7d5 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -51,8 +51,8 @@ ccl_device float area_light_sample(float3 P, bool sample_coord) { /* In our name system we're using P for the center, - * which is o in the paper. - */ + * which is o in the paper. + */ float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f; float axisu_len, axisv_len; @@ -291,24 +291,13 @@ ccl_device float background_portal_pdf(KernelGlobals *kg, } num_possible++; - float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir); - if(t <= 1e-4f) { - /* Either behind the portal or too close. */ - continue; - } - float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1); float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2); float3 axisu = make_float3(data1.y, data1.z, data1.w); float3 axisv = make_float3(data2.y, data2.z, data2.w); - float3 hit = P + t*direction; - float3 inplane = hit - lightpos; - /* Skip if the the ray doesn't pass through portal. */ - if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f) - continue; - if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f) + if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL)) continue; portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); @@ -729,8 +718,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float3 light_P = make_float3(data0.y, data0.z, data0.w); - if(!ray_quad_intersect(P, D, t, - light_P, axisu, axisv, &ls->P, &ls->t)) + if(!ray_quad_intersect(P, D, 0.0f, t, + light_P, axisu, axisv, Ng, &ls->P, &ls->t)) { return false; } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 5527d8aa861..d5b31037723 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -25,6 +25,7 @@ #include "kernel_camera.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_accumulate.h" #include "kernel_shader.h" @@ -53,6 +54,7 @@ CCL_NAMESPACE_BEGIN ccl_device void kernel_path_indirect(KernelGlobals *kg, + ShaderData *sd, ShaderData *emission_sd, RNG *rng, Ray *ray, @@ -61,9 +63,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, PathState *state, PathRadiance *L) { - /* shader data memory used for both volumes and surfaces, saves stack space */ - ShaderData sd; - /* path iteration */ for(;;) { /* intersect scene */ @@ -121,12 +120,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, VolumeSegment volume_segment; shader_setup_from_volume(kg, - &sd, + sd, &volume_ray); kernel_volume_decoupled_record(kg, state, &volume_ray, - &sd, + sd, &volume_segment, heterogeneous); @@ -149,7 +148,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* direct light sampling */ kernel_branched_path_volume_connect_light(kg, rng, - &sd, + sd, emission_sd, throughput, state, @@ -167,7 +166,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, result = kernel_volume_decoupled_scatter(kg, state, &volume_ray, - &sd, + sd, &throughput, rphase, rscatter, @@ -182,7 +181,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, if(result == VOLUME_PATH_SCATTERED) { if(kernel_path_volume_bounce(kg, rng, - &sd, + sd, &throughput, state, L, @@ -203,14 +202,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, &sd, &volume_ray, L, &throughput, rng, heterogeneous); + kg, state, sd, &volume_ray, L, &throughput, rng, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ kernel_path_volume_connect_light(kg, rng, - &sd, + sd, emission_sd, throughput, state, @@ -219,7 +218,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* indirect light bounce */ if(kernel_path_volume_bounce(kg, rng, - &sd, + sd, &throughput, state, L, @@ -251,13 +250,13 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, - &sd, + sd, &isect, ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ - shader_merge_closures(&sd); + shader_merge_closures(sd); #endif /* blurring of bsdf after bounces, for rays that have a small likelihood @@ -267,15 +266,15 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, if(blur_pdf < 1.0f) { float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f; - shader_bsdf_blur(kg, &sd, blur_roughness); + shader_bsdf_blur(kg, sd, blur_roughness); } } #ifdef __EMISSION__ /* emission */ - if(sd.flag & SD_EMISSION) { + if(sd->flag & SD_EMISSION) { float3 emission = indirect_primitive_emission(kg, - &sd, + sd, isect.t, state->flag, state->ray_pdf); @@ -305,30 +304,30 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { float bsdf_u, bsdf_v; path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; - float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N); + float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N); float3 ao_D; float ao_pdf; float3 ao_alpha = make_float3(0.0f, 0.0f, 0.0f); sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); - if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { + if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { Ray light_ray; float3 ao_shadow; - light_ray.P = ray_offset(sd.P, sd.Ng); + light_ray.P = ray_offset(sd->P, sd->Ng); light_ray.D = ao_D; light_ray.t = kernel_data.background.ao_distance; # ifdef __OBJECT_MOTION__ - light_ray.time = sd.time; + light_ray.time = sd->time; # endif - light_ray.dP = sd.dP; + light_ray.dP = sd->dP; light_ray.dD = differential3_zero(); if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { @@ -346,9 +345,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object, replacing * the closures with a diffuse BSDF */ - if(sd.flag & SD_BSSRDF) { + if(sd->flag & SD_BSSRDF) { float bssrdf_probability; - ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability); + ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability); /* modify throughput for picking bssrdf or bsdf */ throughput *= bssrdf_probability; @@ -364,7 +363,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v); subsurface_scatter_step(kg, - &sd, + sd, state, state->flag, sc, @@ -380,7 +379,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, int all = kernel_data.integrator.sample_all_lights_indirect; kernel_branched_path_surface_connect_light(kg, rng, - &sd, + sd, emission_sd, state, throughput, @@ -390,7 +389,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, } #endif - if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray)) + if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray)) break; } } @@ -793,7 +792,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ #ifdef __HOLDOUT__ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index b4dee220aa5..56516967d8f 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -64,8 +64,8 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, /* bounce off surface and integrate indirect light */ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg, - RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, - float num_samples_adjust, PathState *state, PathRadiance *L) + RNG *rng, ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd, + float3 throughput, float num_samples_adjust, PathState *state, PathRadiance *L) { for(int i = 0; i < ccl_fetch(sd, num_closure); i++) { const ShaderClosure *sc = &ccl_fetch(sd, closure)[i]; @@ -112,6 +112,7 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba } kernel_path_indirect(kg, + indirect_sd, emission_sd, rng, &bsdf_ray, @@ -131,6 +132,7 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba #ifdef __SUBSURFACE__ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, + ShaderData *indirect_sd, ShaderData *emission_sd, PathRadiance *L, PathState *state, @@ -222,6 +224,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, kg, rng, &bssrdf_sd, + indirect_sd, emission_sd, throughput, num_samples_inv, @@ -244,8 +247,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* shader data memory used for both volumes and surfaces, saves stack space */ ShaderData sd; - /* shader data used by emission, shadows, volume stacks */ - ShaderData emission_sd; + /* shader data used by emission, shadows, volume stacks, indirect path */ + ShaderData emission_sd, indirect_sd; PathState state; path_state_init(kg, &emission_sd, &state, rng, sample, &ray); @@ -356,6 +359,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in &pray)) { kernel_path_indirect(kg, + &indirect_sd, &emission_sd, rng, &pray, @@ -413,6 +417,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in &pray)) { kernel_path_indirect(kg, + &indirect_sd, &emission_sd, rng, &pray, @@ -458,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); - shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); shader_merge_closures(&sd); /* holdout */ @@ -522,8 +527,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object */ if(sd.flag & SD_BSSRDF) { - kernel_branched_path_subsurface_scatter(kg, &sd, &emission_sd, &L, &state, - rng, &ray, throughput); + kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd, + &L, &state, rng, &ray, throughput); } #endif @@ -541,7 +546,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* indirect light */ kernel_branched_path_surface_indirect_light(kg, rng, - &sd, &emission_sd, throughput, 1.0f, &hit_state, &L); + &sd, &indirect_sd, &emission_sd, throughput, 1.0f, &hit_state, &L); /* continue in case of transparency */ throughput *= shader_bsdf_transparency(kg, &sd); diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 631a2cb75de..731dc0407c5 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -314,5 +314,21 @@ ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scr return lcg_init(*rng + state->rng_offset + state->sample*scramble); } +/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */ + +ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng, + const ccl_addr_space PathState *state, + uint scramble) +{ + return lcg_init(*rng + state->rng_offset + state->sample*scramble); +} + +ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) +{ + /* implicit mod 2^32 */ + *rng = (1103515245*(*rng) + 12345); + return (float)*rng * (1.0f/(float)0xFFFFFFFF); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a0b56118ab7..b7641c37d93 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -24,6 +24,7 @@ * */ +#include "closure/alloc.h" #include "closure/bsdf_util.h" #include "closure/bsdf.h" #include "closure/emissive.h" @@ -453,21 +454,11 @@ ccl_device void shader_merge_closures(ShaderData *sd) for(int j = i + 1; j < sd->num_closure; j++) { ShaderClosure *scj = &sd->closure[j]; -#ifdef __OSL__ - if(sci->prim || scj->prim) + if(sci->type != scj->type) continue; -#endif - - if(!(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1 && sci->data2 == scj->data2)) + if(!bsdf_merge(sci, scj)) continue; - if(CLOSURE_IS_BSDF_OR_BSSRDF(sci->type)) { - if(sci->N != scj->N) - continue; - else if(CLOSURE_IS_BSDF_ANISOTROPIC(sci->type) && sci->T != scj->T) - continue; - } - sci->weight += scj->weight; sci->sample_weight += scj->sample_weight; @@ -488,7 +479,7 @@ ccl_device void shader_merge_closures(ShaderData *sd) /* BSDF */ -ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf, +ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf, int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) { /* this is the veach one-sample model with balance heuristic, some pdf @@ -517,7 +508,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa #ifdef __BRANCHED_PATH__ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, - const ShaderData *sd, + ShaderData *sd, const float3 omega_in, BsdfEval *result_eval, float light_pdf, @@ -563,7 +554,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg, } } -ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -620,7 +611,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, return label; } -ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -738,8 +729,9 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac ShaderClosure *sc = ccl_fetch_array(sd, closure, i); if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) { + const DiffuseBsdf *bsdf = (const DiffuseBsdf*)sc; eval += sc->weight*ao_factor; - N += sc->N*average(sc->weight); + N += bsdf->N*average(sc->weight); } else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) { eval += sc->weight; @@ -756,6 +748,7 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac return eval; } +#ifdef __SUBSURFACE__ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_blur_) { float3 eval = make_float3(0.0f, 0.0f, 0.0f); @@ -766,11 +759,12 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b ShaderClosure *sc = ccl_fetch_array(sd, closure, i); if(CLOSURE_IS_BSSRDF(sc->type)) { + const Bssrdf *bssrdf = (const Bssrdf*)sc; float avg_weight = fabsf(average(sc->weight)); - N += sc->N*avg_weight; + N += bssrdf->N*avg_weight; eval += sc->weight; - texture_blur += sc->data1*avg_weight; + texture_blur += bssrdf->texture_blur*avg_weight; weight_sum += avg_weight; } } @@ -783,6 +777,7 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b return eval; } +#endif /* Emission */ @@ -824,10 +819,11 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; + ccl_fetch(sd, num_closure_extra) = 0; ccl_fetch(sd, randb_closure) = randb; #ifdef __OSL__ @@ -846,6 +842,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0)); #endif } + + if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) { + ccl_fetch(sd, lcg_state) = lcg_state_init_addrspace(rng, state, 0xb4bc3953); + } } /* Background Evaluation */ @@ -854,33 +854,33 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, int path_flag, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; + ccl_fetch(sd, num_closure_extra) = 0; ccl_fetch(sd, randb_closure) = 0.0f; +#ifdef __SVM__ #ifdef __OSL__ if(kg->osl) { - return OSLShader::eval_background(kg, sd, state, path_flag, ctx); + OSLShader::eval_background(kg, sd, state, path_flag, ctx); } else #endif - { -#ifdef __SVM__ svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag); + } - float3 eval = make_float3(0.0f, 0.0f, 0.0f); + float3 eval = make_float3(0.0f, 0.0f, 0.0f); - for(int i = 0; i < ccl_fetch(sd, num_closure); i++) { - const ShaderClosure *sc = ccl_fetch_array(sd, closure, i); + for(int i = 0; i < ccl_fetch(sd, num_closure); i++) { + const ShaderClosure *sc = ccl_fetch_array(sd, closure, i); - if(CLOSURE_IS_BACKGROUND(sc->type)) - eval += sc->weight; - } + if(CLOSURE_IS_BACKGROUND(sc->type)) + eval += sc->weight; + } - return eval; + return eval; #else - return make_float3(0.8f, 0.8f, 0.8f); + return make_float3(0.8f, 0.8f, 0.8f); #endif - } } /* Volume */ @@ -997,6 +997,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd, /* reset closures once at the start, we will be accumulating the closures * for all volumes in the stack into a single array of closures */ sd->num_closure = 0; + sd->num_closure_extra = 0; sd->flag = 0; for(int i = 0; stack[i].shader != SHADER_NONE; i++) { @@ -1044,6 +1045,7 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd, ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; + ccl_fetch(sd, num_closure_extra) = 0; ccl_fetch(sd, randb_closure) = 0.0f; /* this will modify sd->P */ diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 1abbbb2ddad..db2fc84834a 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -117,7 +117,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, /* attenuation from transparent surface */ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); @@ -252,7 +252,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, /* attenuation from transparent surface */ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index f64b3472739..888df7f06fd 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -136,38 +136,42 @@ ccl_device float3 subsurface_scatter_eval(ShaderData *sd, ShaderClosure *sc, flo } /* replace closures with a single diffuse bsdf closure after scatter step */ -ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weight, bool hit, float3 N) +ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, ShaderClosure *sc, float3 weight, bool hit, float3 N) { sd->flag &= ~SD_CLOSURE_FLAGS; sd->randb_closure = 0.0f; + sd->num_closure = 0; + sd->num_closure_extra = 0; if(hit) { - ShaderClosure *sc = &sd->closure[0]; - sd->num_closure = 1; - - sc->weight = weight; - sc->sample_weight = 1.0f; - sc->N = N; - if (sc->type == CLOSURE_BSSRDF_DISNEY_ID) { - sc->data0 = sc->data3; - sd->flag |= bsdf_disney_diffuse_setup(sc); - - /* replace CLOSURE_BSDF_DISNEY_DIFFUSE_ID with this special ID so render passes - * can recognize it as not being a regular Disney diffuse closure */ - sc->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID; + Bssrdf *bssrdf = (Bssrdf *)sc; + if (bssrdf->type == CLOSURE_BSSRDF_DISNEY_ID) { + DisneyDiffuseBsdf *bsdf = (DisneyDiffuseBsdf*)bsdf_alloc(sd, sizeof(DisneyDiffuseBsdf), weight); + + if (bsdf) { + bsdf->N = N; + bsdf->roughness = bssrdf->roughness; + bsdf->baseColor = bssrdf->baseColor; + sd->flag |= bsdf_disney_diffuse_setup(bsdf); + + /* replace CLOSURE_BSDF_DISNEY_DIFFUSE_ID with this special ID so render passes + * can recognize it as not being a regular Disney diffuse closure */ + bsdf->type = CLOSURE_BSDF_BSSRDF_DISNEY_ID; + } } else { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sd->flag |= bsdf_diffuse_setup(sc); + DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight); + + if (bsdf) { + bsdf->N = N; + sd->flag |= bsdf_diffuse_setup(bsdf); - /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes - * can recognize it as not being a regular diffuse closure */ - sc->type = CLOSURE_BSDF_BSSRDF_ID; + /* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes + * can recognize it as not being a regular diffuse closure */ + bsdf->type = CLOSURE_BSDF_BSSRDF_ID; + } } } - else - sd->num_closure = 0; } /* optionally do blurring of color and/or bump mapping, at the cost of a shader evaluation */ @@ -208,7 +212,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, if(bump || texture_blur > 0.0f) { /* average color and normal at incoming point */ - shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); + shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL); /* we simply divide out the average color and multiply with the average @@ -377,7 +381,7 @@ ccl_device void subsurface_scatter_multi_setup(KernelGlobals *kg, subsurface_color_bump_blur(kg, sd, state, state_flag, &weight, &N); /* Setup diffuse BSDF. */ - subsurface_scatter_setup_diffuse_bsdf(sd, weight, true, N); + subsurface_scatter_setup_diffuse_bsdf(sd, sc, weight, true, N); } /* subsurface scattering step, from a point on the surface to another nearby point on the same object */ @@ -467,7 +471,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, PathS subsurface_color_bump_blur(kg, sd, state, state_flag, &eval, &N); /* setup diffuse bsdf */ - subsurface_scatter_setup_diffuse_bsdf(sd, eval, (ss_isect.num_hits > 0), N); + subsurface_scatter_setup_diffuse_bsdf(sd, sc, eval, (ss_isect.num_hits > 0), N); } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 245d236ff97..7d6fec02331 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -25,7 +25,8 @@ /* bvh */ KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes) -KERNEL_TEX(float4, texture_float4, __tri_storage) +KERNEL_TEX(float4, texture_float4, __prim_tri_verts) +KERNEL_TEX(uint, texture_uint, __prim_tri_index) KERNEL_TEX(uint, texture_uint, __prim_type) KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) @@ -39,13 +40,17 @@ KERNEL_TEX(float4, texture_float4, __objects_vector) /* triangles */ KERNEL_TEX(uint, texture_uint, __tri_shader) KERNEL_TEX(float4, texture_float4, __tri_vnormal) -KERNEL_TEX(float4, texture_float4, __tri_vindex) -KERNEL_TEX(float4, texture_float4, __tri_verts) +KERNEL_TEX(uint4, texture_uint4, __tri_vindex) +KERNEL_TEX(uint, texture_uint, __tri_patch) +KERNEL_TEX(float2, texture_float2, __tri_patch_uv) /* curves */ KERNEL_TEX(float4, texture_float4, __curves) KERNEL_TEX(float4, texture_float4, __curve_keys) +/* patches */ +KERNEL_TEX(uint, texture_uint, __patches) + /* attributes */ KERNEL_TEX(uint4, texture_uint4, __attributes_map) KERNEL_TEX(float, texture_float, __attributes_float) @@ -173,9 +178,6 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_086) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_087) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_088) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_089) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_090) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_091) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_092) # else /* bindless textures */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index df5e5d803fa..18b5c35c768 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -121,9 +121,7 @@ CCL_NAMESPACE_BEGIN # define __OBJECT_MOTION__ # define __HAIR__ # define __BAKING__ -# ifdef __KERNEL_EXPERIMENTAL__ -# define __TRANSPARENT_SHADOWS__ -# endif +# define __TRANSPARENT_SHADOWS__ # endif /* __KERNEL_OPENCL_AMD__ */ # ifdef __KERNEL_OPENCL_INTEL_CPU__ @@ -294,12 +292,14 @@ enum PathRayFlag { PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */ PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */ - /* note that these can use maximum 12 bits, the other are for layers */ - PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024), + /* Special flag to tag unaligned BVH nodes. */ + PATH_RAY_NODE_UNALIGNED = 2048, + + PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024|2048), - PATH_RAY_MIS_SKIP = 2048, - PATH_RAY_DIFFUSE_ANCESTOR = 4096, - PATH_RAY_SINGLE_PASS_DONE = 8192, + PATH_RAY_MIS_SKIP = 4096, + PATH_RAY_DIFFUSE_ANCESTOR = 8192, + PATH_RAY_SINGLE_PASS_DONE = 16384, }; /* Closure Label */ @@ -387,12 +387,13 @@ typedef enum BakePassFilterCombos { BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE), } BakePassFilterCombos; -#ifdef __PASSES__ - typedef ccl_addr_space struct PathRadiance { +#ifdef __PASSES__ int use_light_pass; +#endif float3 emission; +#ifdef __PASSES__ float3 background; float3 ao; @@ -426,25 +427,23 @@ typedef ccl_addr_space struct PathRadiance { float4 shadow; float mist; +#endif } 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; -} BsdfEval; - -#else - -typedef ccl_addr_space float3 PathRadiance; -typedef float3 BsdfEval; - #endif +} BsdfEval; /* Shader Flag */ @@ -574,8 +573,13 @@ typedef enum PrimitiveType { /* Attributes */ -#define ATTR_PRIM_TYPES 2 -#define ATTR_PRIM_CURVE 1 +typedef enum AttributePrimitive { + ATTR_PRIM_TRIANGLE = 0, + ATTR_PRIM_CURVE, + ATTR_PRIM_SUBD, + + ATTR_PRIM_TYPES +} AttributePrimitive; typedef enum AttributeElement { ATTR_ELEMENT_NONE, @@ -632,37 +636,30 @@ typedef enum AttributeStandard { # define MAX_CLOSURE 1 #endif -/* This struct is to be 16 bytes aligned, we also keep some extra precautions: - * - All the float3 members are in the beginning of the struct, so compiler - * does not put own padding trying to align this members. - * - We make sure OSL pointer is also 16 bytes aligned. - */ +/* 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(). + * + * float3 is 12 bytes on CUDA and 16 bytes on CPU/OpenCL, we set the data + * size to ensure ShaderClosure is 80 bytes total everywhere. */ + +#define SHADER_CLOSURE_BASE \ + float3 weight; \ + ClosureType type; \ + float sample_weight \ + typedef ccl_addr_space struct ShaderClosure { - float3 weight; - float3 N; - float3 T; - - float3 color0; - - ClosureType type; - float sample_weight; - float data0; - float data1; - float data2; - float data3; - float data4; - - /* Following fields could be used to store pre-calculated - * values by various BSDF closures for more effective sampling - * and evaluation. - */ - float custom1; - float custom2; - float custom3; - float3 custom_color0; + SHADER_CLOSURE_BASE; -#ifdef __OSL__ - void *prim, *pad4; + /* pad to 80 bytes, data types are aligned to own size */ +#ifdef __KERNEL_CUDA__ + float data[15]; +#else + float data[14]; #endif } ShaderClosure; @@ -687,31 +684,33 @@ typedef enum ShaderContext { enum ShaderDataFlag { /* runtime flags */ - SD_BACKFACING = (1 << 0), /* backside of surface? */ - SD_EMISSION = (1 << 1), /* have emissive closure? */ - SD_BSDF = (1 << 2), /* have bsdf closure? */ - SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ - SD_BSSRDF = (1 << 4), /* have bssrdf */ - SD_HOLDOUT = (1 << 5), /* have holdout closure? */ - SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ - SD_SCATTER = (1 << 7), /* have volume phase closure? */ - SD_AO = (1 << 8), /* have ao closure? */ - SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BACKFACING = (1 << 0), /* backside of surface? */ + SD_EMISSION = (1 << 1), /* have emissive closure? */ + SD_BSDF = (1 << 2), /* have bsdf closure? */ + SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ + SD_BSSRDF = (1 << 4), /* have bssrdf */ + SD_HOLDOUT = (1 << 5), /* have holdout closure? */ + SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ + SD_SCATTER = (1 << 7), /* have volume phase closure? */ + SD_AO = (1 << 8), /* have ao closure? */ + SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BSDF_NEEDS_LCG = (1 << 10), SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF| - SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO), + SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO| + SD_BSDF_NEEDS_LCG), /* shader flags */ - SD_USE_MIS = (1 << 10), /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */ - SD_HAS_VOLUME = (1 << 12), /* has volume shader */ - SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */ - SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */ - SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */ - SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */ - SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */ - SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */ - SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */ + SD_USE_MIS = (1 << 12), /* direct light sample */ + SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */ + SD_HAS_VOLUME = (1 << 14), /* has volume shader */ + SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */ + SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */ + SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */ + SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */ + SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */ + SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */ + SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */ SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME| SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME| @@ -719,104 +718,110 @@ enum ShaderDataFlag { SD_VOLUME_CUBIC|SD_HAS_BUMP), /* object flags */ - SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */ - SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */ - SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */ + SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */ + SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */ + SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */ + SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */ + SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED| SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| SD_OBJECT_INTERSECTS_VOLUME) }; -struct KernelGlobals; - #ifdef __SPLIT_KERNEL__ # define SD_THREAD (get_global_id(1) * get_global_size(0) + get_global_id(0)) # if defined(__SPLIT_KERNEL_AOS__) /* ShaderData is stored as an Array-of-Structures */ -# define ccl_fetch(s, t) (s[SD_THREAD].t) -# define ccl_fetch_array(s, t, index) (&s[SD_THREAD].t[index]) +# define ccl_soa_member(type, name) type soa_##name; +# define ccl_fetch(s, t) (s[SD_THREAD].soa_##t) +# define ccl_fetch_array(s, t, index) (&s[SD_THREAD].soa_##t[index]) # else /* ShaderData is stored as an Structure-of-Arrays */ # define SD_GLOBAL_SIZE (get_global_size(0) * get_global_size(1)) # define SD_FIELD_SIZE(t) sizeof(((struct ShaderData*)0)->t) # define SD_OFFSETOF(t) ((char*)(&((struct ShaderData*)0)->t) - (char*)0) -# define ccl_fetch(s, t) (((ShaderData*)((ccl_addr_space char*)s + SD_GLOBAL_SIZE * SD_OFFSETOF(t) + SD_FIELD_SIZE(t) * SD_THREAD - SD_OFFSETOF(t)))->t) +# define ccl_soa_member(type, name) type soa_##name; +# define ccl_fetch(s, t) (((ShaderData*)((ccl_addr_space char*)s + SD_GLOBAL_SIZE * SD_OFFSETOF(soa_##t) + SD_FIELD_SIZE(soa_##t) * SD_THREAD - SD_OFFSETOF(soa_##t)))->soa_##t) # define ccl_fetch_array(s, t, index) (&ccl_fetch(s, t)[index]) # endif #else +# define ccl_soa_member(type, name) type name # define ccl_fetch(s, t) (s->t) # define ccl_fetch_array(s, t, index) (&s->t[index]) #endif typedef ccl_addr_space struct ShaderData { /* position */ - float3 P; + ccl_soa_member(float3, P); /* smooth normal for shading */ - float3 N; + ccl_soa_member(float3, N); /* true geometric normal */ - float3 Ng; + ccl_soa_member(float3, Ng); /* view/incoming direction */ - float3 I; + ccl_soa_member(float3, I); /* shader id */ - int shader; + ccl_soa_member(int, shader); /* booleans describing shader, see ShaderDataFlag */ - int flag; + ccl_soa_member(int, flag); /* primitive id if there is one, ~0 otherwise */ - int prim; + ccl_soa_member(int, prim); /* combined type and curve segment for hair */ - int type; + ccl_soa_member(int, type); /* parametric coordinates - * - barycentric weights for triangles */ - float u; - float v; + * - barycentric weights for triangles */ + ccl_soa_member(float, u); + ccl_soa_member(float, v); /* object id if there is one, ~0 otherwise */ - int object; + ccl_soa_member(int, object); /* motion blur sample time */ - float time; + ccl_soa_member(float, time); /* length of the ray being shaded */ - float ray_length; + ccl_soa_member(float, ray_length); #ifdef __RAY_DIFFERENTIALS__ /* differential of P. these are orthogonal to Ng, not N */ - differential3 dP; + ccl_soa_member(differential3, dP); /* differential of I */ - differential3 dI; + ccl_soa_member(differential3, dI); /* differential of u, v */ - differential du; - differential dv; + ccl_soa_member(differential, du); + ccl_soa_member(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; + * not readily suitable as a tangent for shading on triangles. */ + ccl_soa_member(float3, dPdu); + ccl_soa_member(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; + * re-interpolating them constantly for shading */ + ccl_soa_member(Transform, ob_tfm); + ccl_soa_member(Transform, ob_itfm); #endif /* Closure data, we store a fixed array of closures */ - struct ShaderClosure closure[MAX_CLOSURE]; - int num_closure; - float randb_closure; + ccl_soa_member(struct ShaderClosure, closure[MAX_CLOSURE]); + ccl_soa_member(int, num_closure); + ccl_soa_member(int, num_closure_extra); + ccl_soa_member(float, randb_closure); + ccl_soa_member(float3, svm_closure_weight); + + /* LCG state for closures that require additional random numbers. */ + ccl_soa_member(uint, lcg_state); /* ray start position, only set for backgrounds */ - float3 ray_P; - differential3 ray_dP; + ccl_soa_member(float3, ray_P); + ccl_soa_member(differential3, ray_dP); #ifdef __OSL__ struct KernelGlobals * osl_globals; @@ -1173,11 +1178,11 @@ typedef ccl_addr_space struct DebugData { #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 1 - Active rays + * Queue 2 - Background queue + * Queue 3 - Shadow ray cast kernel - AO + * Queeu 4 - Shadow ray cast kernel - direct lighting + */ #define NUM_QUEUES 4 /* Queue names */ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index e1ea60f372e..01c87e6d89d 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -276,7 +276,7 @@ ccl_device float kernel_volume_distance_sample(float max_t, float3 sigma_t, int float sample_t = min(max_t, -logf(1.0f - xi*(1.0f - sample_transmittance))/sample_sigma_t); *transmittance = volume_color_transmittance(sigma_t, sample_t); - *pdf = (sigma_t * *transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); + *pdf = safe_divide_color(sigma_t * *transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); /* todo: optimization: when taken together with hit/miss decision, * the full_transmittance cancels out drops out and xi does not @@ -290,7 +290,7 @@ ccl_device float3 kernel_volume_distance_pdf(float max_t, float3 sigma_t, float float3 full_transmittance = volume_color_transmittance(sigma_t, max_t); float3 transmittance = volume_color_transmittance(sigma_t, sample_t); - return (sigma_t * transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); + return safe_divide_color(sigma_t * transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); } /* Emission */ @@ -625,11 +625,13 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta const int global_max_steps = kernel_data.integrator.volume_max_steps; step_size = kernel_data.integrator.volume_step_size; /* compute exact steps in advance for malloc */ - max_steps = max((int)ceilf(ray->t/step_size), 1); - if(max_steps > global_max_steps) { + if(ray->t > global_max_steps*step_size) { max_steps = global_max_steps; step_size = ray->t / (float)max_steps; } + else { + max_steps = max((int)ceilf(ray->t/step_size), 1); + } #ifdef __KERNEL_CPU__ /* NOTE: For the branched path tracing it's possible to have direct * and indirect light integration both having volume segments allocated. @@ -1027,7 +1029,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg, int stack_index = 0, enclosed_index = 0; #ifdef __VOLUME_RECORD_ALL__ - Intersection hits[2*VOLUME_STACK_SIZE]; + Intersection hits[2*VOLUME_STACK_SIZE + 1]; uint num_hits = scene_intersect_volume_all(kg, &volume_ray, hits, @@ -1197,7 +1199,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, Ray volume_ray = *ray; # ifdef __VOLUME_RECORD_ALL__ - Intersection hits[2*VOLUME_STACK_SIZE]; + Intersection hits[2*VOLUME_STACK_SIZE + 1]; uint num_hits = scene_intersect_volume_all(kg, &volume_ray, hits, @@ -1216,6 +1218,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, # else Intersection isect; int step = 0; + float3 Pend = ray->P + ray->D*ray->t; while(step < 2 * VOLUME_STACK_SIZE && scene_intersect_volume(kg, &volume_ray, @@ -1227,7 +1230,9 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, /* Move ray forward. */ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng); - volume_ray.t -= stack_sd->ray_length; + if(volume_ray.t != FLT_MAX) { + volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t); + } ++step; } # endif diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index 365ce891354..f11c85d5f6a 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -95,7 +95,7 @@ void kernel_tex_copy(KernelGlobals *kg, int id = atoi(name + strlen("__tex_image_float4_")); int array_index = id; - if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_CPU) { tex = &kg->texture_float4_images[array_index]; } @@ -109,9 +109,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_float")) { texture_image_float *tex = NULL; int id = atoi(name + strlen("__tex_image_float_")); - int array_index = id - TEX_IMAGE_FLOAT_START_CPU; + int array_index = id - TEX_START_FLOAT_CPU; - if(array_index >= 0 && array_index < TEX_NUM_FLOAT_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_FLOAT_CPU) { tex = &kg->texture_float_images[array_index]; } @@ -125,9 +125,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_byte4")) { texture_image_uchar4 *tex = NULL; int id = atoi(name + strlen("__tex_image_byte4_")); - int array_index = id - TEX_IMAGE_BYTE4_START_CPU; + int array_index = id - TEX_START_BYTE4_CPU; - if(array_index >= 0 && array_index < TEX_NUM_BYTE4_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_BYTE4_CPU) { tex = &kg->texture_byte4_images[array_index]; } @@ -141,9 +141,9 @@ void kernel_tex_copy(KernelGlobals *kg, else if(strstr(name, "__tex_image_byte")) { texture_image_uchar *tex = NULL; int id = atoi(name + strlen("__tex_image_byte_")); - int array_index = id - TEX_IMAGE_BYTE_START_CPU; + int array_index = id - TEX_START_BYTE_CPU; - if(array_index >= 0 && array_index < TEX_NUM_BYTE_IMAGES_CPU) { + if(array_index >= 0 && array_index < TEX_NUM_BYTE_CPU) { tex = &kg->texture_byte_images[array_index]; } @@ -154,6 +154,38 @@ void kernel_tex_copy(KernelGlobals *kg, tex->extension = extension; } } + else if(strstr(name, "__tex_image_half4")) { + texture_image_half4 *tex = NULL; + int id = atoi(name + strlen("__tex_image_half4_")); + int array_index = id - TEX_START_HALF4_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF4_CPU) { + tex = &kg->texture_half4_images[array_index]; + } + + if(tex) { + tex->data = (half4*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } + else if(strstr(name, "__tex_image_half")) { + texture_image_half *tex = NULL; + int id = atoi(name + strlen("__tex_image_half_")); + int array_index = id - TEX_START_HALF_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF_CPU) { + tex = &kg->texture_half_images[array_index]; + } + + if(tex) { + tex->data = (half*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } else assert(0); } diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index 4807f96a0df..47383140170 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -23,24 +23,32 @@ CCL_NAMESPACE_BEGIN ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp(x, y); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp(x, y); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp(x, y); + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp(x, y); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp(x, y); + else if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp(x, y); else return kg->texture_float4_images[tex].interp(x, y); } ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d(x, y, z); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d(x, y, z); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d(x, y, z); + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d(x, y, z); else return kg->texture_float4_images[tex].interp_3d(x, y, z); @@ -48,12 +56,16 @@ ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, fl ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation) { - if(tex >= TEX_IMAGE_BYTE_START_CPU) - return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d_ex(x, y, z, interpolation); - else if(tex >= TEX_IMAGE_FLOAT_START_CPU) - return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d_ex(x, y, z, interpolation); - else if(tex >= TEX_IMAGE_BYTE4_START_CPU) - return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d_ex(x, y, z, interpolation); + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half_images[tex - TEX_START_HALF4_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_BYTE_CPU) + return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_FLOAT_CPU) + return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_BYTE4_CPU) + return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d_ex(x, y, z, interpolation); else return kg->texture_float4_images[tex].interp_3d_ex(x, y, z, interpolation); } diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h index 962196ccbdd..ec82d4b4c22 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h @@ -109,6 +109,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, { if(type >= SHADER_EVAL_BAKE) { kernel_assert(output_luma == NULL); +#ifdef __BAKING__ kernel_bake_evaluate(kg, input, output, @@ -117,6 +118,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, i, offset, sample); +#endif } else { kernel_shader_evaluate(kg, diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index 37fae54faf0..eb2b6ea5414 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -77,8 +77,8 @@ # define CUDA_KERNEL_MAX_REGISTERS 63 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 -/* 5.0, 5.2 and 5.3 */ -#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530 +/* 5.0, 5.2, 5.3, 6.0, 6.1 */ +#elif __CUDA_ARCH__ >= 500 # define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536 # define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32 # define CUDA_BLOCK_MAX_THREADS 1024 @@ -86,7 +86,7 @@ /* tunable parameters */ # define CUDA_THREADS_BLOCK_WIDTH 16 -# define CUDA_KERNEL_MAX_REGISTERS 40 +# define CUDA_KERNEL_MAX_REGISTERS 48 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 /* unknown architecture */ diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl index aad06ed5c76..37907cd8fdc 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel.cl @@ -35,6 +35,7 @@ # include "../../kernel_montecarlo.h" # include "../../kernel_projection.h" # include "../../geom/geom.h" +# include "../../bvh/bvh.h" # include "../../kernel_accumulate.h" # include "../../kernel_camera.h" diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index 9cf4f2d759a..98de40e5a8a 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -25,7 +25,6 @@ set(SRC ) set(HEADER_SRC - osl_bssrdf.h osl_closures.h osl_globals.h osl_services.h diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp index 85fa7b34bcc..d835f9be45c 100644 --- a/intern/cycles/kernel/osl/background.cpp +++ b/intern/cycles/kernel/osl/background.cpp @@ -36,6 +36,9 @@ #include "osl_closures.h" +#include "kernel_compat_cpu.h" +#include "closure/alloc.h" + CCL_NAMESPACE_BEGIN using namespace OSL; @@ -48,7 +51,10 @@ using namespace OSL; /// class GenericBackgroundClosure : public CClosurePrimitive { public: - GenericBackgroundClosure() : CClosurePrimitive(Background) {} + void setup(ShaderData *sd, int /* path_flag */, float3 weight) + { + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, weight); + } }; /// Holdout closure @@ -60,7 +66,11 @@ public: /// class HoldoutClosure : CClosurePrimitive { public: - HoldoutClosure () : CClosurePrimitive(Holdout) {} + void setup(ShaderData *sd, int /* path_flag */, float3 weight) + { + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, weight); + sd->flag |= SD_HOLDOUT; + } }; /// ambient occlusion closure @@ -71,7 +81,11 @@ public: /// class AmbientOcclusionClosure : public CClosurePrimitive { public: - AmbientOcclusionClosure () : CClosurePrimitive(AmbientOcclusion) {} + void setup(ShaderData *sd, int /* path_flag */, float3 weight) + { + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, weight); + sd->flag |= SD_AO; + } }; ClosureParam *closure_background_params() diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp index b5c0d76cf37..bc26f42b559 100644 --- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp @@ -39,6 +39,7 @@ #include "kernel_types.h" #include "kernel_montecarlo.h" +#include "closure/alloc.h" #include "closure/bsdf_diffuse_ramp.h" CCL_NAMESPACE_BEGIN @@ -47,51 +48,30 @@ using namespace OSL; class DiffuseRampClosure : public CBSDFClosure { public: + DiffuseRampBsdf params; Color3 colors[8]; - float3 fcolors[8]; - DiffuseRampClosure() : CBSDFClosure(LABEL_DIFFUSE) - {} - - void setup() + void setup(ShaderData *sd, int /* path_flag */, float3 weight) { - sc.prim = this; - m_shaderdata_flag = bsdf_diffuse_ramp_setup(&sc); + DiffuseRampBsdf *bsdf = (DiffuseRampBsdf*)bsdf_alloc_osl(sd, sizeof(DiffuseRampBsdf), weight, ¶ms); - for(int i = 0; i < 8; i++) - fcolors[i] = TO_FLOAT3(colors[i]); - } + if(bsdf) { + bsdf->colors = (float3*)closure_alloc_extra(sd, sizeof(float3)*8); - void blur(float roughness) - { - bsdf_diffuse_ramp_blur(&sc, roughness); - } + if(bsdf->colors) { + for(int i = 0; i < 8; i++) + bsdf->colors[i] = TO_FLOAT3(colors[i]); - float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const - { - return bsdf_diffuse_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf); - } - - float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const - { - return bsdf_diffuse_ramp_eval_transmit(&sc, fcolors, omega_out, omega_in, &pdf); - } - - int sample(const float3 &Ng, - const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, - float randu, float randv, - float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, - float &pdf, float3 &eval) const - { - return bsdf_diffuse_ramp_sample(&sc, fcolors, Ng, omega_out, domega_out_dx, domega_out_dy, - randu, randv, &eval, &omega_in, &domega_in_dx, &domega_in_dy, &pdf); + sd->flag |= bsdf_diffuse_ramp_setup(bsdf); + } + } } }; ClosureParam *closure_bsdf_diffuse_ramp_params() { static ClosureParam params[] = { - CLOSURE_FLOAT3_PARAM(DiffuseRampClosure, sc.N), + CLOSURE_FLOAT3_PARAM(DiffuseRampClosure, params.N), CLOSURE_COLOR_ARRAY_PARAM(DiffuseRampClosure, colors, 8), CLOSURE_STRING_KEYPARAM(DiffuseRampClosure, label, "label"), CLOSURE_FINISH_PARAM(DiffuseRampClosure) diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp index bc73d80cd78..14c7644936e 100644 --- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp +++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp @@ -38,6 +38,7 @@ #include "osl_closures.h" #include "kernel_types.h" +#include "closure/alloc.h" #include "closure/bsdf_phong_ramp.h" CCL_NAMESPACE_BEGIN @@ -46,52 +47,31 @@ using namespace OSL; class PhongRampClosure : public CBSDFClosure { public: + PhongRampBsdf params; Color3 colors[8]; - float3 fcolors[8]; - PhongRampClosure() : CBSDFClosure(LABEL_GLOSSY) - {} - - void setup() + void setup(ShaderData *sd, int /* path_flag */, float3 weight) { - sc.prim = this; - m_shaderdata_flag = bsdf_phong_ramp_setup(&sc); + PhongRampBsdf *bsdf = (PhongRampBsdf*)bsdf_alloc_osl(sd, sizeof(PhongRampBsdf), weight, ¶ms); - for(int i = 0; i < 8; i++) - fcolors[i] = TO_FLOAT3(colors[i]); - } + if(bsdf) { + bsdf->colors = (float3*)closure_alloc_extra(sd, sizeof(float3)*8); - void blur(float roughness) - { - bsdf_phong_ramp_blur(&sc, roughness); - } + if(bsdf->colors) { + for(int i = 0; i < 8; i++) + bsdf->colors[i] = TO_FLOAT3(colors[i]); - float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const - { - return bsdf_phong_ramp_eval_reflect(&sc, fcolors, omega_out, omega_in, &pdf); - } - - float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const - { - return bsdf_phong_ramp_eval_transmit(&sc, fcolors, omega_out, omega_in, &pdf); - } - - int sample(const float3 &Ng, - const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, - float randu, float randv, - float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, - float &pdf, float3 &eval) const - { - return bsdf_phong_ramp_sample(&sc, fcolors, Ng, omega_out, domega_out_dx, domega_out_dy, - randu, randv, &eval, &omega_in, &domega_in_dx, &domega_in_dy, &pdf); + sd->flag |= bsdf_phong_ramp_setup(bsdf); + } + } } }; ClosureParam *closure_bsdf_phong_ramp_params() { static ClosureParam params[] = { - CLOSURE_FLOAT3_PARAM(PhongRampClosure, sc.N), - CLOSURE_FLOAT_PARAM(PhongRampClosure, sc.data0), + CLOSURE_FLOAT3_PARAM(PhongRampClosure, params.N), + CLOSURE_FLOAT_PARAM(PhongRampClosure, params.exponent), CLOSURE_COLOR_ARRAY_PARAM(PhongRampClosure, colors, 8), CLOSURE_STRING_KEYPARAM(PhongRampClosure, label, "label"), CLOSURE_FINISH_PARAM(PhongRampClosure) diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp index f91fd6e015c..3f13e08b302 100644 --- a/intern/cycles/kernel/osl/emissive.cpp +++ b/intern/cycles/kernel/osl/emissive.cpp @@ -36,7 +36,9 @@ #include "osl_closures.h" +#include "kernel_compat_cpu.h" #include "kernel_types.h" +#include "closure/alloc.h" #include "closure/emissive.h" CCL_NAMESPACE_BEGIN @@ -52,25 +54,10 @@ using namespace OSL; /// class GenericEmissiveClosure : public CClosurePrimitive { public: - GenericEmissiveClosure() : CClosurePrimitive(Emissive) { } - - Color3 eval(const Vec3 &Ng, const Vec3 &omega_out) const - { - float3 result = emissive_simple_eval(TO_FLOAT3(Ng), TO_FLOAT3(omega_out)); - return TO_COLOR3(result); - } - - void sample(const Vec3 &Ng, float randu, float randv, - Vec3 &omega_out, float &pdf) const - { - float3 omega_out_; - emissive_sample(TO_FLOAT3(Ng), randu, randv, &omega_out_, &pdf); - omega_out = TO_VEC3(omega_out_); - } - - float pdf(const Vec3 &Ng, const Vec3 &omega_out) const + void setup(ShaderData *sd, int /* path_flag */, float3 weight) { - return emissive_pdf(TO_FLOAT3(Ng), TO_FLOAT3(omega_out)); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, weight); + sd->flag |= SD_EMISSION; } }; diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp index f5284653c49..b76f2b4713a 100644 --- a/intern/cycles/kernel/osl/osl_bssrdf.cpp +++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp @@ -30,17 +30,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <OpenImageIO/fmath.h> - #include <OSL/genclosure.h> #include "kernel_compat_cpu.h" -#include "osl_bssrdf.h" #include "osl_closures.h" #include "kernel_types.h" #include "kernel_montecarlo.h" +#include "closure/alloc.h" #include "closure/bsdf_util.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_disney_diffuse.h" @@ -50,27 +48,83 @@ CCL_NAMESPACE_BEGIN using namespace OSL; +class CBSSRDFClosure : public CClosurePrimitive { +public: + Bssrdf params; + float3 radius; + float3 albedo; + + void alloc(ShaderData *sd, int path_flag, float3 weight, ClosureType type) + { + float sample_weight = fabsf(average(weight)); + + /* disable in case of diffuse ancestor, can't see it well then and + * adds considerably noise due to probabilities of continuing path + * getting lower and lower */ + if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { + radius = make_float3(0.0f, 0.0f, 0.0f); + } + + if(sample_weight > CLOSURE_WEIGHT_CUTOFF) { + /* sharpness */ + float sharpness = params.sharpness; + /* texture color blur */ + float texture_blur = params.texture_blur; + + /* create one closure per color channel */ + Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.x; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.x; + bssrdf->sharpness = sharpness; + bssrdf->N = params.N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); + } + + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.y; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.y; + bssrdf->sharpness = sharpness; + bssrdf->N = params.N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); + } + + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.z; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.z; + bssrdf->sharpness = sharpness; + bssrdf->N = params.N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); + } + } + } +}; + /* Cubic */ class CubicBSSRDFClosure : public CBSSRDFClosure { public: - CubicBSSRDFClosure() - {} - - void setup() + void setup(ShaderData *sd, int path_flag, float3 weight) { - sc.type = CLOSURE_BSSRDF_CUBIC_ID; - sc.data0 = fabsf(average(radius)); + alloc(sd, path_flag, weight, CLOSURE_BSSRDF_CUBIC_ID); } }; ClosureParam *closure_bssrdf_cubic_params() { static ClosureParam params[] = { - CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, sc.N), + CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, params.N), CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, radius), - CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.data1), - CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.T.x), + CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.texture_blur), + CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, params.sharpness), CLOSURE_STRING_KEYPARAM(CubicBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(CubicBSSRDFClosure) }; @@ -83,22 +137,18 @@ CCLOSURE_PREPARE(closure_bssrdf_cubic_prepare, CubicBSSRDFClosure) class GaussianBSSRDFClosure : public CBSSRDFClosure { public: - GaussianBSSRDFClosure() - {} - - void setup() + void setup(ShaderData *sd, int path_flag, float3 weight) { - sc.type = CLOSURE_BSSRDF_GAUSSIAN_ID; - sc.data0 = fabsf(average(radius)); + alloc(sd, path_flag, weight, CLOSURE_BSSRDF_GAUSSIAN_ID); } }; ClosureParam *closure_bssrdf_gaussian_params() { static ClosureParam params[] = { - CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, sc.N), + CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, params.N), CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, radius), - CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, sc.data1), + CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, params.texture_blur), CLOSURE_STRING_KEYPARAM(GaussianBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(GaussianBSSRDFClosure) }; @@ -111,22 +161,18 @@ CCLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure) class BurleyBSSRDFClosure : public CBSSRDFClosure { public: - BurleyBSSRDFClosure() - {} - - void setup() + void setup(ShaderData *sd, int path_flag, float3 weight) { - sc.type = CLOSURE_BSSRDF_BURLEY_ID; - sc.data0 = fabsf(average(radius)); + alloc(sd, path_flag, weight, CLOSURE_BSSRDF_BURLEY_ID); } }; ClosureParam *closure_bssrdf_burley_params() { static ClosureParam params[] = { - CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, sc.N), + CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, params.N), CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, radius), - CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, sc.data1), + CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, params.texture_blur), CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, albedo), CLOSURE_STRING_KEYPARAM(BurleyBSSRDFClosure, label, "label"), CLOSURE_FINISH_PARAM(BurleyBSSRDFClosure) diff --git a/intern/cycles/kernel/osl/osl_bssrdf.h b/intern/cycles/kernel/osl/osl_bssrdf.h deleted file mode 100644 index d81ecade543..00000000000 --- a/intern/cycles/kernel/osl/osl_bssrdf.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Adapted from Open Shading Language with this license: - * - * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. - * All Rights Reserved. - * - * Modifications Copyright 2011, Blender Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Sony Pictures Imageworks nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __OSL_BSSRDF_H__ -#define __OSL_BSSRDF_H__ - -#include <OSL/oslclosure.h> -#include <OSL/oslexec.h> -#include <OSL/genclosure.h> - -#include "osl_closures.h" - -#include "kernel_types.h" - -#include "util_types.h" - -CCL_NAMESPACE_BEGIN - -class CBSSRDFClosure : public CClosurePrimitive { -public: - ShaderClosure sc; - float3 radius; - float3 albedo; - - CBSSRDFClosure() : CClosurePrimitive(BSSRDF) { } - int scattering() const { return LABEL_DIFFUSE; } -}; - -CCL_NAMESPACE_END - -#endif /* __OSL_BSSRDF_H__ */ - diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 838c651a71c..2c7772fb25e 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -44,11 +44,14 @@ #include "kernel_compat_cpu.h" #include "kernel_globals.h" #include "kernel_montecarlo.h" +#include "kernel_random.h" +#include "closure/alloc.h" #include "closure/bsdf_util.h" #include "closure/bsdf_ashikhmin_velvet.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_microfacet.h" +#include "closure/bsdf_microfacet_multi.h" #include "closure/bsdf_oren_nayar.h" #include "closure/bsdf_reflection.h" #include "closure/bsdf_refraction.h" @@ -68,117 +71,145 @@ using namespace OSL; /* BSDF class definitions */ -BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, diffuse, LABEL_DIFFUSE) - CLOSURE_FLOAT3_PARAM(DiffuseClosure, sc.N), +BSDF_CLOSURE_CLASS_BEGIN(Diffuse, diffuse, DiffuseBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(DiffuseClosure, params.N), BSDF_CLOSURE_CLASS_END(Diffuse, diffuse) -BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, translucent, LABEL_DIFFUSE) - CLOSURE_FLOAT3_PARAM(TranslucentClosure, sc.N), +BSDF_CLOSURE_CLASS_BEGIN(Translucent, translucent, DiffuseBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(TranslucentClosure, params.N), BSDF_CLOSURE_CLASS_END(Translucent, translucent) -BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, oren_nayar, LABEL_DIFFUSE) - CLOSURE_FLOAT3_PARAM(OrenNayarClosure, sc.N), - CLOSURE_FLOAT_PARAM(OrenNayarClosure, sc.data0), +BSDF_CLOSURE_CLASS_BEGIN(OrenNayar, oren_nayar, OrenNayarBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(OrenNayarClosure, params.N), + CLOSURE_FLOAT_PARAM(OrenNayarClosure, params.roughness), BSDF_CLOSURE_CLASS_END(OrenNayar, oren_nayar) -BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, reflection, LABEL_SINGULAR) - CLOSURE_FLOAT3_PARAM(ReflectionClosure, sc.N), +BSDF_CLOSURE_CLASS_BEGIN(Reflection, reflection, MicrofacetBsdf, LABEL_SINGULAR) + CLOSURE_FLOAT3_PARAM(ReflectionClosure, params.N), BSDF_CLOSURE_CLASS_END(Reflection, reflection) -BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, refraction, LABEL_SINGULAR) - CLOSURE_FLOAT3_PARAM(RefractionClosure, sc.N), - CLOSURE_FLOAT_PARAM(RefractionClosure, sc.data0), +BSDF_CLOSURE_CLASS_BEGIN(Refraction, refraction, MicrofacetBsdf, LABEL_SINGULAR) + CLOSURE_FLOAT3_PARAM(RefractionClosure, params.N), + CLOSURE_FLOAT_PARAM(RefractionClosure, params.ior), BSDF_CLOSURE_CLASS_END(Refraction, refraction) -BSDF_CLOSURE_CLASS_BEGIN(Transparent, transparent, transparent, LABEL_SINGULAR) +BSDF_CLOSURE_CLASS_BEGIN(Transparent, transparent, ShaderClosure, LABEL_SINGULAR) BSDF_CLOSURE_CLASS_END(Transparent, transparent) -BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, ashikhmin_velvet, LABEL_DIFFUSE) - CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, sc.N), - CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, sc.data0), +BSDF_CLOSURE_CLASS_BEGIN(AshikhminVelvet, ashikhmin_velvet, VelvetBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(AshikhminVelvetClosure, params.N), + CLOSURE_FLOAT_PARAM(AshikhminVelvetClosure, params.sigma), BSDF_CLOSURE_CLASS_END(AshikhminVelvet, ashikhmin_velvet) -BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley, ashikhmin_shirley_aniso, ashikhmin_shirley, LABEL_GLOSSY|LABEL_REFLECT) - CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, sc.N), - CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, sc.T), - CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, sc.data0), - CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, sc.data1), +BSDF_CLOSURE_CLASS_BEGIN(AshikhminShirley, ashikhmin_shirley_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.N), + CLOSURE_FLOAT3_PARAM(AshikhminShirleyClosure, params.T), + CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(AshikhminShirleyClosure, params.alpha_y), BSDF_CLOSURE_CLASS_END(AshikhminShirley, ashikhmin_shirley_aniso) -BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, diffuse_toon, LABEL_DIFFUSE) - CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, sc.N), - CLOSURE_FLOAT_PARAM(DiffuseToonClosure, sc.data0), - CLOSURE_FLOAT_PARAM(DiffuseToonClosure, sc.data1), +BSDF_CLOSURE_CLASS_BEGIN(DiffuseToon, diffuse_toon, ToonBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(DiffuseToonClosure, params.N), + CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.size), + CLOSURE_FLOAT_PARAM(DiffuseToonClosure, params.smooth), BSDF_CLOSURE_CLASS_END(DiffuseToon, diffuse_toon) -BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, glossy_toon, LABEL_GLOSSY) - CLOSURE_FLOAT3_PARAM(GlossyToonClosure, sc.N), - CLOSURE_FLOAT_PARAM(GlossyToonClosure, sc.data0), - CLOSURE_FLOAT_PARAM(GlossyToonClosure, sc.data1), +BSDF_CLOSURE_CLASS_BEGIN(GlossyToon, glossy_toon, ToonBsdf, LABEL_GLOSSY) + CLOSURE_FLOAT3_PARAM(GlossyToonClosure, params.N), + CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.size), + CLOSURE_FLOAT_PARAM(GlossyToonClosure, params.smooth), BSDF_CLOSURE_CLASS_END(GlossyToon, glossy_toon) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX, microfacet_ggx, microfacet_ggx, LABEL_GLOSSY|LABEL_REFLECT) - CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, sc.N), - CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, sc.data0), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGX, microfacet_ggx, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(MicrofacetGGXClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetGGXClosure, params.alpha_x), BSDF_CLOSURE_CLASS_END(MicrofacetGGX, microfacet_ggx) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXAniso, microfacet_ggx_aniso, microfacet_ggx, LABEL_GLOSSY|LABEL_REFLECT) - CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, sc.N), - CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, sc.T), - CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, sc.data0), - CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, sc.data1), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXAniso, microfacet_ggx_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, params.N), + CLOSURE_FLOAT3_PARAM(MicrofacetGGXAnisoClosure, params.T), + CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetGGXAnisoClosure, params.alpha_y), BSDF_CLOSURE_CLASS_END(MicrofacetGGXAniso, microfacet_ggx_aniso) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann, microfacet_beckmann, microfacet_beckmann, LABEL_GLOSSY|LABEL_REFLECT) - CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, sc.N), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, sc.data0), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmann, microfacet_beckmann, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannClosure, params.alpha_x), BSDF_CLOSURE_CLASS_END(MicrofacetBeckmann, microfacet_beckmann) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannAniso, microfacet_beckmann_aniso, microfacet_beckmann, LABEL_GLOSSY|LABEL_REFLECT) - CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, sc.N), - CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, sc.T), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, sc.data0), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, sc.data1), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannAniso, microfacet_beckmann_aniso, MicrofacetBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, params.N), + CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannAnisoClosure, params.T), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannAnisoClosure, params.alpha_y), BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannAniso, microfacet_beckmann_aniso) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction, microfacet_ggx_refraction, microfacet_ggx, LABEL_GLOSSY|LABEL_TRANSMIT) - CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, sc.N), - CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, sc.data0), - CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, sc.data2), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetGGXRefraction, microfacet_ggx_refraction, MicrofacetBsdf, LABEL_GLOSSY|LABEL_TRANSMIT) + CLOSURE_FLOAT3_PARAM(MicrofacetGGXRefractionClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetGGXRefractionClosure, params.ior), BSDF_CLOSURE_CLASS_END(MicrofacetGGXRefraction, microfacet_ggx_refraction) -BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction, microfacet_beckmann, LABEL_GLOSSY|LABEL_TRANSMIT) - CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, sc.N), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, sc.data0), - CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, sc.data2), +BSDF_CLOSURE_CLASS_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction, MicrofacetBsdf, LABEL_GLOSSY|LABEL_TRANSMIT) + CLOSURE_FLOAT3_PARAM(MicrofacetBeckmannRefractionClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetBeckmannRefractionClosure, params.ior), BSDF_CLOSURE_CLASS_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction) -BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, hair_reflection, LABEL_GLOSSY) - CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.N), - CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data0), - CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data1), - CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T), - CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data2), +BSDF_CLOSURE_CLASS_BEGIN(HairReflection, hair_reflection, HairBsdf, LABEL_GLOSSY) + CLOSURE_FLOAT3_PARAM(HairReflectionClosure, unused), + CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness1), + CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.roughness2), + CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T), + CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset), BSDF_CLOSURE_CLASS_END(HairReflection, hair_reflection) -BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, hair_transmission, LABEL_GLOSSY) - CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, sc.N), - CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data0), - CLOSURE_FLOAT_PARAM(HairTransmissionClosure, sc.data1), - CLOSURE_FLOAT3_PARAM(HairReflectionClosure, sc.T), - CLOSURE_FLOAT_PARAM(HairReflectionClosure, sc.data2), +BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, HairBsdf, LABEL_GLOSSY) + CLOSURE_FLOAT3_PARAM(HairTransmissionClosure, unused), + CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness1), + CLOSURE_FLOAT_PARAM(HairTransmissionClosure, params.roughness2), + CLOSURE_FLOAT3_PARAM(HairReflectionClosure, params.T), + CLOSURE_FLOAT_PARAM(HairReflectionClosure, params.offset), BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission) -VOLUME_CLOSURE_CLASS_BEGIN(VolumeHenyeyGreenstein, henyey_greenstein, LABEL_VOLUME_SCATTER) - CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, sc.data0), +VOLUME_CLOSURE_CLASS_BEGIN(VolumeHenyeyGreenstein, henyey_greenstein, HenyeyGreensteinVolume, LABEL_VOLUME_SCATTER) + CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, params.g), VOLUME_CLOSURE_CLASS_END(VolumeHenyeyGreenstein, henyey_greenstein) -VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, LABEL_SINGULAR) +VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, ShaderClosure, LABEL_SINGULAR) VOLUME_CLOSURE_CLASS_END(VolumeAbsorption, absorption) +BSDF_CLOSURE_CLASS_BEGIN(DisneyDiffuse, disney_diffuse, DisneyDiffuseBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(DisneyDiffuseClosure, params.N), + CLOSURE_FLOAT3_PARAM(DisneyDiffuseClosure, params.baseColor), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, params.roughness), +BSDF_CLOSURE_CLASS_END(DisneyDiffuse, disney_diffuse) + +BSDF_CLOSURE_CLASS_BEGIN(DisneySheen, disney_sheen, DisneySheenBsdf, LABEL_DIFFUSE) + CLOSURE_FLOAT3_PARAM(DisneySheenClosure, params.N), + CLOSURE_FLOAT_PARAM(DisneySheenClosure, params.sheen), + CLOSURE_FLOAT_PARAM(DisneySheenClosure, params.sheenTint), +BSDF_CLOSURE_CLASS_END(DisneySheen, disney_sheen) + +BSDF_CLOSURE_CLASS_BEGIN(DisneySpecular, disney_specular, DisneySpecularBsdf, LABEL_GLOSSY | LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(DisneySpecularClosure, params.N), + CLOSURE_FLOAT3_PARAM(DisneySpecularClosure, params.T), + CLOSURE_FLOAT3_PARAM(DisneySpecularClosure, params.baseColor), + CLOSURE_FLOAT_PARAM(DisneySpecularClosure, params.metallic), + CLOSURE_FLOAT_PARAM(DisneySpecularClosure, params.specular), + CLOSURE_FLOAT_PARAM(DisneySpecularClosure, params.specularTint), + CLOSURE_FLOAT_PARAM(DisneySpecularClosure, params.roughness), + CLOSURE_FLOAT_PARAM(DisneySpecularClosure, params.anisotropic), +BSDF_CLOSURE_CLASS_END(DisneySpecular, disney_specular) + +BSDF_CLOSURE_CLASS_BEGIN(DisneyClearcoat, disney_clearcoat, DisneyClearcoatBsdf, LABEL_GLOSSY|LABEL_REFLECT) + CLOSURE_FLOAT3_PARAM(DisneyClearcoatClosure, params.N), + CLOSURE_FLOAT_PARAM(DisneyClearcoatClosure, params.clearcoat), + CLOSURE_FLOAT_PARAM(DisneyClearcoatClosure, params.clearcoatGloss), +BSDF_CLOSURE_CLASS_END(DisneyClearcoat, disney_clearcoat) /* DISNEY CLEARCOAT */ -class DisneyClearcoatClosure : public CBSDFClosure { +/*class DisneyClearcoatClosure : public CBSDFClosure { public: DisneyClearcoatClosure() : CBSDFClosure(LABEL_REFLECT | LABEL_GLOSSY) {} @@ -227,10 +258,10 @@ ClosureParam *bsdf_disney_clearcoat_params() } CCLOSURE_PREPARE(bsdf_disney_clearcoat_prepare, DisneyClearcoatClosure) - +*/ /* DISNEY DIFFUSE */ -class DisneyDiffuseClosure : public CBSDFClosure { +/*class DisneyDiffuseClosure : public CBSDFClosure { public: DisneyDiffuseClosure() : CBSDFClosure(LABEL_DIFFUSE) {} @@ -277,10 +308,10 @@ ClosureParam *bsdf_disney_diffuse_params() } CCLOSURE_PREPARE(bsdf_disney_diffuse_prepare, DisneyDiffuseClosure) - +*/ /* DISNEY SHEEN */ -class DisneySheenClosure : public CBSDFClosure { +/*class DisneySheenClosure : public CBSDFClosure { public: DisneySheenClosure() : CBSDFClosure(LABEL_DIFFUSE) {} @@ -328,10 +359,10 @@ ClosureParam *bsdf_disney_sheen_params() } CCLOSURE_PREPARE(bsdf_disney_sheen_prepare, DisneySheenClosure) - +*/ /* DISNEY SPECULAR */ -class DisneySpecularClosure : public CBSDFClosure { +/*class DisneySpecularClosure : public CBSDFClosure { public: DisneySpecularClosure() : CBSDFClosure(LABEL_REFLECT | LABEL_GLOSSY) {} @@ -383,6 +414,7 @@ ClosureParam *bsdf_disney_specular_params() } CCLOSURE_PREPARE(bsdf_disney_specular_prepare, DisneySpecularClosure) +*/ /* Registration */ @@ -417,6 +449,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare); register_closure(ss, "microfacet_ggx_refraction", id++, bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_multi_ggx", id++, + closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare); + register_closure(ss, "microfacet_multi_ggx_glass", id++, + closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare); + register_closure(ss, "microfacet_multi_ggx_aniso", id++, + closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare); register_closure(ss, "microfacet_beckmann", id++, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); register_closure(ss, "microfacet_beckmann_aniso", id++, @@ -470,5 +508,120 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) volume_absorption_params(), volume_absorption_prepare); } +/* BSDF Closure */ + +bool CBSDFClosure::skip(const ShaderData *sd, int path_flag, int scattering) +{ + /* caustic options */ + if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) { + KernelGlobals *kg = sd->osl_globals; + + if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) || + (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT))) + { + return true; + } + } + + return false; +} + +/* Multiscattering GGX closures */ + +class MicrofacetMultiClosure : public CBSDFClosure { +public: + MicrofacetBsdf params; + float3 color; + + MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight) + { + /* Technically, the MultiGGX Glass closure may also transmit. However, + * since this is set statically and only used for caustic flags, this + * is probably as good as it gets. */ + if(!skip(sd, path_flag, LABEL_GLOSSY|LABEL_REFLECT)) { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, ¶ms); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf && extra) { + bsdf->extra = extra; + bsdf->extra->color = color; + return bsdf; + } + } + + return NULL; + } +}; + +class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure); + +class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure { +public: + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_aniso_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.T), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_y), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure); + +class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {} + + void setup(ShaderData *sd, int path_flag, float3 weight) + { + MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight); + sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_glass_setup(bsdf) : 0; + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, params.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.alpha_x), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, params.ior), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure); + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 1578d06cd56..cd7b33703ff 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params(); OSL::ClosureParam *closure_bssrdf_gaussian_params(); OSL::ClosureParam *closure_bssrdf_burley_params(); OSL::ClosureParam *closure_henyey_greenstein_volume_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); @@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data); void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ @@ -84,21 +90,7 @@ void name(RendererServices *, int id, void *data) \ class CClosurePrimitive { public: - enum Category { - BSDF, ///< Reflective and/or transmissive surface - BSSRDF, ///< Sub-surface light transfer - Emissive, ///< Light emission - Background, ///< Background emission - Volume, ///< Volume scattering - Holdout, ///< Holdout from alpha - AmbientOcclusion, ///< Ambient occlusion - }; - - CClosurePrimitive (Category category_) : category (category_) {} - virtual ~CClosurePrimitive() {} - virtual void setup() {} - - Category category; + virtual void setup(ShaderData *sd, int path_flag, float3 weight) = 0; OSL::ustring label; }; @@ -107,68 +99,22 @@ public: class CBSDFClosure : public CClosurePrimitive { public: - ShaderClosure sc; - - CBSDFClosure(int scattering) : CClosurePrimitive(BSDF), - m_scattering_label(scattering), m_shaderdata_flag(0) - {} - - int scattering() const { return m_scattering_label; } - int shaderdata_flag() const { return m_shaderdata_flag; } - - virtual void blur(float roughness) = 0; - virtual float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float &pdf) const = 0; - virtual float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float &pdf) const = 0; - - virtual int sample(const float3 &Ng, - const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, - float randu, float randv, - float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, - float &pdf, float3 &eval) const = 0; - -protected: - int m_scattering_label; - int m_shaderdata_flag; + bool skip(const ShaderData *sd, int path_flag, int scattering); }; -#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, svmlower, TYPE) \ +#define BSDF_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \ \ class Upper##Closure : public CBSDFClosure { \ public: \ - Upper##Closure() : CBSDFClosure(TYPE) \ - { \ - } \ + structname params; \ + float3 unused; \ \ - void setup() \ + void setup(ShaderData *sd, int path_flag, float3 weight) \ { \ - sc.prim = NULL; \ - m_shaderdata_flag = bsdf_##lower##_setup(&sc); \ - } \ -\ - void blur(float roughness) \ - { \ - } \ -\ - float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const \ - { \ - pdf = 0.0f; \ - return make_float3(0.0f, 0.0f, 0.0f); \ - } \ -\ - float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const \ - { \ - pdf = 0.0f; \ - return make_float3(0.0f, 0.0f, 0.0f); \ - } \ -\ - int sample(const float3 &Ng, \ - const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, \ - float randu, float randv, \ - float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, \ - float &pdf, float3 &eval) const \ - { \ - pdf = 0; \ - return LABEL_NONE; \ + if(!skip(sd, path_flag, TYPE)) { \ + structname *bsdf = (structname*)bsdf_alloc_osl(sd, sizeof(structname), weight, ¶ms); \ + sd->flag |= (bsdf) ? bsdf_##lower##_setup(bsdf) : 0; \ + } \ } \ }; \ \ @@ -187,36 +133,18 @@ static ClosureParam *bsdf_##lower##_params() \ \ CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure) - /* Volume */ -class CVolumeClosure : public CClosurePrimitive { -public: - ShaderClosure sc; - - CVolumeClosure(int scattering) : CClosurePrimitive(Volume), - m_scattering_label(scattering), m_shaderdata_flag(0) - {} - ~CVolumeClosure() { } - - int scattering() const { return m_scattering_label; } - int shaderdata_flag() const { return m_shaderdata_flag; } - -protected: - int m_scattering_label; - int m_shaderdata_flag; -}; - -#define VOLUME_CLOSURE_CLASS_BEGIN(Upper, lower, TYPE) \ +#define VOLUME_CLOSURE_CLASS_BEGIN(Upper, lower, structname, TYPE) \ \ -class Upper##Closure : public CVolumeClosure { \ +class Upper##Closure : public CBSDFClosure { \ public: \ - Upper##Closure() : CVolumeClosure(TYPE) {} \ + structname params; \ \ - void setup() \ + void setup(ShaderData *sd, int path_flag, float3 weight) \ { \ - sc.prim = NULL; \ - m_shaderdata_flag = volume_##lower##_setup(&sc); \ + structname *volume = (structname*)bsdf_alloc_osl(sd, sizeof(structname), weight, ¶ms); \ + sd->flag |= (volume) ? volume_##lower##_setup(volume) : 0; \ } \ }; \ \ diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index ebe739ebd0e..caae24405f1 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -47,6 +47,7 @@ #include "kernel_camera.h" #include "kernels/cpu/kernel_cpu_image.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_projection.h" #include "kernel_accumulate.h" @@ -786,7 +787,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring TypeDesc type, ustring name, void *val) { KernelGlobals *kg = sd->osl_globals; - bool is_curve; + int prim_type = 0; int object; /* lookup of attribute on another object */ @@ -797,18 +798,17 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring return false; object = it->second; - is_curve = false; } else { object = sd->object; - is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0; + prim_type = attribute_primitive_type(kg, sd); if(object == OBJECT_NONE) return get_background_attribute(kg, sd, name, type, derivatives, val); } /* find attribute on object */ - object = object*ATTR_PRIM_TYPES + (is_curve == true); + object = object*ATTR_PRIM_TYPES + prim_type; OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object]; OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); @@ -912,7 +912,7 @@ bool OSLRenderServices::texture(ustring filename, #endif bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t); @@ -993,7 +993,7 @@ bool OSLRenderServices::texture3d(ustring filename, } bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z); diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index a2f1c31a7c5..784e468635c 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -23,12 +23,12 @@ #include "geom/geom_object.h" -#include "closure/bsdf_util.h" +/*#include "closure/bsdf_util.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_disney_diffuse.h" #include "closure/bssrdf.h" -#include "osl_bssrdf.h" +#include "osl_bssrdf.h"*/ #include "osl_closures.h" #include "osl_globals.h" #include "osl_services.h" @@ -143,8 +143,10 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, PathS /* Surface */ -static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, - const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) +static void flatten_surface_closure_tree(ShaderData *sd, + int path_flag, + const OSL::ClosureColor *closure, + float3 weight = make_float3(1.0f, 1.0f, 1.0f)) { /* OSL gives us a closure tree, we flatten it into arrays per * closure type, for evaluation, sampling, etc later on. */ @@ -165,159 +167,11 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure; CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); - if(prim) { - ShaderClosure sc; - + if (prim) { #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS weight = weight*TO_FLOAT3(comp->w); #endif - sc.weight = weight; - - prim->setup(); - - switch(prim->category) { - case CClosurePrimitive::BSDF: { - CBSDFClosure *bsdf = (CBSDFClosure *)prim; - int scattering = bsdf->scattering(); - - /* caustic options */ - if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) { - KernelGlobals *kg = sd->osl_globals; - - if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) || - (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT))) - { - return; - } - } - - /* sample weight */ - float sample_weight = fabsf(average(weight)); - - sc.sample_weight = sample_weight; - - sc.type = bsdf->sc.type; - sc.N = bsdf->sc.N; - sc.T = bsdf->sc.T; - sc.data0 = bsdf->sc.data0; - sc.data1 = bsdf->sc.data1; - sc.data2 = bsdf->sc.data2; - sc.prim = bsdf->sc.prim; - - /* add */ - if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) { - sd->closure[sd->num_closure++] = sc; - sd->flag |= bsdf->shaderdata_flag(); - } - break; - } - case CClosurePrimitive::Emissive: { - /* sample weight */ - float sample_weight = fabsf(average(weight)); - - sc.sample_weight = sample_weight; - sc.type = CLOSURE_EMISSION_ID; - sc.data0 = 0.0f; - sc.data1 = 0.0f; - sc.data2 = 0.0f; - sc.prim = NULL; - - /* flag */ - if(sd->num_closure < MAX_CLOSURE) { - sd->closure[sd->num_closure++] = sc; - sd->flag |= SD_EMISSION; - } - break; - } - case CClosurePrimitive::AmbientOcclusion: { - /* sample weight */ - float sample_weight = fabsf(average(weight)); - - sc.sample_weight = sample_weight; - sc.type = CLOSURE_AMBIENT_OCCLUSION_ID; - sc.data0 = 0.0f; - sc.data1 = 0.0f; - sc.data2 = 0.0f; - sc.prim = NULL; - - if(sd->num_closure < MAX_CLOSURE) { - sd->closure[sd->num_closure++] = sc; - sd->flag |= SD_AO; - } - break; - } - case CClosurePrimitive::Holdout: { - sc.sample_weight = 0.0f; - sc.type = CLOSURE_HOLDOUT_ID; - sc.data0 = 0.0f; - sc.data1 = 0.0f; - sc.data2 = 0.0f; - sc.prim = NULL; - - if(sd->num_closure < MAX_CLOSURE) { - sd->closure[sd->num_closure++] = sc; - sd->flag |= SD_HOLDOUT; - } - break; - } - case CClosurePrimitive::BSSRDF: { - CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim; - float sample_weight = fabsf(average(weight)); - - if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) { - sc.sample_weight = sample_weight; - - sc.type = bssrdf->sc.type; - sc.N = bssrdf->sc.N; - sc.data1 = bssrdf->sc.data1; - sc.T.x = bssrdf->sc.T.x; - sc.prim = NULL; - - /* disable in case of diffuse ancestor, can't see it well then and - * adds considerably noise due to probabilities of continuing path - * getting lower and lower */ - if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) - bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f); - - float3 albedo = - (bssrdf->sc.type == CLOSURE_BSSRDF_BURLEY_ID || bssrdf->sc.type == CLOSURE_BSSRDF_DISNEY_ID) - ? bssrdf->albedo - : make_float3(0.0f, 0.0f, 0.0f); - - /* create one closure for each color channel */ - if(fabsf(weight.x) > 0.0f) { - sc.weight = make_float3(weight.x, 0.0f, 0.0f); - sc.data0 = bssrdf->radius.x; - sc.data1 = 0.0f; - sc.data2 = albedo.x; - sd->flag |= bssrdf_setup(&sc, sc.type); - sd->closure[sd->num_closure++] = sc; - } - - if(fabsf(weight.y) > 0.0f) { - sc.weight = make_float3(0.0f, weight.y, 0.0f); - sc.data0 = bssrdf->radius.y; - sc.data1 = 0.0f; - sc.data2 = albedo.y; - sd->flag |= bssrdf_setup(&sc, sc.type); - sd->closure[sd->num_closure++] = sc; - } - - if(fabsf(weight.z) > 0.0f) { - sc.weight = make_float3(0.0f, 0.0f, weight.z); - sc.data0 = bssrdf->radius.z; - sc.data1 = 0.0f; - sc.data2 = albedo.z; - sd->flag |= bssrdf_setup(&sc, sc.type); - sd->closure[sd->num_closure++] = sc; - } - } - break; - } - case CClosurePrimitive::Background: - case CClosurePrimitive::Volume: - break; /* not relevant */ - } + prim->setup(sd, path_flag, weight); } break; } @@ -347,7 +201,9 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state /* Background */ -static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure) +static void flatten_background_closure_tree(ShaderData *sd, + const OSL::ClosureColor *closure, + float3 weight = make_float3(1.0f, 1.0f, 1.0f)) { /* OSL gives us a closure tree, if we are shading for background there * is only one supported closure type at the moment, which has no evaluation @@ -356,32 +212,32 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure) switch(closure->id) { case OSL::ClosureColor::MUL: { OSL::ClosureMul *mul = (OSL::ClosureMul *)closure; - - return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure); + flatten_background_closure_tree(sd, mul->closure, weight * TO_FLOAT3(mul->weight)); + break; } case OSL::ClosureColor::ADD: { OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure; - return flatten_background_closure_tree(add->closureA) + - flatten_background_closure_tree(add->closureB); + flatten_background_closure_tree(sd, add->closureA, weight); + flatten_background_closure_tree(sd, add->closureB, weight); + break; } default: { OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure; CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); - if(prim && prim->category == CClosurePrimitive::Background) + if(prim) { #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS - return TO_FLOAT3(comp->w); -#else - return make_float3(1.0f, 1.0f, 1.0f); + weight = weight*TO_FLOAT3(comp->w); #endif + prim->setup(sd, 0, weight); + } + break; } } - - return make_float3(0.0f, 0.0f, 0.0f); } -float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx) +void OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; @@ -398,15 +254,14 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState * /* return background color immediately */ if(globals->Ci) - return flatten_background_closure_tree(globals->Ci); - - return make_float3(0.0f, 0.0f, 0.0f); + flatten_background_closure_tree(sd, globals->Ci); } /* Volume */ static void flatten_volume_closure_tree(ShaderData *sd, - const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) + const OSL::ClosureColor *closure, + float3 weight = make_float3(1.0f, 1.0f, 1.0f)) { /* OSL gives us a closure tree, we flatten it into arrays per * closure type, for evaluation, sampling, etc later on. */ @@ -428,60 +283,10 @@ static void flatten_volume_closure_tree(ShaderData *sd, CClosurePrimitive *prim = (CClosurePrimitive *)comp->data(); if(prim) { - ShaderClosure sc; - #ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS weight = weight*TO_FLOAT3(comp->w); #endif - sc.weight = weight; - - prim->setup(); - - switch(prim->category) { - case CClosurePrimitive::Volume: { - CVolumeClosure *volume = (CVolumeClosure *)prim; - /* sample weight */ - float sample_weight = fabsf(average(weight)); - - sc.sample_weight = sample_weight; - sc.type = volume->sc.type; - sc.data0 = volume->sc.data0; - sc.data1 = volume->sc.data1; - - /* add */ - if((sc.sample_weight > CLOSURE_WEIGHT_CUTOFF) && - (sd->num_closure < MAX_CLOSURE)) - { - sd->closure[sd->num_closure++] = sc; - sd->flag |= volume->shaderdata_flag(); - } - break; - } - case CClosurePrimitive::Emissive: { - /* sample weight */ - float sample_weight = fabsf(average(weight)); - - sc.sample_weight = sample_weight; - sc.type = CLOSURE_EMISSION_ID; - sc.data0 = 0.0f; - sc.data1 = 0.0f; - sc.prim = NULL; - - /* flag */ - if(sd->num_closure < MAX_CLOSURE) { - sd->closure[sd->num_closure++] = sc; - sd->flag |= SD_EMISSION; - } - break; - } - case CClosurePrimitive::Holdout: - break; /* not implemented */ - case CClosurePrimitive::Background: - case CClosurePrimitive::BSDF: - case CClosurePrimitive::BSSRDF: - case CClosurePrimitive::AmbientOcclusion: - break; /* not relevant */ - } + prim->setup(sd, 0, weight); } } } @@ -533,40 +338,6 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte sd->P = TO_FLOAT3(globals->P); } -/* BSDF Closure */ - -int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf) -{ - CBSDFClosure *sample_bsdf = (CBSDFClosure *)sc->prim; - - pdf = 0.0f; - - return sample_bsdf->sample(sd->Ng, - sd->I, sd->dI.dx, sd->dI.dy, - randu, randv, - omega_in, domega_in.dx, domega_in.dy, - pdf, eval); -} - -float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf) -{ - CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim; - float3 bsdf_eval; - - if(dot(sd->Ng, omega_in) >= 0.0f) - bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf); - else - bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf); - - return bsdf_eval; -} - -void OSLShader::bsdf_blur(ShaderClosure *sc, float roughness) -{ - CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim; - bsdf->blur(roughness); -} - /* Attributes */ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 7d26cd40da5..a185b8b8c05 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -54,18 +54,10 @@ public: /* eval */ static void eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); - static float3 eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); + static void eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); static void eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx); static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx); - /* sample & eval */ - static int bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, - float randu, float randv, - float3& eval, float3& omega_in, differential3& domega_in, float& pdf); - static float3 bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, - const float3& omega_in, float& pdf); - static void bsdf_blur(ShaderClosure *sc, float roughness); - /* attributes */ static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem); }; diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 5dab03bcb16..39dbd185018 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC_OSL node_hair_bsdf.osl node_uv_map.osl node_disney_bsdf.osl + node_rgb_to_bw.osl ) set(SRC_OSL_HEADERS diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl index 281ed4e8726..bef6d7e8809 100644 --- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl @@ -45,12 +45,14 @@ shader node_anisotropic_bsdf( RoughnessV = Roughness / (1.0 - aniso); } - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * reflection(Normal); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color); else BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV); } diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl index 35e01178ba8..d5e0a7d4c8c 100644 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ b/intern/cycles/kernel/shaders/node_brick_texture.osl @@ -59,10 +59,10 @@ float brick(point p, float mortar_size, float bias, shader node_brick_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float Offset = 0.5, - int OffsetFrequency = 2, - float Squash = 1.0, - int SquashFrequency = 1, + float offset = 0.5, + int offset_frequency = 2, + float squash = 1.0, + int squash_frequency = 1, point Vector = P, color Color1 = 0.2, color Color2 = 0.8, @@ -84,7 +84,7 @@ shader node_brick_texture( color Col = Color1; Fac = brick(p * Scale, MortarSize, Bias, BrickWidth, RowHeight, - Offset, OffsetFrequency, Squash, SquashFrequency, tint); + offset, offset_frequency, squash, squash_frequency, tint); if (Fac != 1.0) { float facm = 1.0 - tint; diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/shaders/node_convert_from_color.osl index 44074317f42..e95a17f6fa1 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_color.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_color.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_color( - color Color = 0.0, - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + color value_color = 0.0, + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; - ValInt = (int)(Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722); - Vector = vector(Color[0], Color[1], Color[2]); - Point = point(Color[0], Color[1], Color[2]); - Normal = normal(Color[0], Color[1], Color[2]); + value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722; + value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722); + value_vector = vector(value_color[0], value_color[1], value_color[2]); + value_point = point(value_color[0], value_color[1], value_color[2]); + value_normal = normal(value_color[0], value_color[1], value_color[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/shaders/node_convert_from_float.osl index fc5c79c4c64..a5c2e3b26ad 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_float.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_float.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_float( - float Val = 0.0, - output string String = "", - output int ValInt = 0, - output color Color = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + float value_float = 0.0, + output string value_string = "", + output int value_int = 0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - ValInt = (int)Val; - Color = color(Val, Val, Val); - Vector = vector(Val, Val, Val); - Point = point(Val, Val, Val); - Normal = normal(Val, Val, Val); + value_int = (int)value_float; + value_color = color(value_float, value_float, value_float); + value_vector = vector(value_float, value_float, value_float); + value_point = point(value_float, value_float, value_float); + value_normal = normal(value_float, value_float, value_float); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/shaders/node_convert_from_int.osl index 3c3785ebc0d..0e6ae711210 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_int.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_int.osl @@ -17,19 +17,19 @@ #include "stdosl.h" shader node_convert_from_int( - int ValInt = 0, - output string String = "", - output float Val = 0.0, - output color Color = 0.0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + int value_int = 0, + output string value_string = "", + output float value_float = 0.0, + output color value_color = 0.0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - float f = (float)ValInt; - Val = f; - Color = color(f, f, f); - Vector = vector(f, f, f); - Point = point(f, f, f); - Normal = normal(f, f, f); + float f = (float)value_int; + value_float = f; + value_color = color(f, f, f); + value_vector = vector(f, f, f); + value_point = point(f, f, f); + value_normal = normal(f, f, f); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/shaders/node_convert_from_normal.osl index 8ecc56ac8ce..7fffa7f6169 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_normal.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_normal( - normal Normal = normal(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output color Color = 0.0, - output point Point = point(0.0, 0.0, 0.0)) + normal value_normal = normal(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output point value_point = point(0.0, 0.0, 0.0)) { - Val = (Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Vector = vector(Normal[0], Normal[1], Normal[2]); - Color = color(Normal[0], Normal[1], Normal[2]); - Point = point(Normal[0], Normal[1], Normal[2]); + value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_normal[0], value_normal[1], value_normal[2]); + value_color = color(value_normal[0], value_normal[1], value_normal[2]); + value_point = point(value_normal[0], value_normal[1], value_normal[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/shaders/node_convert_from_point.osl index e5913b7a1e4..9e4930296bb 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_point.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_point.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_point( - point Point = point(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output color Color = 0.0, - output normal Normal = normal(0.0, 0.0, 0.0)) + point value_point = point(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output color value_color = 0.0, + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = (Point[0] + Point[1] + Point[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Vector = vector(Point[0], Point[1], Point[2]); - Color = color(Point[0], Point[1], Point[2]); - Normal = normal(Point[0], Point[1], Point[2]); + value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_vector = vector(value_point[0], value_point[1], value_point[2]); + value_color = color(value_point[0], value_point[1], value_point[2]); + value_normal = normal(value_point[0], value_point[1], value_point[2]); } diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/shaders/node_convert_from_string.osl index 0466734277b..cbc6653eada 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_string.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_string.osl @@ -17,13 +17,13 @@ #include "stdosl.h" shader node_convert_from_string( - string String = "", - output color Color = color(0.0, 0.0, 0.0), - output float Val = 0.0, - output int ValInt = 0, - output vector Vector = vector(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + string value_string = "", + output color value_color = color(0.0, 0.0, 0.0), + output float value_float = 0.0, + output int value_int = 0, + output vector value_vector = vector(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { } diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/shaders/node_convert_from_vector.osl index 79c5cb04550..8bdca469b90 100644 --- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl +++ b/intern/cycles/kernel/shaders/node_convert_from_vector.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_convert_from_vector( - vector Vector = vector(0.0, 0.0, 0.0), - output string String = "", - output float Val = 0.0, - output int ValInt = 0, - output color Color = color(0.0, 0.0, 0.0), - output point Point = point(0.0, 0.0, 0.0), - output normal Normal = normal(0.0, 0.0, 0.0)) + vector value_vector = vector(0.0, 0.0, 0.0), + output string value_string = "", + output float value_float = 0.0, + output int value_int = 0, + output color value_color = color(0.0, 0.0, 0.0), + output point value_point = point(0.0, 0.0, 0.0), + output normal value_normal = normal(0.0, 0.0, 0.0)) { - Val = (Vector[0] + Vector[1] + Vector[2]) * (1.0 / 3.0); - ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0)); - Color = color(Vector[0], Vector[1], Vector[2]); - Point = point(Vector[0], Vector[1], Vector[2]); - Normal = normal(Vector[0], Vector[1], Vector[2]); + value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0); + value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0)); + value_color = color(value_vector[0], value_vector[1], value_vector[2]); + value_point = point(value_vector[0], value_vector[1], value_vector[2]); + value_normal = normal(value_vector[0], value_vector[1], value_vector[2]); } diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl index 3a0b782c98e..0a7f602226d 100644 --- a/intern/cycles/kernel/shaders/node_environment_texture.osl +++ b/intern/cycles/kernel/shaders/node_environment_texture.osl @@ -44,7 +44,7 @@ shader node_environment_texture( matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), vector Vector = P, string filename = "", - string projection = "Equirectangular", + string projection = "equirectangular", string interpolation = "linear", string color_space = "sRGB", int is_float = 1, @@ -59,7 +59,7 @@ shader node_environment_texture( p = normalize(p); - if (projection == "Equirectangular") + if (projection == "equirectangular") p = environment_texture_direction_to_equirectangular(p); else p = environment_texture_direction_to_mirrorball(p); diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl index 68bc107cc5e..a9723a8300a 100644 --- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl @@ -19,7 +19,7 @@ shader node_glass_bsdf( color Color = 0.8, - string distribution = "Sharp", + string distribution = "sharp", float Roughness = 0.2, float IOR = 1.45, normal Normal = N, @@ -30,11 +30,13 @@ shader node_glass_bsdf( float cosi = dot(I, Normal); float Fr = fresnel_dielectric_cos(cosi, eta); - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta)); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) + (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta)); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color); else if (distribution == "GGX") BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) + (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta)); diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl index d3250b32d0b..f4ea7e7dc6a 100644 --- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl @@ -24,12 +24,14 @@ shader node_glossy_bsdf( normal Normal = N, output closure color BSDF = 0) { - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * reflection(Normal); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann(Normal, Roughness); else if (distribution == "GGX") BSDF = Color * microfacet_ggx(Normal, Roughness); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color); else BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness); diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl index 52b49688ab3..f458937a18f 100644 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl @@ -29,31 +29,31 @@ float gradient(point p, string type) float result = 0.0; - if (type == "Linear") { + if (type == "linear") { result = x; } - else if (type == "Quadratic") { + else if (type == "quadratic") { float r = max(x, 0.0); result = r * r; } - else if (type == "Easing") { + else if (type == "easing") { float r = min(max(x, 0.0), 1.0); float t = r * r; result = (3.0 * t - 2.0 * t * r); } - else if (type == "Diagonal") { + else if (type == "diagonal") { result = (x + y) * 0.5; } - else if (type == "Radial") { + else if (type == "radial") { result = atan2(y, x) / M_2PI + 0.5; } else { float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0); - if (type == "Quadratic Sphere") + if (type == "quadratic_sphere") result = r * r; - else if (type == "Spherical") + else if (type == "spherical") result = r; } @@ -63,7 +63,7 @@ float gradient(point p, string type) shader node_gradient_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "Linear", + string type = "linear", point Vector = P, output float Fac = 0.0, output color Color = 0.0) @@ -73,7 +73,7 @@ shader node_gradient_texture( if (use_mapping) p = transform(mapping, p); - Fac = gradient(p, Type); + Fac = gradient(p, type); Color = color(Fac, Fac, Fac); } diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_hair_bsdf.osl index 54d4cb67c3b..ef8f2fae894 100644 --- a/intern/cycles/kernel/shaders/node_hair_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_hair_bsdf.osl @@ -20,38 +20,39 @@ shader node_hair_bsdf( color Color = 0.8, - string component = "Reflection", + string component = "reflection", float Offset = 0.0, float RoughnessU = 0.1, float RoughnessV = 1.0, - normal Normal = Ng, + normal Tangent = normal(0, 0, 0), output closure color BSDF = 0) { - float IsStrand; float roughnessh = clamp(RoughnessU, 0.001, 1.0); float roughnessv = clamp(RoughnessV, 0.001, 1.0); - getattribute("geom:is_curve", IsStrand); + float offset = -Offset; - if (!IsStrand) { - if (backfacing()) { - BSDF = transparent(); - } - else { - if (component == "Reflection") - BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0); - else - BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0); - } + normal T; + float IsCurve = 0; + getattribute("geom:is_curve", IsCurve); + + if (isconnected(Tangent)) { + T = Tangent; + } + else if(!IsCurve) { + T = normalize(dPdv); + offset = 0.0; + } + else { + T = normalize(dPdu); + } + + if (backfacing() && IsCurve) { + BSDF = transparent(); } else { - if (backfacing()) { - BSDF = transparent(); - } - else { - if (component == "Reflection") - BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, dPdu, -Offset); - else - BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, dPdu, -Offset); - } + if (component == "reflection") + BSDF = Color * hair_reflection(Ng, roughnessh, roughnessv, T, offset); + else + BSDF = Color * hair_transmission(Ng, roughnessh, roughnessv, T, offset); } } diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl index d3a347b70db..7cd2922dd4f 100644 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ b/intern/cycles/kernel/shaders/node_image_texture.osl @@ -62,9 +62,9 @@ color image_texture_lookup(string filename, int use_alpha, int is_float, string interpolation, - string wrap) + string extension) { - color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha); + color rgb = (color)texture(filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha); if (use_alpha) { rgb = color_unpremultiply(rgb, Alpha); @@ -86,9 +86,9 @@ shader node_image_texture( point Vector = P, string filename = "", string color_space = "sRGB", - string projection = "Flat", + string projection = "flat", string interpolation = "smartcubic", - string wrap = "periodic", + string extension = "periodic", float projection_blend = 0.0, int is_float = 1, int use_alpha = 1, @@ -100,7 +100,7 @@ shader node_image_texture( if (use_mapping) p = transform(mapping, p); - if (projection == "Flat") { + if (projection == "flat") { Color = image_texture_lookup(filename, color_space, p[0], p[1], @@ -108,9 +108,9 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } - else if (projection == "Box") { + else if (projection == "box") { /* object space normal */ vector Nob = transform("world", "object", N); @@ -184,7 +184,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[0] * tmp_alpha; } if (weight[1] > 0.0) { @@ -195,7 +195,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[1] * tmp_alpha; } if (weight[2] > 0.0) { @@ -206,11 +206,11 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[2] * tmp_alpha; } } - else if (projection == "Sphere") { + else if (projection == "sphere") { point projected = map_to_sphere(texco_remap_square(p)); Color = image_texture_lookup(filename, color_space, @@ -219,9 +219,9 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } - else if (projection == "Tube") { + else if (projection == "tube") { point projected = map_to_tube(texco_remap_square(p)); Color = image_texture_lookup(filename, color_space, @@ -230,6 +230,6 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } } diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl index 55992e3494c..8d6af391e04 100644 --- a/intern/cycles/kernel/shaders/node_magic_texture.osl +++ b/intern/cycles/kernel/shaders/node_magic_texture.osl @@ -93,7 +93,7 @@ color magic(point p, int n, float distortion) shader node_magic_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - int Depth = 2, + int depth = 2, float Distortion = 5.0, float Scale = 5.0, point Vector = P, @@ -105,7 +105,7 @@ shader node_magic_texture( if (use_mapping) p = transform(mapping, p); - Color = magic(p * Scale, Depth, Distortion); + Color = magic(p * Scale, depth, Distortion); Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0); } diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index 7eef97fd7e8..f309ef7c6f3 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -49,54 +49,54 @@ float safe_log(float a, float b) } shader node_math( - string type = "Add", - int Clamp = 0, + string type = "add", + int use_clamp = 0, float Value1 = 0.0, float Value2 = 0.0, output float Value = 0.0) { /* OSL asin, acos, pow check for values that could give rise to nan */ - if (type == "Add") + if (type == "add") Value = Value1 + Value2; - else if (type == "Subtract") + else if (type == "subtract") Value = Value1 - Value2; - else if (type == "Multiply") + else if (type == "multiply") Value = Value1 * Value2; - else if (type == "Divide") + else if (type == "divide") Value = safe_divide(Value1, Value2); - else if (type == "Sine") + else if (type == "sine") Value = sin(Value1); - else if (type == "Cosine") + else if (type == "cosine") Value = cos(Value1); - else if (type == "Tangent") + else if (type == "tangent") Value = tan(Value1); - else if (type == "Arcsine") + else if (type == "arcsine") Value = asin(Value1); - else if (type == "Arccosine") + else if (type == "arccosine") Value = acos(Value1); - else if (type == "Arctangent") + else if (type == "arctangent") Value = atan(Value1); - else if (type == "Power") + else if (type == "power") Value = pow(Value1, Value2); - else if (type == "Logarithm") + else if (type == "logarithm") Value = safe_log(Value1, Value2); - else if (type == "Minimum") + else if (type == "minimum") Value = min(Value1, Value2); - else if (type == "Maximum") + else if (type == "maximum") Value = max(Value1, Value2); - else if (type == "Round") + else if (type == "round") Value = floor(Value1 + 0.5); - else if (type == "Less Than") + else if (type == "less_than") Value = Value1 < Value2; - else if (type == "Greater Than") + else if (type == "greater_than") Value = Value1 > Value2; - else if (type == "Modulo") + else if (type == "modulo") Value = safe_modulo(Value1, Value2); - else if (type == "Absolute") + else if (type == "absolute") Value = fabs(Value1); - if (Clamp) + if (use_clamp) Value = clamp(Value, 0.0, 1.0); } diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl index 9ef58e4cbba..0862c34b6e1 100644 --- a/intern/cycles/kernel/shaders/node_mix.osl +++ b/intern/cycles/kernel/shaders/node_mix.osl @@ -277,8 +277,8 @@ color node_mix_clamp(color col) } shader node_mix( - string type = "Mix", - int Clamp = 0, + string type = "mix", + int use_clamp = 0, float Fac = 0.5, color Color1 = 0.0, color Color2 = 0.0, @@ -286,44 +286,44 @@ shader node_mix( { float t = clamp(Fac, 0.0, 1.0); - if (type == "Mix") + if (type == "mix") Color = node_mix_blend(t, Color1, Color2); - if (type == "Add") + if (type == "add") Color = node_mix_add(t, Color1, Color2); - if (type == "Multiply") + if (type == "multiply") Color = node_mix_mul(t, Color1, Color2); - if (type == "Screen") + if (type == "screen") Color = node_mix_screen(t, Color1, Color2); - if (type == "Overlay") + if (type == "overlay") Color = node_mix_overlay(t, Color1, Color2); - if (type == "Subtract") + if (type == "subtract") Color = node_mix_sub(t, Color1, Color2); - if (type == "Divide") + if (type == "divide") Color = node_mix_div(t, Color1, Color2); - if (type == "Difference") + if (type == "difference") Color = node_mix_diff(t, Color1, Color2); - if (type == "Darken") + if (type == "darken") Color = node_mix_dark(t, Color1, Color2); - if (type == "Lighten") + if (type == "lighten") Color = node_mix_light(t, Color1, Color2); - if (type == "Dodge") + if (type == "dodge") Color = node_mix_dodge(t, Color1, Color2); - if (type == "Burn") + if (type == "burn") Color = node_mix_burn(t, Color1, Color2); - if (type == "Hue") + if (type == "hue") Color = node_mix_hue(t, Color1, Color2); - if (type == "Saturation") + if (type == "saturation") Color = node_mix_sat(t, Color1, Color2); - if (type == "Value") + if (type == "value") Color = node_mix_val (t, Color1, Color2); - if (type == "Color") + if (type == "color") Color = node_mix_color(t, Color1, Color2); - if (type == "Soft Light") + if (type == "soft_light") Color = node_mix_soft(t, Color1, Color2); - if (type == "Linear Light") + if (type == "linear_light") Color = node_mix_linear(t, Color1, Color2); - if (Clamp) + if (use_clamp) Color = node_mix_clamp(Color); } diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl index 4f95dec910a..91f4fba5898 100644 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl @@ -187,7 +187,7 @@ float noise_musgrave_ridged_multi_fractal(point p, float H, float lacunarity, shader node_musgrave_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "fBM", + string type = "fBM", float Dimension = 2.0, float Lacunarity = 1.0, float Detail = 2.0, @@ -210,15 +210,15 @@ shader node_musgrave_texture( p = p * Scale; - if (Type == "Multifractal") + if (type == "multifractal") Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); - else if (Type == "fBM") + else if (type == "fBM") Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves); - else if (Type == "Hybrid Multifractal") + else if (type == "hybrid_multifractal") Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (Type == "Ridged Multifractal") + else if (type == "ridged_multifractal") Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (Type == "Hetero Terrain") + else if (type == "hetero_terrain") Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset); Color = color(Fac, Fac, Fac); diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/shaders/node_normal.osl index 2d04978fc72..7307971eddd 100644 --- a/intern/cycles/kernel/shaders/node_normal.osl +++ b/intern/cycles/kernel/shaders/node_normal.osl @@ -17,12 +17,12 @@ #include "stdosl.h" shader node_normal( - normal Direction = normal(0.0, 0.0, 0.0), + normal direction = normal(0.0, 0.0, 0.0), normal NormalIn = normal(0.0, 0.0, 0.0), output normal NormalOut = normal(0.0, 0.0, 0.0), output float Dot = 1.0) { - NormalOut = normalize(Direction); + NormalOut = normalize(direction); Dot = dot(NormalOut, normalize(NormalIn)); } diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl index 01be566fb20..f95e9fcfe3c 100644 --- a/intern/cycles/kernel/shaders/node_normal_map.osl +++ b/intern/cycles/kernel/shaders/node_normal_map.osl @@ -20,14 +20,14 @@ shader node_normal_map( normal NormalIn = N, float Strength = 1.0, color Color = color(0.5, 0.5, 1.0), - string space = "Tangent", + string space = "tangent", string attr_name = "geom:tangent", string attr_sign_name = "geom:tangent_sign", output normal Normal = NormalIn) { color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5); - if (space == "Tangent") { + if (space == "tangent") { vector tangent; vector ninterp; float tangent_sign; @@ -53,20 +53,20 @@ shader node_normal_map( Normal = normal(0, 0, 0); } } - else if (space == "Object") { + else if (space == "object") { Normal = normalize(transform("object", "world", vector(mcolor))); } - else if (space == "World") { + else if (space == "world") { Normal = normalize(vector(mcolor)); } - else if (space == "Blender Object") { + else if (space == "blender_object") { /* strange blender convention */ mcolor[1] = -mcolor[1]; mcolor[2] = -mcolor[2]; Normal = normalize(transform("object", "world", vector(mcolor))); } - else if (space == "Blender World") { + else if (space == "blender_world") { /* strange blender convention */ mcolor[1] = -mcolor[1]; mcolor[2] = -mcolor[2]; diff --git a/intern/cycles/kernel/shaders/node_ramp_util.h b/intern/cycles/kernel/shaders/node_ramp_util.h new file mode 100644 index 00000000000..917fb65c6df --- /dev/null +++ b/intern/cycles/kernel/shaders/node_ramp_util.h @@ -0,0 +1,89 @@ +/* + * 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. + */ + +/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */ + +color rgb_ramp_lookup(color ramp[], float at, int interpolate, int extrapolate) +{ + float f = at; + int table_size = arraylength(ramp); + + if ((f < 0.0 || f > 1.0) && extrapolate) { + color t0, dy; + if (f < 0.0) { + t0 = ramp[0]; + dy = t0 - ramp[1]; + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(at, 0.0, 1.0) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = (int)f; + if (i < 0) i = 0; + if (i >= table_size) i = table_size - 1; + float t = f - (float)i; + + color result = ramp[i]; + + if (interpolate && t > 0.0) + result = (1.0 - t) * result + t * ramp[i + 1]; + + return result; +} + +float rgb_ramp_lookup(float ramp[], float at, int interpolate, int extrapolate) +{ + float f = at; + int table_size = arraylength(ramp); + + if ((f < 0.0 || f > 1.0) && extrapolate) { + float t0, dy; + if (f < 0.0) { + t0 = ramp[0]; + dy = t0 - ramp[1]; + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(at, 0.0, 1.0) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = (int)f; + if (i < 0) i = 0; + if (i >= table_size) i = table_size - 1; + float t = f - (float)i; + + float result = ramp[i]; + + if (interpolate && t > 0.0) + result = (1.0 - t) * result + t * ramp[i + 1]; + + return result; +} diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl index d458ca730a4..828becf1818 100644 --- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl @@ -18,7 +18,7 @@ shader node_refraction_bsdf( color Color = 0.8, - string distribution = "Sharp", + string distribution = "sharp", float Roughness = 0.2, float IOR = 1.45, normal Normal = N, @@ -27,9 +27,9 @@ shader node_refraction_bsdf( float f = max(IOR, 1e-5); float eta = backfacing() ? 1.0 / f : f; - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * refraction(Normal, eta); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta); diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/shaders/node_rgb_curves.osl index 8e208e8a8f7..c8e7e4f175b 100644 --- a/intern/cycles/kernel/shaders/node_rgb_curves.osl +++ b/intern/cycles/kernel/shaders/node_rgb_curves.osl @@ -14,43 +14,7 @@ * limitations under the License. */ -#include "stdosl.h" -#include "oslutil.h" - -float ramp_lookup(color ramp[], float at, int component) -{ - int table_size = arraylength(ramp); - - if (at < 0.0 || at > 1.0) { - float t0, dy; - if (at < 0.0) { - t0 = ramp[0][component]; - dy = t0 - ramp[1][component]; - at = -at; - } - else { - t0 = ramp[table_size - 1][component]; - dy = t0 - ramp[table_size - 2][component]; - at = at - 1.0; - } - return t0 + dy * at * (table_size - 1); - } - - float f = clamp(at, 0.0, 1.0) * (table_size - 1); - - /* clamp int as well in case of NaN */ - int i = (int)f; - if (i < 0) i = 0; - if (i >= table_size) i = table_size - 1; - float t = f - (float)i; - - float result = ramp[i][component]; - - if (t > 0.0) - result = (1.0 - t) * result + t * ramp[i + 1][component]; - - return result; -} +#include "node_ramp_util.h" shader node_rgb_curves( color ramp[] = {0.0}, @@ -63,9 +27,13 @@ shader node_rgb_curves( { color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x); - ColorOut[0] = ramp_lookup(ramp, c[0], 0); - ColorOut[1] = ramp_lookup(ramp, c[1], 1); - ColorOut[2] = ramp_lookup(ramp, c[2], 2); + color r = rgb_ramp_lookup(ramp, c[0], 1, 1); + color g = rgb_ramp_lookup(ramp, c[0], 1, 1); + color b = rgb_ramp_lookup(ramp, c[0], 1, 1); + + ColorOut[0] = r[0]; + ColorOut[1] = g[1]; + ColorOut[2] = b[2]; ColorOut = mix(ColorIn, ColorOut, Fac); } diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/shaders/node_rgb_ramp.osl index 2ab6b6778b7..24b8728b999 100644 --- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl +++ b/intern/cycles/kernel/shaders/node_rgb_ramp.osl @@ -14,33 +14,18 @@ * limitations under the License. */ -#include "stdosl.h" -#include "oslutil.h" +#include "node_ramp_util.h" shader node_rgb_ramp( color ramp_color[] = {0.0}, float ramp_alpha[] = {0.0}, - int ramp_interpolate = 1, + int interpolate = 1, float Fac = 0.0, output color Color = 0.0, output float Alpha = 1.0) { - int table_size = arraylength(ramp_color); - float f = clamp(Fac, 0.0, 1.0) * (table_size - 1); - - /* clamp int as well in case of NaN */ - int i = (int)f; - if (i < 0) i = 0; - if (i >= table_size) i = table_size - 1; - float t = f - (float)i; - - Color = ramp_color[i]; - Alpha = ramp_alpha[i]; - - if (ramp_interpolate && t > 0.0) { - Color = (1.0 - t) * Color + t * ramp_color[i + 1]; - Alpha = (1.0 - t) * Alpha + t * ramp_alpha[i + 1]; - } + Color = rgb_ramp_lookup(ramp_color, Fac, interpolate, 0); + Alpha = rgb_ramp_lookup(ramp_alpha, Fac, interpolate, 0); } diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl new file mode 100644 index 00000000000..903dfcdc881 --- /dev/null +++ b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include "stdosl.h" + +shader node_rgb_to_bw( + color Color = 0.0, + output float Val = 0.0) +{ + Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; +} + diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl index 05eed23bea8..a6c187d15f2 100644 --- a/intern/cycles/kernel/shaders/node_sky_texture.osl +++ b/intern/cycles/kernel/shaders/node_sky_texture.osl @@ -111,7 +111,7 @@ shader node_sky_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), vector Vector = P, - string sky_model = "Hosek / Wilkie", + string type = "hosek_wilkie", float theta = 0.0, float phi = 0.0, color radiance = color(0.0, 0.0, 0.0), @@ -125,7 +125,7 @@ shader node_sky_texture( if (use_mapping) p = transform(mapping, p); - if (sky_model == "Hosek / Wilkie") + if (type == "hosek_wilkie") Color = sky_radiance_new(p, phi, theta, radiance, config_x, config_y, config_z); else Color = sky_radiance_old(p, phi, theta, radiance, config_x, config_y, config_z); diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl index a67333c5d4e..5ba8f34021d 100644 --- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl +++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl @@ -22,13 +22,13 @@ shader node_subsurface_scattering( vector Radius = vector(0.1, 0.1, 0.1), float TextureBlur = 0.0, float Sharpness = 0.0, - string Falloff = "Cubic", + string falloff = "cubic", normal Normal = N, output closure color BSSRDF = 0) { - if (Falloff == "Gaussian") + if (falloff == "gaussian") BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur); - else if (Falloff == "Cubic") + else if (falloff == "cubic") BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness); else BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color); diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl index 53a47396f9f..c527070a2c8 100644 --- a/intern/cycles/kernel/shaders/node_tangent.osl +++ b/intern/cycles/kernel/shaders/node_tangent.osl @@ -19,24 +19,24 @@ shader node_tangent( normal NormalIn = N, string attr_name = "geom:tangent", - string direction_type = "Radial", - string axis = "Z", + string direction_type = "radial", + string axis = "z", output normal Tangent = normalize(dPdu)) { vector T; - if (direction_type == "UV Map") { + if (direction_type == "uv_map") { getattribute(attr_name, T); } - else if (direction_type == "Radial") { + else if (direction_type == "radial") { point generated; if (!getattribute("geom:generated", generated)) generated = P; - if (axis == "X") + if (axis == "x") T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5)); - else if (axis == "Y") + else if (axis == "y") T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5)); else T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); diff --git a/intern/cycles/kernel/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/shaders/node_toon_bsdf.osl index 75c5d06f847..ae68a463e46 100644 --- a/intern/cycles/kernel/shaders/node_toon_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_toon_bsdf.osl @@ -18,15 +18,15 @@ shader node_toon_bsdf( color Color = 0.8, - string component = "Diffuse", + string component = "diffuse", float Size = 0.5, float Smooth = 0.0, normal Normal = N, output closure color BSDF = 0) { - if (component == "Diffuse") + if (component == "diffuse") BSDF = Color * diffuse_toon(Normal, Size, Smooth); - else if (component == "Glossy") + else if (component == "glossy") BSDF = Color * glossy_toon(Normal, Size, Smooth); } diff --git a/intern/cycles/kernel/shaders/node_uv_map.osl b/intern/cycles/kernel/shaders/node_uv_map.osl index 77e2e8d12d7..b46b2e73457 100644 --- a/intern/cycles/kernel/shaders/node_uv_map.osl +++ b/intern/cycles/kernel/shaders/node_uv_map.osl @@ -18,7 +18,7 @@ shader node_uv_map( int from_dupli = 0, - string name = "", + string attribute = "", string bump_offset = "center", output point UV = point(0.0, 0.0, 0.0)) { @@ -26,10 +26,10 @@ shader node_uv_map( getattribute("geom:dupli_uv", UV); } else { - if (name == "") + if (attribute == "") getattribute("geom:uv", UV); else - getattribute(name, UV); + getattribute(attribute, UV); } if (bump_offset == "dx") { diff --git a/intern/cycles/kernel/shaders/node_vector_curves.osl b/intern/cycles/kernel/shaders/node_vector_curves.osl index cff4efe1d98..d92fa11d439 100644 --- a/intern/cycles/kernel/shaders/node_vector_curves.osl +++ b/intern/cycles/kernel/shaders/node_vector_curves.osl @@ -14,43 +14,7 @@ * limitations under the License. */ -#include "stdosl.h" -#include "oslutil.h" - -float ramp_lookup(color ramp[], float at, int component) -{ - int table_size = arraylength(ramp); - - if (at < 0.0 || at > 1.0) { - float t0, dy; - if (at < 0.0) { - t0 = ramp[0][component]; - dy = t0 - ramp[1][component]; - at = -at; - } - else { - t0 = ramp[table_size - 1][component]; - dy = t0 - ramp[table_size - 2][component]; - at = at - 1.0; - } - return t0 + dy * at * (table_size - 1); - } - - float f = clamp(at, 0.0, 1.0) * (table_size - 1); - - /* clamp int as well in case of NaN */ - int i = (int)f; - if (i < 0) i = 0; - if (i >= table_size) i = table_size - 1; - float t = f - (float)i; - - float result = ramp[i][component]; - - if (t > 0.0) - result = (1.0 - t) * result + t * ramp[i + 1][component]; - - return result; -} +#include "node_ramp_util.h" shader node_vector_curves( color ramp[] = {0.0}, @@ -63,9 +27,13 @@ shader node_vector_curves( { vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x); - VectorOut[0] = ramp_lookup(ramp, c[0], 0); - VectorOut[1] = ramp_lookup(ramp, c[1], 1); - VectorOut[2] = ramp_lookup(ramp, c[2], 2); + color r = rgb_ramp_lookup(ramp, c[0], 1, 1); + color g = rgb_ramp_lookup(ramp, c[0], 1, 1); + color b = rgb_ramp_lookup(ramp, c[0], 1, 1); + + VectorOut[0] = r[0]; + VectorOut[1] = g[1]; + VectorOut[2] = b[2]; VectorOut = mix(VectorIn, VectorOut, Fac); } diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl index f83412dc0f7..a7e3637402e 100644 --- a/intern/cycles/kernel/shaders/node_vector_math.osl +++ b/intern/cycles/kernel/shaders/node_vector_math.osl @@ -17,33 +17,33 @@ #include "stdosl.h" shader node_vector_math( - string type = "Add", + string type = "add", vector Vector1 = vector(0.0, 0.0, 0.0), vector Vector2 = vector(0.0, 0.0, 0.0), output float Value = 0.0, output vector Vector = vector(0.0, 0.0, 0.0)) { - if (type == "Add") { + if (type == "add") { Vector = Vector1 + Vector2; Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } - else if (type == "Subtract") { + else if (type == "subtract") { Vector = Vector1 - Vector2; Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } - else if (type == "Average") { + else if (type == "average") { Value = length(Vector1 + Vector2); Vector = normalize(Vector1 + Vector2); } - else if (type == "Dot Product") { + else if (type == "dot_product") { Value = dot(Vector1, Vector2); } - else if (type == "Cross Product") { + else if (type == "cross_product") { vector c = cross(Vector1, Vector2); Value = length(c); Vector = normalize(c); } - else if (type == "Normalize") { + else if (type == "normalize") { Value = length(Vector1); Vector = normalize(Vector1); } diff --git a/intern/cycles/kernel/shaders/node_vector_transform.osl b/intern/cycles/kernel/shaders/node_vector_transform.osl index 8ebaa31ab25..afb95b340d1 100644 --- a/intern/cycles/kernel/shaders/node_vector_transform.osl +++ b/intern/cycles/kernel/shaders/node_vector_transform.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_vector_transform( - string type = "Vector", + string type = "vector", string convert_from = "world", string convert_to = "object", vector VectorIn = vector(0.0, 0.0, 0.0), output vector VectorOut = vector(0.0, 0.0, 0.0)) { - if (type == "Vector" || type == "Normal") { + if (type == "vector" || type == "normal") { VectorOut = transform(convert_from, convert_to, VectorIn); - if (type == "Normal") + if (type == "normal") VectorOut = normalize(VectorOut); } - else if (type == "Point") { + else if (type == "point") { point Point = (point)VectorIn; VectorOut = transform(convert_from, convert_to, Point); } diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl index 29e143ae207..0c3b95ae4d0 100644 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl @@ -22,7 +22,7 @@ shader node_voronoi_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Coloring = "Intensity", + string coloring = "intensity", float Scale = 5.0, point Vector = P, output float Fac = 0.0, @@ -40,7 +40,7 @@ shader node_voronoi_texture( voronoi(p * Scale, 1.0, da, pa); /* Colored output */ - if (Coloring == "Intensity") { + if (coloring == "intensity") { Fac = fabs(da[0]); Color = color(Fac); } diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl index 59f61d3b46a..71bc9324705 100644 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ b/intern/cycles/kernel/shaders/node_wave_texture.osl @@ -23,10 +23,10 @@ float wave(point p, string type, string profile, float detail, float distortion, { float n = 0.0; - if (type == "Bands") { + if (type == "bands") { n = (p[0] + p[1] + p[2]) * 10.0; } - else if (type == "Rings") { + else if (type == "rings") { n = length(p) * 20.0; } @@ -34,7 +34,7 @@ float wave(point p, string type, string profile, float detail, float distortion, n = n + (distortion * noise_turbulence(p * dscale, detail, 0)); } - if (profile == "Sine") { + if (profile == "sine") { return 0.5 + 0.5 * sin(n); } else { @@ -48,8 +48,8 @@ float wave(point p, string type, string profile, float detail, float distortion, shader node_wave_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string Type = "Bands", - string Profile = "Sine", + string type = "bands", + string profile = "sine", float Scale = 5.0, float Distortion = 0.0, float Detail = 2.0, @@ -63,7 +63,7 @@ shader node_wave_texture( if (use_mapping) p = transform(mapping, p); - Fac = wave(p * Scale, Type, Profile, Detail, Distortion, DetailScale); + Fac = wave(p * Scale, type, profile, Detail, Distortion, DetailScale); Color = Fac; } diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index ba88f0f4a79..fc0b94bfdce 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -527,6 +527,9 @@ closure color transparent() BUILTIN; closure color microfacet_ggx(normal N, float ag) BUILTIN; closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index e816a818915..cef64bf5f36 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval( isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); } } diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h index e1c7e2cea99..88d6dab04d0 100644 --- a/intern/cycles/kernel/split/kernel_split_common.h +++ b/intern/cycles/kernel/split/kernel_split_common.h @@ -31,6 +31,7 @@ #include "kernel_camera.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_accumulate.h" #include "kernel_shader.h" diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 543e31bcb35..502994e71f1 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -142,6 +142,7 @@ CCL_NAMESPACE_END #include "svm_noise.h" #include "svm_texture.h" +#include "svm_color_util.h" #include "svm_math_util.h" #include "svm_attribute.h" @@ -404,10 +405,8 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a #if NODES_GROUP(NODE_GROUP_LEVEL_3) case NODE_RGB_CURVES: - svm_node_rgb_curves(kg, sd, stack, node, &offset); - break; case NODE_VECTOR_CURVES: - svm_node_vector_curves(kg, sd, stack, node, &offset); + svm_node_curves(kg, sd, stack, node, &offset); break; case NODE_TANGENT: svm_node_tangent(kg, sd, stack, node); diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index 63bbb27d873..6c557684099 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -28,9 +28,7 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, /* find attribute by unique id */ uint id = node.y; uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride; -#ifdef __HAIR__ - attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; -#endif + attr_offset += attribute_primitive_type(kg, sd); uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); while(attr_map.x != id) { diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h index e4d545a00ae..d71b0ee0b61 100644 --- a/intern/cycles/kernel/svm/svm_brightness.h +++ b/intern/cycles/kernel/svm/svm_brightness.h @@ -25,12 +25,7 @@ ccl_device void svm_node_brightness(ShaderData *sd, float *stack, uint in_color, float brightness = stack_load_float(stack, bright_offset); float contrast = stack_load_float(stack, contrast_offset); - float a = 1.0f + contrast; - float b = brightness - contrast*0.5f; - - color.x = max(a*color.x + b, 0.0f); - color.y = max(a*color.y + b, 0.0f); - color.z = max(a*color.z + b, 0.0f); + color = svm_brightness_contrast(color, brightness, contrast); if(stack_valid(out_color)) stack_store_float3(stack, out_color, color); diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 6161bc5d914..2f886308a64 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -18,104 +18,44 @@ CCL_NAMESPACE_BEGIN /* Closure Nodes */ -ccl_device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract) +ccl_device void svm_node_glass_setup(ShaderData *sd, MicrofacetBsdf *bsdf, int type, float eta, float roughness, bool refract) { if(type == CLOSURE_BSDF_SHARP_GLASS_ID) { if(refract) { - sc->data0 = eta; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc); + bsdf->alpha_y = 0.0f; + bsdf->alpha_x = 0.0f; + bsdf->ior = eta; + ccl_fetch(sd, flag) |= bsdf_refraction_setup(bsdf); } else { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc); + bsdf->alpha_y = 0.0f; + bsdf->alpha_x = 0.0f; + bsdf->ior = 0.0f; + ccl_fetch(sd, flag) |= bsdf_reflection_setup(bsdf); } } else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) { - sc->data0 = roughness; - sc->data1 = roughness; - sc->data2 = eta; + bsdf->alpha_x = roughness; + bsdf->alpha_y = roughness; + bsdf->ior = eta; if(refract) - ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(bsdf); else - ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(bsdf); } else { - sc->data0 = roughness; - sc->data1 = roughness; - sc->data2 = eta; + bsdf->alpha_x = roughness; + bsdf->alpha_y = roughness; + bsdf->ior = eta; if(refract) - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(bsdf); else - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(bsdf); } } -ccl_device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, ClosureType type, float mix_weight) -{ - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - - if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - sc->weight *= mix_weight; - sc->type = type; - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; -#ifdef __OSL__ - sc->prim = NULL; -#endif - ccl_fetch(sd, num_closure)++; - return sc; - } - - return NULL; -} - -ccl_device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float mix_weight) -{ - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - - float3 weight = sc->weight * mix_weight; - float sample_weight = fabsf(average(weight)); - - if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - sc->weight = weight; - sc->sample_weight = sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif - return sc; - } - - return NULL; -} - -ccl_device_inline ShaderClosure *svm_node_closure_get_absorption(ShaderData *sd, float mix_weight) -{ - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - - float3 weight = (make_float3(1.0f, 1.0f, 1.0f) - sc->weight) * mix_weight; - float sample_weight = fabsf(average(weight)); - - if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - sc->weight = weight; - sc->sample_weight = sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif - return sc; - } - - return NULL; -} - ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int path_flag, int *offset) { uint type, param1_offset, param2_offset; @@ -136,17 +76,13 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w); switch(type) { -#ifndef __SPLIT_KERNEL__ -# define sc_next(sc) sc++ -#else -# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)) -#endif case CLOSURE_BSDF_DISNEY_ID: { uint specular_offset, roughness_offset, specularTint_offset, anisotropic_offset, sheen_offset, sheenTint_offset, clearcoat_offset, clearcoatGloss_offset, eta_offset, transparency_offset, refr_roughness_offset; uint tmp0; uint4 data_node2 = read_node(kg, offset); + float3 T = stack_load_float3(stack, data_node.y); decode_node_uchar4(data_node.z, &specular_offset, &roughness_offset, &specularTint_offset, &anisotropic_offset); decode_node_uchar4(data_node.w, &sheen_offset, &sheenTint_offset, &clearcoat_offset, &clearcoatGloss_offset); decode_node_uchar4(data_node2.x, &eta_offset, &transparency_offset, &refr_roughness_offset, &tmp0); @@ -167,7 +103,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * refr_roughness = 1.0f - (1.0f - roughness) * (1.0f - refr_roughness); float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); - eta = (ccl_fetch(sd, flag) & SD_BACKFACING) ? 1.0f / eta : eta; + float ior = (ccl_fetch(sd, flag) & SD_BACKFACING) ? 1.0f / eta : eta; // calculate fresnel for refraction float cosNO = dot(N, ccl_fetch(sd, I)); @@ -193,8 +129,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float3 subsurfaceColor = stack_valid(data_subsurface_color.x) ? stack_load_float3(stack, data_subsurface_color.x) : make_float3(__uint_as_float(data_subsurface_color.y), __uint_as_float(data_subsurface_color.z), __uint_as_float(data_subsurface_color.w)); - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - float3 weight = sc->weight * mix_weight; + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; #ifdef __SUBSURFACE__ float3 albedo = subsurfaceColor; //baseColor; @@ -207,7 +142,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) subsurface = 0.0f; - if (subsurf_sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) + 2 < MAX_CLOSURE) { + if (subsurf_sample_weight > CLOSURE_WEIGHT_CUTOFF) { /* radius * scale */ float3 radius = make_float3(1.0f, 1.0f, 1.0f) * subsurface; /* sharpness */ @@ -216,317 +151,251 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float texture_blur = 0.0f; /* create one closure per color channel */ - if (fabsf(subsurf_weight.x) > 0.0f) { - sc->weight = make_float3(subsurf_weight.x, 0.0f, 0.0f); - sc->sample_weight = subsurf_sample_weight; - sc->data0 = radius.x; - sc->data1 = texture_blur; - sc->data2 = albedo.x; - sc->data3 = roughness; - sc->T.x = sharpness; - sc->color0 = baseColor; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(subsurf_weight.x, 0.0f, 0.0f)); + if (bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.x; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.x; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->baseColor = baseColor; + bssrdf->roughness = roughness; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); } - if (fabsf(subsurf_weight.y) > 0.0f) { - sc->weight = make_float3(0.0f, subsurf_weight.y, 0.0f); - sc->sample_weight = subsurf_sample_weight; - sc->data0 = radius.y; - sc->data1 = texture_blur; - sc->data2 = albedo.y; - sc->data3 = roughness; - sc->T.x = sharpness; - sc->color0 = baseColor; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, subsurf_weight.y, 0.0f)); + if (bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.y; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.y; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->baseColor = baseColor; + bssrdf->roughness = roughness; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); } - if (fabsf(subsurf_weight.z) > 0.0f) { - sc->weight = make_float3(0.0f, 0.0f, subsurf_weight.z); - sc->sample_weight = subsurf_sample_weight; - sc->data0 = radius.z; - sc->data1 = texture_blur; - sc->data2 = albedo.z; - sc->data3 = roughness; - sc->T.x = sharpness; - sc->color0 = baseColor; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, subsurf_weight.z)); + if (bssrdf) { + bssrdf->sample_weight = subsurf_sample_weight; + bssrdf->radius = radius.z; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.z; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + bssrdf->baseColor = baseColor; + bssrdf->roughness = roughness; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_DISNEY_ID); } } #else /* diffuse */ if (diffuse_weight > 0.0f) { - if (ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - float3 diff_weight = weight * diffuse_weight; - float diff_sample_weight = fabsf(average(diff_weight)); - - if (diff_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = diff_weight; - sc->sample_weight = diff_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif + float3 diff_weight = weight * diffuse_weight; + float diff_sample_weight = fabsf(average(diff_weight)); - sc->N = N; + DisneyDiffuseBsdf *bsdf = (DisneyDiffuseBsdf*)bsdf_alloc(sd, sizeof(DisneyDiffuseBsdf), diff_weight); - sc->color0 = baseColor; - sc->data0 = roughness; + if (bsdf) { + bsdf->N = N; + bsdf->baseColor = baseColor; + bsdf->roughness = roughness; - ccl_fetch(sd, flag) |= bsdf_disney_diffuse_setup(sc); - sc_next(sc); - } + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_disney_diffuse_setup(bsdf); } } #endif /* sheen */ if (diffuse_weight > 0.0f && sheen != 0.0f) { - if (ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - float3 sheen_weight = weight * diffuse_weight; - float sheen_sample_weight = fabsf(average(sheen_weight)); - - if (sheen_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = sheen_weight; - sc->sample_weight = sheen_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif + float3 sheen_weight = weight * diffuse_weight; + float sheen_sample_weight = fabsf(average(sheen_weight)); - sc->N = N; + DisneySheenBsdf *bsdf = (DisneySheenBsdf*)bsdf_alloc(sd, sizeof(DisneySheenBsdf), weight); - sc->color0 = baseColor; - sc->data0 = sheen; - sc->data1 = sheenTint; + if (bsdf) { + bsdf->N = N; + bsdf->baseColor = baseColor; + bsdf->sheen = sheen; + bsdf->sheenTint = sheenTint; - ccl_fetch(sd, flag) |= bsdf_disney_sheen_setup(sc); - sc_next(sc); - } - } + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_disney_sheen_setup(bsdf); + } } /* specular reflection */ - if (specular != 0.0f || metallic != 0.0f) { - if (ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - float3 spec_weight = weight * specular_weight; - float spec_sample_weight = fabsf(average(spec_weight)); - - if (spec_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = spec_weight; - sc->sample_weight = spec_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; +#ifdef __CAUSTICS_TRICKS__ + if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { #endif + if (specular != 0.0f || metallic != 0.0f) { + float3 spec_weight = weight * specular_weight; - sc->N = N; - sc->T = stack_load_float3(stack, data_node.y); + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), spec_weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); - sc->color0 = baseColor; - sc->data0 = metallic; - sc->data1 = specular; // (1.0f - transparency) * specular + transparency * specular * 12.5f/* equals division by 0.08f */; - sc->data2 = specularTint; - sc->data3 = roughness; - sc->data4 = anisotropic; + if (bsdf && extra) { + bsdf->N = N; + bsdf->ior = 0.0f; + bsdf->T = T; + bsdf->extra = extra; - ccl_fetch(sd, flag) |= bsdf_disney_specular_setup(sc); - sc_next(sc); - } - } - } + float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); + float r2 = roughness * roughness; - /* BSDF */ - if (specular_weight < 1.0f) { - if (ccl_fetch(sd, num_closure) + 1 < MAX_CLOSURE) { -#ifdef __CAUSTICS_TRICKS__ - if (!kernel_data.integrator.caustics_reflective && - !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) - { - break; - } -#endif + bsdf->alpha_x = fmaxf(0.001f, r2 / aspect); + bsdf->alpha_y = fmaxf(0.001f, r2 * aspect); - /* reflection */ - float3 spec_refl_weight = weight * (1.0f - specular_weight) * fresnel; - float spec_refl_sample_weight = fabsf(average(spec_refl_weight)); + float m_cdlum = 0.3f * baseColor.x + 0.6f * baseColor.y + 0.1f * baseColor.z; // luminance approx. + float3 m_ctint = m_cdlum > 0.0f ? baseColor / m_cdlum : make_float3(0.0f, 0.0f, 0.0f); // normalize lum. to isolate hue+sat + float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specularTint) + m_ctint * specularTint; - if (spec_refl_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = spec_refl_weight; - sc->sample_weight = spec_refl_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif + bsdf->extra->cspec0 = (specular * 0.08f * tmp_col) * (1.0f - metallic) + baseColor * metallic; + bsdf->extra->color = baseColor; -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) + /* setup bsdf */ +#ifdef __DISNEY_SPECULAR_MULTI_GGX__ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(bsdf, true); +#else + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(bsdf, true); #endif - { - sc->N = N; - sc->T = stack_load_float3(stack, data_node.y); - - sc->color0 = baseColor; - sc->data0 = 0.0f; - sc->data1 = 12.5f; // == (1.0f / 0.08f) - sc->data2 = specularTint; - sc->data3 = roughness; - sc->data4 = 0.0f; - - ccl_fetch(sd, flag) |= bsdf_disney_specular_setup(sc); - sc_next(sc); - } } + } +#ifdef __CAUSTICS_TRICKS__ + } +#endif + /* BSDF */ #ifdef __CAUSTICS_TRICKS__ - if (!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) - break; + if (kernel_data.integrator.caustics_reflective || kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) { #endif + if (specular_weight < 1.0f) { + float3 glass_weight = baseColor * weight * (1.0f - specular_weight); - /* refraction */ - float3 spec_refr_weight = baseColor * weight * (1.0f - specular_weight) * (1.0f - fresnel); - float spec_refr_sample_weight = fabsf(average(spec_refr_weight)); + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), glass_weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); - if (spec_refr_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = spec_refr_weight; - sc->sample_weight = spec_refr_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif + if (bsdf && extra) { + bsdf->N = N; + bsdf->extra = extra; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); - sc->N = N; + bsdf->alpha_x = refr_roughness * refr_roughness; + bsdf->alpha_y = refr_roughness * refr_roughness; + bsdf->ior = ior; - sc->data0 = refr_roughness * refr_roughness; - sc->data1 = refr_roughness * refr_roughness; - sc->data2 = eta; + bsdf->extra->color = baseColor; - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc); - sc_next(sc); + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); } } +#ifdef __CAUSTICS_TRICKS__ } +#endif /* clearcoat */ - if (clearcoat > 0.0f) { - if (ccl_fetch(sd, num_closure) < MAX_CLOSURE) { +#ifdef __CAUSTICS_TRICKS__ + if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { +#endif + if (clearcoat > 0.0f) { float3 clearcoat_weight = weight; float clearcoat_sample_weight = fabsf(average(clearcoat_weight)); - if (clearcoat_sample_weight > CLOSURE_WEIGHT_CUTOFF) { - sc->weight = clearcoat_weight; - sc->sample_weight = clearcoat_sample_weight; - ccl_fetch(sd, num_closure)++; -#ifdef __OSL__ - sc->prim = NULL; -#endif - - sc->N = CN; + DisneyClearcoatBsdf *bsdf = (DisneyClearcoatBsdf*)bsdf_alloc(sd, sizeof(DisneyClearcoatBsdf), clearcoat_weight); - sc->data0 = clearcoat; - sc->data1 = clearcoatGloss; + if (bsdf) { + bsdf->N = CN; + bsdf->clearcoat = clearcoat; + bsdf->clearcoatGloss = clearcoatGloss; - ccl_fetch(sd, flag) |= bsdf_disney_clearcoat_setup(sc); - sc_next(sc); + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_disney_clearcoat_setup(bsdf); } } +#ifdef __CAUSTICS_TRICKS__ } +#endif break; } -#undef sc_next case CLOSURE_BSDF_DIFFUSE_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + OrenNayarBsdf *bsdf = (OrenNayarBsdf*)bsdf_alloc(sd, sizeof(OrenNayarBsdf), weight); - if(sc) { - sc->N = N; + if(bsdf) { + bsdf->N = N; float roughness = param1; if(roughness == 0.0f) { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_diffuse_setup(sc); + ccl_fetch(sd, flag) |= bsdf_diffuse_setup((DiffuseBsdf*)bsdf); } else { - sc->data0 = roughness; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_oren_nayar_setup(sc); + bsdf->roughness = roughness; + ccl_fetch(sd, flag) |= bsdf_oren_nayar_setup(bsdf); } } break; } case CLOSURE_BSDF_TRANSLUCENT_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight); - if(sc) { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - sc->N = N; - ccl_fetch(sd, flag) |= bsdf_translucent_setup(sc); + if(bsdf) { + bsdf->N = N; + ccl_fetch(sd, flag) |= bsdf_translucent_setup(bsdf); } break; } case CLOSURE_BSDF_TRANSPARENT_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight); - if(sc) { - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - sc->N = N; - ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc); + if(bsdf) { + ccl_fetch(sd, flag) |= bsdf_transparent_setup(bsdf); } break; } case CLOSURE_BSDF_REFLECTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: { + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight); - if(sc) { - sc->N = N; - sc->data0 = param1; - sc->data1 = param1; - sc->data2 = 0.0f; + if(bsdf) { + bsdf->N = N; + bsdf->alpha_x = param1; + bsdf->alpha_y = param1; + bsdf->ior = 0.0f; + bsdf->extra = NULL; /* setup bsdf */ if(type == CLOSURE_BSDF_REFLECTION_ID) - ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc); + ccl_fetch(sd, flag) |= bsdf_reflection_setup(bsdf); else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) - ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(bsdf); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID) - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(bsdf); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { + kernel_assert(stack_valid(data_node.z)); + bsdf->extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf->extra) { + bsdf->extra->color = stack_load_float3(stack, data_node.z); + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(bsdf); + } + } else - ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc); + ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(bsdf); } break; @@ -538,31 +407,33 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * if(!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight); - if(sc) { - sc->N = N; + if(bsdf) { + bsdf->N = N; + bsdf->extra = NULL; float eta = fmaxf(param2, 1e-5f); eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta; /* setup bsdf */ if(type == CLOSURE_BSDF_REFRACTION_ID) { - sc->data0 = eta; - sc->data1 = 0.0f; - sc->data2 = 0.0f; + bsdf->alpha_x = 0.0f; + bsdf->alpha_y = 0.0f; + bsdf->ior = eta; - ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc); + ccl_fetch(sd, flag) |= bsdf_refraction_setup(bsdf); } else { - sc->data0 = param1; - sc->data1 = param1; - sc->data2 = eta; + bsdf->alpha_x = param1; + bsdf->alpha_y = param1; + bsdf->ior = eta; if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) - ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(bsdf); else - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc); + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(bsdf); } } @@ -578,7 +449,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } #endif - int num_closure = ccl_fetch(sd, num_closure); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; /* index of refraction */ float eta = fmaxf(param2, 1e-5f); @@ -590,164 +461,193 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float roughness = param1; /* reflection */ - ShaderClosure *sc = ccl_fetch_array(sd, closure, num_closure); - float3 weight = sc->weight; - float sample_weight = sc->sample_weight; - - sc = svm_node_closure_get_bsdf(sd, mix_weight*fresnel); #ifdef __CAUSTICS_TRICKS__ if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) #endif { - if(sc) { - sc->N = N; - svm_node_glass_setup(sd, sc, type, eta, roughness, false); + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight*fresnel); + + if(bsdf) { + bsdf->N = N; + bsdf->extra = NULL; + svm_node_glass_setup(sd, bsdf, type, eta, roughness, false); } } + /* refraction */ #ifdef __CAUSTICS_TRICKS__ - if(!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) + if(kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) +#endif + { + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight*(1.0f - fresnel)); + + if(bsdf) { + bsdf->N = N; + bsdf->extra = NULL; + svm_node_glass_setup(sd, bsdf, type, eta, roughness, true); + } + } + + break; + } + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) break; #endif + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight); + MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); - /* refraction */ - if(num_closure + 1 < MAX_CLOSURE) { - sc = ccl_fetch_array(sd, closure, num_closure + 1); - sc->weight = weight; - sc->sample_weight = sample_weight; + if(bsdf && extra) { + bsdf->N = N; + bsdf->extra = extra; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); - sc = svm_node_closure_get_bsdf(sd, mix_weight*(1.0f - fresnel)); + bsdf->alpha_x = param1; + bsdf->alpha_y = param1; + float eta = fmaxf(param2, 1e-5f); + bsdf->ior = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta; - if(sc) { - sc->N = N; - svm_node_glass_setup(sd, sc, type, eta, roughness, true); - } + kernel_assert(stack_valid(data_node.z)); + bsdf->extra->color = stack_load_float3(stack, data_node.z); + + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); } break; } case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID: case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); - - if(sc) { - sc->N = N; + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight); - sc->T = stack_load_float3(stack, data_node.y); + if(bsdf) { + bsdf->N = N; + bsdf->extra = NULL; + bsdf->T = stack_load_float3(stack, data_node.y); /* rotate tangent */ float rotation = stack_load_float(stack, data_node.z); if(rotation != 0.0f) - sc->T = rotate_around_axis(sc->T, sc->N, rotation * M_2PI_F); + bsdf->T = rotate_around_axis(bsdf->T, bsdf->N, rotation * M_2PI_F); /* compute roughness */ float roughness = param1; float anisotropy = clamp(param2, -0.99f, 0.99f); if(anisotropy < 0.0f) { - sc->data0 = roughness/(1.0f + anisotropy); - sc->data1 = roughness*(1.0f + anisotropy); + bsdf->alpha_x = roughness/(1.0f + anisotropy); + bsdf->alpha_y = roughness*(1.0f + anisotropy); } else { - sc->data0 = roughness*(1.0f - anisotropy); - sc->data1 = roughness/(1.0f - anisotropy); + bsdf->alpha_x = roughness*(1.0f - anisotropy); + bsdf->alpha_y = roughness/(1.0f - anisotropy); } - sc->data2 = 0.0f; + bsdf->ior = 0.0f; - if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID) - ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc); - else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) - ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc); + if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID) { + ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(bsdf); + } + else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) { + ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(bsdf); + } + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) { + kernel_assert(stack_valid(data_node.w)); + bsdf->extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); + if(bsdf->extra) { + bsdf->extra->color = stack_load_float3(stack, data_node.w); + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(bsdf); + } + } else - ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc); + ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(bsdf); } break; } case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + VelvetBsdf *bsdf = (VelvetBsdf*)bsdf_alloc(sd, sizeof(VelvetBsdf), weight); - if(sc) { - sc->N = N; + if(bsdf) { + bsdf->N = N; - /* sigma */ - sc->data0 = saturate(param1); - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_ashikhmin_velvet_setup(sc); + bsdf->sigma = saturate(param1); + ccl_fetch(sd, flag) |= bsdf_ashikhmin_velvet_setup(bsdf); } break; } - case CLOSURE_BSDF_DIFFUSE_TOON_ID: - case CLOSURE_BSDF_GLOSSY_TOON_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); - - if(sc) { - /* Normal, Size and Smooth */ - sc->N = N; - sc->data0 = param1; - sc->data1 = param2; - sc->data2 = 0.0f; + case CLOSURE_BSDF_GLOSSY_TOON_ID: +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + case CLOSURE_BSDF_DIFFUSE_TOON_ID: { + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; + ToonBsdf *bsdf = (ToonBsdf*)bsdf_alloc(sd, sizeof(ToonBsdf), weight); + + if(bsdf) { + bsdf->N = N; + bsdf->size = param1; + bsdf->smooth = param2; if(type == CLOSURE_BSDF_DIFFUSE_TOON_ID) - ccl_fetch(sd, flag) |= bsdf_diffuse_toon_setup(sc); + ccl_fetch(sd, flag) |= bsdf_diffuse_toon_setup(bsdf); else - ccl_fetch(sd, flag) |= bsdf_glossy_toon_setup(sc); + ccl_fetch(sd, flag) |= bsdf_glossy_toon_setup(bsdf); } break; } #ifdef __HAIR__ case CLOSURE_BSDF_HAIR_REFLECTION_ID: case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: { + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; if(ccl_fetch(sd, flag) & SD_BACKFACING && ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + ShaderClosure *bsdf = bsdf_alloc(sd, sizeof(ShaderClosure), weight); - if(sc) { + if(bsdf) { /* todo: giving a fixed weight here will cause issues when * mixing multiple BSDFS. energy will not be conserved and * the throughput can blow up after multiple bounces. we * better figure out a way to skip backfaces from rays * spawned by transmission from the front */ - sc->weight = make_float3(1.0f, 1.0f, 1.0f); - sc->N = N; - sc->data0 = 0.0f; - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc); + bsdf->weight = make_float3(1.0f, 1.0f, 1.0f); + ccl_fetch(sd, flag) |= bsdf_transparent_setup(bsdf); } } else { - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - sc = svm_node_closure_get_bsdf(sd, mix_weight); + HairBsdf *bsdf = (HairBsdf*)bsdf_alloc(sd, sizeof(HairBsdf), weight); - if(sc) { - sc->N = N; - sc->data0 = param1; - sc->data1 = param2; - sc->data2 = -stack_load_float(stack, data_node.z); + if(bsdf) { + bsdf->roughness1 = param1; + bsdf->roughness2 = param2; + bsdf->offset = -stack_load_float(stack, data_node.z); if(stack_valid(data_node.y)) { - sc->T = normalize(stack_load_float3(stack, data_node.y)); + bsdf->T = normalize(stack_load_float3(stack, data_node.y)); } else if(!(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)) { - sc->T = normalize(ccl_fetch(sd, dPdv)); - sc->data2 = 0.0f; + bsdf->T = normalize(ccl_fetch(sd, dPdv)); + bsdf->offset = 0.0f; } else - sc->T = normalize(ccl_fetch(sd, dPdu)); + bsdf->T = normalize(ccl_fetch(sd, dPdu)); if(type == CLOSURE_BSDF_HAIR_REFLECTION_ID) { - ccl_fetch(sd, flag) |= bsdf_hair_reflection_setup(sc); + ccl_fetch(sd, flag) |= bsdf_hair_reflection_setup(bsdf); } else { - ccl_fetch(sd, flag) |= bsdf_hair_transmission_setup(sc); + ccl_fetch(sd, flag) |= bsdf_hair_transmission_setup(bsdf); } } } @@ -757,17 +657,11 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * #endif #ifdef __SUBSURFACE__ -# ifndef __SPLIT_KERNEL__ -# define sc_next(sc) sc++ -# else -# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)) -# endif case CLOSURE_BSSRDF_CUBIC_ID: case CLOSURE_BSSRDF_GAUSSIAN_ID: case CLOSURE_BSSRDF_BURLEY_ID: { - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - float3 albedo = sc->weight; - float3 weight = sc->weight * mix_weight; + float3 albedo = ccl_fetch(sd, svm_closure_weight); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight; float sample_weight = fabsf(average(weight)); /* disable in case of diffuse ancestor, can't see it well then and @@ -776,7 +670,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) param1 = 0.0f; - if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure)+2 < MAX_CLOSURE) { + if(sample_weight > CLOSURE_WEIGHT_CUTOFF) { /* radius * scale */ float3 radius = stack_load_float3(stack, data_node.z)*param1; /* sharpness */ @@ -785,61 +679,42 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float texture_blur = param2; /* create one closure per color channel */ - if(fabsf(weight.x) > 0.0f) { - sc->weight = make_float3(weight.x, 0.0f, 0.0f); - sc->sample_weight = sample_weight; - sc->data0 = radius.x; - sc->data1 = texture_blur; - sc->data2 = albedo.x; - sc->T.x = sharpness; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(weight.x, 0.0f, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.x; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.x; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); } - if(fabsf(weight.y) > 0.0f) { - sc->weight = make_float3(0.0f, weight.y, 0.0f); - sc->sample_weight = sample_weight; - sc->data0 = radius.y; - sc->data1 = texture_blur; - sc->data2 = albedo.y; - sc->T.x = sharpness; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, weight.y, 0.0f)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.y; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.y; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); } - if(fabsf(weight.z) > 0.0f) { - sc->weight = make_float3(0.0f, 0.0f, weight.z); - sc->sample_weight = sample_weight; - sc->data0 = radius.z; - sc->data1 = texture_blur; - sc->data2 = albedo.z; - sc->T.x = sharpness; -# ifdef __OSL__ - sc->prim = NULL; -# endif - sc->N = N; - ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type); - - ccl_fetch(sd, num_closure)++; - sc_next(sc); + bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, weight.z)); + if(bssrdf) { + bssrdf->sample_weight = sample_weight; + bssrdf->radius = radius.z; + bssrdf->texture_blur = texture_blur; + bssrdf->albedo = albedo.z; + bssrdf->sharpness = sharpness; + bssrdf->N = N; + ccl_fetch(sd, flag) |= bssrdf_setup(bssrdf, (ClosureType)type); } } break; } -# undef sc_next #endif default: break; @@ -864,7 +739,8 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float switch(type) { case CLOSURE_VOLUME_ABSORPTION_ID: { - ShaderClosure *sc = svm_node_closure_get_absorption(sd, mix_weight * density); + float3 weight = (make_float3(1.0f, 1.0f, 1.0f) - ccl_fetch(sd, svm_closure_weight)) * mix_weight * density; + ShaderClosure *sc = closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_NONE_ID, weight); if(sc) { ccl_fetch(sd, flag) |= volume_absorption_setup(sc); @@ -872,13 +748,12 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float break; } case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: { - ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight * density); + float3 weight = ccl_fetch(sd, svm_closure_weight) * mix_weight * density; + HenyeyGreensteinVolume *volume = (HenyeyGreensteinVolume*)bsdf_alloc(sd, sizeof(HenyeyGreensteinVolume), weight); - if(sc) { - sc->data0 = param2; /* g */ - sc->data1 = 0.0f; - sc->data2 = 0.0f; - ccl_fetch(sd, flag) |= volume_henyey_greenstein_setup(sc); + if(volume) { + volume->g = param2; /* g */ + ccl_fetch(sd, flag) |= volume_henyey_greenstein_setup(volume); } break; } @@ -898,10 +773,10 @@ ccl_device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 no if(mix_weight == 0.0f) return; - svm_node_closure_get_non_bsdf(sd, CLOSURE_EMISSION_ID, mix_weight); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight); } else - svm_node_closure_get_non_bsdf(sd, CLOSURE_EMISSION_ID, 1.0f); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_EMISSION_ID, ccl_fetch(sd, svm_closure_weight)); ccl_fetch(sd, flag) |= SD_EMISSION; } @@ -916,10 +791,10 @@ ccl_device void svm_node_closure_background(ShaderData *sd, float *stack, uint4 if(mix_weight == 0.0f) return; - svm_node_closure_get_non_bsdf(sd, CLOSURE_BACKGROUND_ID, mix_weight); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight); } else - svm_node_closure_get_non_bsdf(sd, CLOSURE_BACKGROUND_ID, 1.0f); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_BACKGROUND_ID, ccl_fetch(sd, svm_closure_weight)); } ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 node) @@ -932,10 +807,10 @@ ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 nod if(mix_weight == 0.0f) return; - svm_node_closure_get_non_bsdf(sd, CLOSURE_HOLDOUT_ID, mix_weight); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight); } else - svm_node_closure_get_non_bsdf(sd, CLOSURE_HOLDOUT_ID, 1.0f); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_HOLDOUT_ID, ccl_fetch(sd, svm_closure_weight)); ccl_fetch(sd, flag) |= SD_HOLDOUT; } @@ -950,10 +825,10 @@ ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack, if(mix_weight == 0.0f) return; - svm_node_closure_get_non_bsdf(sd, CLOSURE_AMBIENT_OCCLUSION_ID, mix_weight); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, ccl_fetch(sd, svm_closure_weight) * mix_weight); } else - svm_node_closure_get_non_bsdf(sd, CLOSURE_AMBIENT_OCCLUSION_ID, 1.0f); + closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, ccl_fetch(sd, svm_closure_weight)); ccl_fetch(sd, flag) |= SD_AO; } @@ -962,10 +837,7 @@ ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack, ccl_device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight) { - if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) { - ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure)); - sc->weight = weight; - } + ccl_fetch(sd, svm_closure_weight) = weight; } ccl_device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b) diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h new file mode 100644 index 00000000000..258cdeb630e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_color_util.h @@ -0,0 +1,306 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) +{ + return interp(col1, col2, t); +} + +ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 + col2, t); +} + +ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 * col2, t); +} + +ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 tm3 = make_float3(tm, tm, tm); + + return one - (tm3 + t*(one - col2))*(one - col1); +} + +ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(outcol.x < 0.5f) + outcol.x *= tm + 2.0f*t*col2.x; + else + outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); + + if(outcol.y < 0.5f) + outcol.y *= tm + 2.0f*t*col2.y; + else + outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); + + if(outcol.z < 0.5f) + outcol.z *= tm + 2.0f*t*col2.z; + else + outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); + + return outcol; +} + +ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 - col2, t); +} + +ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; + if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; + if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; + + return outcol; +} + +ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) +{ + return interp(col1, fabs(col1 - col2), t); +} + +ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) +{ + return min(col1, col2)*t + col1*(1.0f - t); +} + +ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) +{ + return max(col1, col2*t); +} + +ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(outcol.x != 0.0f) { + float tmp = 1.0f - t*col2.x; + if(tmp <= 0.0f) + outcol.x = 1.0f; + else if((tmp = outcol.x/tmp) > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + } + if(outcol.y != 0.0f) { + float tmp = 1.0f - t*col2.y; + if(tmp <= 0.0f) + outcol.y = 1.0f; + else if((tmp = outcol.y/tmp) > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + } + if(outcol.z != 0.0f) { + float tmp = 1.0f - t*col2.z; + if(tmp <= 0.0f) + outcol.z = 1.0f; + else if((tmp = outcol.z/tmp) > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + } + + return outcol; +} + +ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) +{ + float tmp, tm = 1.0f - t; + + float3 outcol = col1; + + tmp = tm + t*col2.x; + if(tmp <= 0.0f) + outcol.x = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) + outcol.x = 0.0f; + else if(tmp > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + + tmp = tm + t*col2.y; + if(tmp <= 0.0f) + outcol.y = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) + outcol.y = 0.0f; + else if(tmp > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + + tmp = tm + t*col2.z; + if(tmp <= 0.0f) + outcol.z = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) + outcol.z = 0.0f; + else if(tmp > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + + return outcol; +} + +ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + float3 hsv = rgb_to_hsv(outcol); + + if(hsv.y != 0.0f) { + float3 hsv2 = rgb_to_hsv(col2); + + hsv.y = tm*hsv.y + t*hsv2.y; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 hsv = rgb_to_hsv(col1); + float3 hsv2 = rgb_to_hsv(col2); + + hsv.z = tm*hsv.z + t*hsv2.z; + + return hsv_to_rgb(hsv); +} + +ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 scr = one - (one - col2)*(one - col1); + + return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); +} + +ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) +{ + return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); +} + +ccl_device float3 svm_mix_clamp(float3 col) +{ + float3 outcol = col; + + outcol.x = saturate(col.x); + outcol.y = saturate(col.y); + outcol.z = saturate(col.z); + + return outcol; +} + +ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +{ + float t = saturate(fac); + + switch(type) { + case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); + case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); + case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); + case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); + case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); + case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); + case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); + case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); + case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); + case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); + case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); + case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); + case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); + case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); + case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); + case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); + case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); + case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); + case NODE_MIX_CLAMP: return svm_mix_clamp(c1); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast) +{ + float a = 1.0f + contrast; + float b = brightness - contrast*0.5f; + + color.x = max(a*color.x + b, 0.0f); + color.y = max(a*color.y + b, 0.0f); + color.z = max(a*color.z + b, 0.0f); + + return color; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 92d2b36bbb1..b6b90dfff81 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -18,15 +18,15 @@ CCL_NAMESPACE_BEGIN /* Float4 textures on various devices. */ #if defined(__KERNEL_CPU__) -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CPU +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CPU #elif defined(__KERNEL_CUDA__) # if __CUDA_ARCH__ < 300 -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA # else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA_KEPLER # endif #else -# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_OPENCL +# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL #endif #ifdef __KERNEL_OPENCL__ @@ -72,8 +72,16 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint width = info.x; uint height = info.y; uint offset = info.z; - uint periodic = (info.w & 0x1); - uint interpolation = info.w >> 1; + + /* Image Options */ + uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + uint extension; + if(info.w & (1 << 1)) + extension = EXTENSION_REPEAT; + else if(info.w & (1 << 2)) + extension = EXTENSION_EXTEND; + else + extension = EXTENSION_CLIP; float4 r; int ix, iy, nix, niy; @@ -81,22 +89,26 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, svm_image_texture_frac(x*width, &ix); svm_image_texture_frac(y*height, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); } - else { + else if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + else { /* EXTENSION_EXTEND */ ix = svm_image_texture_wrap_clamp(ix, width); iy = svm_image_texture_wrap_clamp(iy, height); - } + r = svm_image_texture_read(kg, id, offset + ix + iy*width); } - else { /* We default to linear interpolation if it is not closest */ - float tx = svm_image_texture_frac(x*width, &ix); - float ty = svm_image_texture_frac(y*height, &iy); + else { /* INTERPOLATION_LINEAR */ + float tx = svm_image_texture_frac(x*width - 0.5f, &ix); + float ty = svm_image_texture_frac(y*height - 0.5f, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); @@ -104,14 +116,17 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, niy = svm_image_texture_wrap_periodic(iy+1, height); } else { - ix = svm_image_texture_wrap_clamp(ix, width); - iy = svm_image_texture_wrap_clamp(iy, height); - + if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + } nix = svm_image_texture_wrap_clamp(ix+1, width); niy = svm_image_texture_wrap_clamp(iy+1, height); + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); } - r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width); r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width); r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width); @@ -256,9 +271,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, case 87: r = kernel_tex_image_interp(__tex_image_byte4_087, x, y); break; case 88: r = kernel_tex_image_interp(__tex_image_byte4_088, x, y); break; case 89: r = kernel_tex_image_interp(__tex_image_byte4_089, x, y); break; - case 90: r = kernel_tex_image_interp(__tex_image_byte4_090, x, y); break; - case 91: r = kernel_tex_image_interp(__tex_image_byte4_091, x, y); break; - case 92: r = kernel_tex_image_interp(__tex_image_byte4_092, x, y); break; default: kernel_assert(0); return make_float4(0.0f, 0.0f, 0.0f, 0.0f); diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h index 7cbda111d81..022a68d1928 100644 --- a/intern/cycles/kernel/svm/svm_mix.h +++ b/intern/cycles/kernel/svm/svm_mix.h @@ -16,280 +16,6 @@ CCL_NAMESPACE_BEGIN -ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) -{ - return interp(col1, col2, t); -} - -ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 + col2, t); -} - -ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 * col2, t); -} - -ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 tm3 = make_float3(tm, tm, tm); - - return one - (tm3 + t*(one - col2))*(one - col1); -} - -ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(outcol.x < 0.5f) - outcol.x *= tm + 2.0f*t*col2.x; - else - outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); - - if(outcol.y < 0.5f) - outcol.y *= tm + 2.0f*t*col2.y; - else - outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); - - if(outcol.z < 0.5f) - outcol.z *= tm + 2.0f*t*col2.z; - else - outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); - - return outcol; -} - -ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 - col2, t); -} - -ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; - if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; - if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; - - return outcol; -} - -ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) -{ - return interp(col1, fabs(col1 - col2), t); -} - -ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) -{ - return min(col1, col2)*t + col1*(1.0f - t); -} - -ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) -{ - return max(col1, col2*t); -} - -ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - if(outcol.x != 0.0f) { - float tmp = 1.0f - t*col2.x; - if(tmp <= 0.0f) - outcol.x = 1.0f; - else if((tmp = outcol.x/tmp) > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - } - if(outcol.y != 0.0f) { - float tmp = 1.0f - t*col2.y; - if(tmp <= 0.0f) - outcol.y = 1.0f; - else if((tmp = outcol.y/tmp) > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - } - if(outcol.z != 0.0f) { - float tmp = 1.0f - t*col2.z; - if(tmp <= 0.0f) - outcol.z = 1.0f; - else if((tmp = outcol.z/tmp) > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - } - - return outcol; -} - -ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) -{ - float tmp, tm = 1.0f - t; - - float3 outcol = col1; - - tmp = tm + t*col2.x; - if(tmp <= 0.0f) - outcol.x = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) - outcol.x = 0.0f; - else if(tmp > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - - tmp = tm + t*col2.y; - if(tmp <= 0.0f) - outcol.y = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) - outcol.y = 0.0f; - else if(tmp > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - - tmp = tm + t*col2.z; - if(tmp <= 0.0f) - outcol.z = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) - outcol.z = 0.0f; - else if(tmp > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - - return outcol; -} - -ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - float3 hsv = rgb_to_hsv(outcol); - - if(hsv.y != 0.0f) { - float3 hsv2 = rgb_to_hsv(col2); - - hsv.y = tm*hsv.y + t*hsv2.y; - outcol = hsv_to_rgb(hsv); - } - - return outcol; -} - -ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 hsv = rgb_to_hsv(col1); - float3 hsv2 = rgb_to_hsv(col2); - - hsv.z = tm*hsv.z + t*hsv2.z; - - return hsv_to_rgb(hsv); -} - -ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - hsv.y = hsv2.y; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 scr = one - (one - col2)*(one - col1); - - return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); -} - -ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) -{ - return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); -} - -ccl_device float3 svm_mix_clamp(float3 col) -{ - float3 outcol = col; - - outcol.x = saturate(col.x); - outcol.y = saturate(col.y); - outcol.z = saturate(col.z); - - return outcol; -} - -ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) -{ - float t = saturate(fac); - - switch(type) { - case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); - case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); - case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); - case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); - case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); - case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); - case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); - case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); - case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); - case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); - case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); - case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); - case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); - case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); - case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); - case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); - case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); - case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); - case NODE_MIX_CLAMP: return svm_mix_clamp(c1); - } - - return make_float3(0.0f, 0.0f, 0.0f); -} - /* Node */ ccl_device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset) diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h index 59dec409a70..f959d90f309 100644 --- a/intern/cycles/kernel/svm/svm_ramp.h +++ b/intern/cycles/kernel/svm/svm_ramp.h @@ -19,6 +19,8 @@ CCL_NAMESPACE_BEGIN +/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */ + ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg, int offset, float f, @@ -75,36 +77,7 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac *offset += table_size; } -ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) -{ - uint fac_offset, color_offset, out_offset; - decode_node_uchar4(node.y, - &fac_offset, - &color_offset, - &out_offset, - NULL); - - uint table_size = read_node(kg, offset).x; - - float fac = stack_load_float(stack, fac_offset); - float3 color = stack_load_float3(stack, color_offset); - - const float min_x = __int_as_float(node.z), - max_x = __int_as_float(node.w); - const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; - - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; - - color = (1.0f - fac)*color + fac*make_float3(r, g, b); - stack_store_float3(stack, out_offset, color); - - *offset += table_size; -} - -ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +ccl_device void svm_node_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) { uint fac_offset, color_offset, out_offset; decode_node_uchar4(node.y, @@ -121,11 +94,11 @@ ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w); const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; + const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x; - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; + float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x; + float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y; + float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); diff --git a/intern/cycles/kernel/svm/svm_ramp_util.h b/intern/cycles/kernel/svm/svm_ramp_util.h new file mode 100644 index 00000000000..495d98cf250 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_ramp_util.h @@ -0,0 +1,97 @@ +/* + * 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 __SVM_RAMP_UTIL_H__ +#define __SVM_RAMP_UTIL_H__ + +CCL_NAMESPACE_BEGIN + +/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */ + +ccl_device float3 rgb_ramp_lookup(const float3 *ramp, + float f, + bool interpolate, + bool extrapolate, + int table_size) +{ + if ((f < 0.0f || f > 1.0f) && extrapolate) { + float3 t0, dy; + if (f < 0.0f) { + t0 = ramp[0]; + dy = t0 - ramp[1], + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0f; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(f, 0.0f, 1.0f) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = clamp(float_to_int(f), 0, table_size-1); + float t = f - (float)i; + + float3 result = ramp[i]; + + if (interpolate && t > 0.0f) + result = (1.0f - t) * result + t * ramp[i + 1]; + + return result; +} + +ccl_device float float_ramp_lookup(const float *ramp, + float f, + bool interpolate, + bool extrapolate, + int table_size) +{ + if ((f < 0.0f || f > 1.0f) && extrapolate) { + float t0, dy; + if (f < 0.0f) { + t0 = ramp[0]; + dy = t0 - ramp[1], + f = -f; + } + else { + t0 = ramp[table_size - 1]; + dy = t0 - ramp[table_size - 2]; + f = f - 1.0f; + } + return t0 + dy * f * (table_size - 1); + } + + f = clamp(f, 0.0f, 1.0f) * (table_size - 1); + + /* clamp int as well in case of NaN */ + int i = clamp(float_to_int(f), 0, table_size-1); + float t = f - (float)i; + + float result = ramp[i]; + + if (interpolate && t > 0.0f) + result = (1.0f - t) * result + t * ramp[i + 1]; + + return result; +} + +CCL_NAMESPACE_END + +#endif /* __SVM_RAMP_UTIL_H__ */ + diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 27fed89fdf7..276b6f26f5e 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -312,7 +312,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st /* apply normal map */ float3 B = sign * cross(normal, tangent); - N = normalize(color.x * tangent + color.y * B + color.z * normal); + N = safe_normalize(color.x * tangent + color.y * B + color.z * normal); /* transform to world space */ object_normal_transform(kg, sd, &N); @@ -330,14 +330,18 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st if(space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT) object_normal_transform(kg, sd, &N); else - N = normalize(N); + N = safe_normalize(N); } float strength = stack_load_float(stack, strength_offset); if(strength != 1.0f) { strength = max(strength, 0.0f); - N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + N = safe_normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + } + + if(is_zero(N)) { + N = ccl_fetch(sd, N); } stack_store_float3(stack, normal_offset, N); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index f69b4cc5c8e..91d444098f7 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -343,6 +343,11 @@ typedef enum NodeNormalMapSpace { NODE_NORMAL_MAP_BLENDER_WORLD, } NodeNormalMapSpace; +typedef enum NodeImageColorSpace { + NODE_COLOR_SPACE_NONE = 0, + NODE_COLOR_SPACE_COLOR = 1, +} NodeImageColorSpace; + typedef enum NodeImageProjection { NODE_IMAGE_PROJ_FLAT = 0, NODE_IMAGE_PROJ_BOX = 1, @@ -350,6 +355,11 @@ typedef enum NodeImageProjection { NODE_IMAGE_PROJ_TUBE = 3, } NodeImageProjection; +typedef enum NodeEnvironmentProjection { + NODE_ENVIRONMENT_EQUIRECTANGULAR = 0, + NODE_ENVIRONMENT_MIRROR_BALL = 1, +} NodeEnvironmentProjection; + typedef enum NodeBumpOffset { NODE_BUMP_OFFSET_CENTER, NODE_BUMP_OFFSET_DX, @@ -388,8 +398,10 @@ typedef enum ClosureType { CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, @@ -407,6 +419,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, @@ -444,6 +457,9 @@ typedef enum ClosureType { #define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID) #define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_DISNEY_ID) #define CLOSURE_IS_BSDF_ANISOTROPIC(type) (type >= CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID) +#define CLOSURE_IS_BSDF_MULTISCATTER(type) (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID ||\ + type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID || \ + type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) #define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_BURLEY_ID) #define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_BURLEY_ID) #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b14da3e63d0..8eaa9de3874 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC bake.cpp buffers.cpp camera.cpp + constant_fold.cpp film.cpp graph.cpp image.cpp @@ -29,6 +30,7 @@ set(SRC light.cpp mesh.cpp mesh_displace.cpp + mesh_subdivision.cpp nodes.cpp object.cpp osl.cpp @@ -49,6 +51,7 @@ set(SRC_HEADERS background.h buffers.h camera.h + constant_fold.h film.h graph.h image.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index b7de83d89c1..e8ff81fe08e 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -51,13 +51,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix); } -void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize) +void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only) { - if(resize) { - buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0); + if(reserve_only) { + buffer.reserve(buffer_size(mesh, prim)); } else { - buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys)); + buffer.resize(buffer_size(mesh, prim), 0); } } @@ -118,6 +118,8 @@ size_t Attribute::data_sizeof() const { if(element == ATTR_ELEMENT_VOXEL) return sizeof(VoxelAttribute); + else if(element == ATTR_ELEMENT_CORNER_BYTE) + return sizeof(uchar4); else if(type == TypeDesc::TypeFloat) return sizeof(float); else if(type == TypeDesc::TypeMatrix) @@ -126,10 +128,10 @@ size_t Attribute::data_sizeof() const return sizeof(float3); } -size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const +size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const { size_t size; - + switch(element) { case ATTR_ELEMENT_OBJECT: case ATTR_ELEMENT_MESH: @@ -137,38 +139,54 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc size = 1; break; case ATTR_ELEMENT_VERTEX: - size = numverts; + size = mesh->verts.size() + mesh->num_ngons; + if(prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts; + } break; case ATTR_ELEMENT_VERTEX_MOTION: - size = numverts * (numsteps - 1); + size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); + if(prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts * (mesh->motion_steps - 1); + } break; case ATTR_ELEMENT_FACE: - size = numtris; + if(prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles(); + } + else { + size = mesh->subd_faces.size() + mesh->num_ngons; + } break; case ATTR_ELEMENT_CORNER: case ATTR_ELEMENT_CORNER_BYTE: - size = numtris*3; + if(prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles()*3; + } + else { + size = mesh->subd_face_corners.size() + mesh->num_ngons; + } break; case ATTR_ELEMENT_CURVE: - size = numcurves; + size = mesh->num_curves(); break; case ATTR_ELEMENT_CURVE_KEY: - size = numkeys; + size = mesh->curve_keys.size(); break; case ATTR_ELEMENT_CURVE_KEY_MOTION: - size = numkeys * (numsteps - 1); + size = mesh->curve_keys.size() * (mesh->motion_steps - 1); break; default: size = 0; break; } - + return size; } -size_t Attribute::buffer_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const +size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const { - return element_size(numverts, numtris, numsteps, numcurves, numkeys)*data_sizeof(); + return element_size(mesh, prim)*data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) @@ -188,6 +206,29 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) return false; } +void Attribute::zero_data(void* dst) +{ + memset(dst, 0, data_sizeof()); +} + +void Attribute::add_with_weight(void* dst, void* src, float weight) +{ + if(element == ATTR_ELEMENT_CORNER_BYTE) { + for(int i = 0; i < 4; i++) { + ((uchar*)dst)[i] += uchar(((uchar*)src)[i] * weight); + } + } + else if(same_storage(type, TypeDesc::TypeFloat)) { + *((float*)dst) += *((float*)src) * weight; + } + else if(same_storage(type, TypeDesc::TypeVector)) { + *((float4*)dst) += *((float4*)src) * weight; + } + else { + assert(!"not implemented for this type"); + } +} + const char *Attribute::standard_name(AttributeStandard std) { switch(std) { @@ -257,13 +298,14 @@ AttributeSet::AttributeSet() { triangle_mesh = NULL; curve_mesh = NULL; + subd_mesh = NULL; } AttributeSet::~AttributeSet() { } -Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element, bool resize) +Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { Attribute *attr = find(name); @@ -291,10 +333,12 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme /* this is weak .. */ if(triangle_mesh) - attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, resize); + attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); if(curve_mesh) - attr->reserve(0, 0, curve_mesh->motion_steps, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), resize); - + attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); + if(subd_mesh) + attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); + return attr; } @@ -330,7 +374,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) if(name == ustring()) name = Attribute::standard_name(std); - if(triangle_mesh) { + if(triangle_mesh || subd_mesh) { switch(std) { case ATTR_STD_VERTEX_NORMAL: attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); @@ -448,13 +492,15 @@ Attribute *AttributeSet::find(AttributeRequest& req) return find(req.std); } -void AttributeSet::reserve() +void AttributeSet::resize(bool reserve_only) { foreach(Attribute& attr, attributes) { if(triangle_mesh) - attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, true); + attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); if(curve_mesh) - attr.reserve(0, 0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), true); + attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); + if(subd_mesh) + attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); } } @@ -477,6 +523,10 @@ AttributeRequest::AttributeRequest(ustring name_) curve_type = TypeDesc::TypeFloat; curve_element = ATTR_ELEMENT_NONE; curve_offset = 0; + + subd_type = TypeDesc::TypeFloat; + subd_element = ATTR_ELEMENT_NONE; + subd_offset = 0; } AttributeRequest::AttributeRequest(AttributeStandard std_) @@ -491,6 +541,10 @@ AttributeRequest::AttributeRequest(AttributeStandard std_) curve_type = TypeDesc::TypeFloat; curve_element = ATTR_ELEMENT_NONE; curve_offset = 0; + + subd_type = TypeDesc::TypeFloat; + subd_element = ATTR_ELEMENT_NONE; + subd_offset = 0; } /* AttributeRequestSet */ diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 01102d22aaa..e51bdf28d66 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -58,11 +58,11 @@ public: Attribute() {} ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); - void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize); + void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only); size_t data_sizeof() const; - size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const; - size_t buffer_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const; + size_t element_size(Mesh *mesh, AttributePrimitive prim) const; + size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const; char *data() { return (buffer.size())? &buffer[0]: NULL; }; float3 *data_float3() { return (float3*)data(); } @@ -79,6 +79,9 @@ public: const Transform *data_transform() const { return (const Transform*)data(); } const VoxelAttribute *data_voxel() const { return (const VoxelAttribute*)data(); } + void zero_data(void* dst); + void add_with_weight(void* dst, void* src, float weight); + void add(const float& f); void add(const float3& f); void add(const uchar4& f); @@ -99,12 +102,13 @@ class AttributeSet { public: Mesh *triangle_mesh; Mesh *curve_mesh; + Mesh *subd_mesh; list<Attribute> attributes; AttributeSet(); ~AttributeSet(); - Attribute *add(ustring name, TypeDesc type, AttributeElement element, bool resize = true); + Attribute *add(ustring name, TypeDesc type, AttributeElement element); Attribute *find(ustring name) const; void remove(ustring name); @@ -114,7 +118,7 @@ public: Attribute *find(AttributeRequest& req); - void reserve(); + void resize(bool reserve_only = false); void clear(); }; @@ -130,9 +134,9 @@ public: AttributeStandard std; /* temporary variables used by MeshManager */ - TypeDesc triangle_type, curve_type; - AttributeElement triangle_element, curve_element; - int triangle_offset, curve_offset; + TypeDesc triangle_type, curve_type, subd_type; + AttributeElement triangle_element, curve_element, subd_element; + int triangle_offset, curve_offset, subd_offset; explicit AttributeRequest(ustring name_); explicit AttributeRequest(AttributeStandard std); diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 6f8d1d1d461..8d7d7b847fd 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -32,12 +32,12 @@ NODE_DEFINE(Background) { NodeType* type = NodeType::add("background", create); - SOCKET_INT(ao_factor, "AO Factor", 0.0f); + SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f); SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX); SOCKET_BOOLEAN(use_shader, "Use Shader", true); SOCKET_BOOLEAN(use_ao, "Use AO", false); - SOCKET_INT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); + SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); SOCKET_BOOLEAN(transparent, "Transparent", false); SOCKET_NODE(shader, "Shader", &Shader::node_type); @@ -116,6 +116,11 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { } +bool Background::modified(const Background& background) +{ + return !Node::equals(background); +} + void Background::tag_update(Scene *scene) { scene->integrator->tag_update(scene); diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index 843655b00a1..8029c6a9e80 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -50,6 +50,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); + bool modified(const Background& background); void tag_update(Scene *scene); }; diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 5bf5e5113ef..13310a61761 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -177,7 +177,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre device->mem_alloc(d_input, MEM_READ_ONLY); device->mem_copy_to(d_input); - device->mem_alloc(d_output, MEM_WRITE_ONLY); + device->mem_alloc(d_output, MEM_READ_WRITE); DeviceTask task(DeviceTask::SHADER); task.shader_input = d_input.device_pointer; diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index d992cac5312..a6df656d220 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -30,70 +30,126 @@ CCL_NAMESPACE_BEGIN static float shutter_curve_eval(float x, - float shutter_curve[RAMP_TABLE_SIZE]) + array<float>& shutter_curve) { - x *= RAMP_TABLE_SIZE; + if (shutter_curve.size() == 0) + return 1.0f; + + x *= shutter_curve.size(); int index = (int)x; float frac = x - index; - if(index < RAMP_TABLE_SIZE - 1) { + if(index < shutter_curve.size() - 1) { return lerp(shutter_curve[index], shutter_curve[index + 1], frac); } else { - return shutter_curve[RAMP_TABLE_SIZE - 1]; + return shutter_curve[shutter_curve.size() - 1]; } } +NODE_DEFINE(Camera) +{ + NodeType* type = NodeType::add("camera", create); + + SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f); + + static NodeEnum motion_position_enum; + motion_position_enum.insert("start", MOTION_POSITION_START); + motion_position_enum.insert("center", MOTION_POSITION_CENTER); + motion_position_enum.insert("end", MOTION_POSITION_END); + SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER); + + static NodeEnum rolling_shutter_type_enum; + rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE); + rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP); + SOCKET_ENUM(rolling_shutter_type, "Rolling Shutter Type", rolling_shutter_type_enum, ROLLING_SHUTTER_NONE); + SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f); + + SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>()); + + SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f); + SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f); + SOCKET_UINT(blades, "Blades", 0); + SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f); + + SOCKET_TRANSFORM(matrix, "Matrix", transform_identity()); + + SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f); + + static NodeEnum type_enum; + type_enum.insert("perspective", CAMERA_PERSPECTIVE); + type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC); + type_enum.insert("panorama", CAMERA_PANORAMA); + SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE); + + static NodeEnum panorama_type_enum; + panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR); + panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); + panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); + panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); + SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR); + + SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F); + SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f); + SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F); + SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F); + SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F); + SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F); + SOCKET_FLOAT(fov, "FOV", M_PI_4_F); + SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F); + SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F); + + static NodeEnum stereo_eye_enum; + stereo_eye_enum.insert("none", STEREO_NONE); + stereo_eye_enum.insert("left", STEREO_LEFT); + stereo_eye_enum.insert("right", STEREO_RIGHT); + SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE); + + SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f); + SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f); + + SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false); + SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f); + SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f); + + SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f); + SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f); + + SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f); + SOCKET_FLOAT(farclip, "Far Clip", 1e5f); + + SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0); + SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0); + SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0); + SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0); + + SOCKET_FLOAT(border.left, "Border Left", 0); + SOCKET_FLOAT(border.right, "Border Right", 0); + SOCKET_FLOAT(border.bottom, "Border Bottom", 0); + SOCKET_FLOAT(border.top, "Border Top", 0); + + return type; +} + Camera::Camera() +: Node(node_type) { - shuttertime = 1.0f; - motion_position = MOTION_POSITION_CENTER; shutter_table_offset = TABLE_OFFSET_INVALID; - aperturesize = 0.0f; - focaldistance = 10.0f; - blades = 0; - bladesrotation = 0.0f; - - matrix = transform_identity(); + width = 1024; + height = 512; + resolution = 1; motion.pre = transform_identity(); motion.post = transform_identity(); use_motion = false; use_perspective_motion = false; - aperture_ratio = 1.0f; - - type = CAMERA_PERSPECTIVE; - panorama_type = PANORAMA_EQUIRECTANGULAR; - fisheye_fov = M_PI_F; - fisheye_lens = 10.5f; - latitude_min = -M_PI_2_F; - latitude_max = M_PI_2_F; - longitude_min = -M_PI_F; - longitude_max = M_PI_F; - fov = M_PI_4_F; - fov_pre = fov_post = fov; - stereo_eye = STEREO_NONE; - interocular_distance = 0.065f; - convergence_distance = 30.0f * 0.065f; - use_pole_merge = false; - pole_merge_angle_from = 60.0f * M_PI_F / 180.0f; - pole_merge_angle_to = 75.0f * M_PI_F / 180.0f; - - sensorwidth = 0.036f; - sensorheight = 0.024f; - - nearclip = 1e-5f; - farclip = 1e5f; - - width = 1024; - height = 512; - resolution = 1; + shutter_curve.resize(RAMP_TABLE_SIZE); + for(int i = 0; i < shutter_curve.size(); ++i) { + shutter_curve[i] = 1.0f; + } - viewplane.left = -((float)width/(float)height); - viewplane.right = (float)width/(float)height; - viewplane.bottom = -1.0f; - viewplane.top = 1.0f; + compute_auto_viewplane(); screentoworld = transform_identity(); rastertoworld = transform_identity(); @@ -109,16 +165,6 @@ Camera::Camera() need_device_update = true; need_flags_update = true; previous_need_motion = -1; - - /* Initialize shutter curve. */ - const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve); - for(int i = 0; i < num_shutter_points; ++i) { - shutter_curve[i] = 1.0f; - } - - /* Initialize rolling shutter effect. */ - rolling_shutter_type = ROLLING_SHUTTER_NONE; - rolling_shutter_duration = 0.1f; } Camera::~Camera() @@ -438,38 +484,14 @@ void Camera::device_free(Device * /*device*/, bool Camera::modified(const Camera& cam) { - return !((shuttertime == cam.shuttertime) && - (aperturesize == cam.aperturesize) && - (blades == cam.blades) && - (bladesrotation == cam.bladesrotation) && - (focaldistance == cam.focaldistance) && - (type == cam.type) && - (fov == cam.fov) && - (nearclip == cam.nearclip) && - (farclip == cam.farclip) && - (sensorwidth == cam.sensorwidth) && - (sensorheight == cam.sensorheight) && - // modified for progressive render - // (width == cam.width) && - // (height == cam.height) && - (viewplane == cam.viewplane) && - (border == cam.border) && - (matrix == cam.matrix) && - (aperture_ratio == cam.aperture_ratio) && - (panorama_type == cam.panorama_type) && - (fisheye_fov == cam.fisheye_fov) && - (fisheye_lens == cam.fisheye_lens) && - (latitude_min == cam.latitude_min) && - (latitude_max == cam.latitude_max) && - (longitude_min == cam.longitude_min) && - (longitude_max == cam.longitude_max) && - (stereo_eye == cam.stereo_eye)); + return !Node::equals(cam); } bool Camera::motion_modified(const Camera& cam) { return !((motion == cam.motion) && - (use_motion == cam.use_motion)); + (use_motion == cam.use_motion) && + (use_perspective_motion == cam.use_perspective_motion)); } void Camera::tag_update() diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 57b9960e70b..141ef9cccef 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -19,6 +19,8 @@ #include "kernel_types.h" +#include "node.h" + #include "util_boundbox.h" #include "util_transform.h" #include "util_types.h" @@ -35,8 +37,10 @@ class Scene; * Renderman, and Blender after remapping. */ -class Camera { +class Camera : public Node { public: + NODE_DECLARE; + /* Specifies an offset for the shutter's time interval. */ enum MotionPosition { /* Shutter opens at the current frame. */ @@ -69,7 +73,7 @@ public: /* motion blur */ float shuttertime; MotionPosition motion_position; - float shutter_curve[RAMP_TABLE_SIZE]; + array<float> shutter_curve; size_t shutter_table_offset; /* ** Rolling shutter effect. ** */ diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp new file mode 100644 index 00000000000..073bafce98d --- /dev/null +++ b/intern/cycles/render/constant_fold.cpp @@ -0,0 +1,354 @@ +/* + * 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. + */ + +#include "constant_fold.h" +#include "graph.h" + +#include "util_foreach.h" +#include "util_logging.h" + +CCL_NAMESPACE_BEGIN + +ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output) +: graph(graph), node(node), output(output) +{ +} + +bool ConstantFolder::all_inputs_constant() const +{ + foreach(ShaderInput *input, node->inputs) { + if(input->link) { + return false; + } + } + + return true; +} + +void ConstantFolder::make_constant(float value) const +{ + VLOG(1) << "Replacing " << node->name << " with constant " << value << "."; + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant(float3 value) const +{ + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant_clamp(float value, bool clamp) const +{ + make_constant(clamp ? saturate(value) : value); +} + +void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const +{ + if(clamp) { + value.x = saturate(value.x); + value.y = saturate(value.y); + value.z = saturate(value.z); + } + + make_constant(value); +} + +void ConstantFolder::make_zero() const +{ + if(output->type() == SocketType::FLOAT) { + make_constant(0.0f); + } + else if(SocketType::is_float3(output->type())) { + make_constant(make_float3(0.0f, 0.0f, 0.0f)); + } + else { + assert(0); + } +} + +void ConstantFolder::bypass(ShaderOutput *new_output) const +{ + assert(new_output); + + /* Remove all outgoing links from socket and connect them to new_output instead. + * The graph->relink method affects node inputs, so it's not safe to use in constant + * folding if the node has multiple outputs and will thus be folded multiple times. */ + vector<ShaderInput*> outputs = output->links; + + graph->disconnect(output); + + foreach(ShaderInput *sock, outputs) { + graph->connect(new_output, sock); + } +} + +void ConstantFolder::discard() const +{ + assert(output->type() == SocketType::CLOSURE); + graph->disconnect(output); +} + +void ConstantFolder::bypass_or_discard(ShaderInput *input) const +{ + assert(input->type() == SocketType::CLOSURE); + + if(input->link) { + bypass(input->link); + } + else { + discard(); + } +} + +bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const +{ + if(input->type() != output->type()) { + return false; + } + else if(!input->link) { + if(input->type() == SocketType::FLOAT) { + make_constant_clamp(node->get_float(input->socket_type), clamp); + return true; + } + else if(SocketType::is_float3(input->type())) { + make_constant_clamp(node->get_float3(input->socket_type), clamp); + return true; + } + } + else if(!clamp) { + bypass(input->link); + return true; + } + + return false; +} + +bool ConstantFolder::is_zero(ShaderInput *input) const +{ + if(!input->link) { + if(input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 0.0f; + } + else if(SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == + make_float3(0.0f, 0.0f, 0.0f); + } + } + + return false; +} + +bool ConstantFolder::is_one(ShaderInput *input) const +{ + if(!input->link) { + if(input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 1.0f; + } + else if(SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == + make_float3(1.0f, 1.0f, 1.0f); + } + } + + return false; +} + +/* Specific nodes */ + +void ConstantFolder::fold_mix(NodeMix type, bool clamp) const +{ + ShaderInput *fac_in = node->input("Fac"); + ShaderInput *color1_in = node->input("Color1"); + ShaderInput *color2_in = node->input("Color2"); + + float fac = saturate(node->get_float(fac_in->socket_type)); + bool fac_is_zero = !fac_in->link && fac == 0.0f; + bool fac_is_one = !fac_in->link && fac == 1.0f; + + /* remove no-op node when factor is 0.0 */ + if(fac_is_zero) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if(!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { + if(try_bypass_or_make_constant(color1_in, clamp)) { + return; + } + } + } + + switch(type) { + case NODE_MIX_BLEND: + /* remove useless mix colors nodes */ + if(color1_in->link && color2_in->link) { + if(color1_in->link == color2_in->link) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + else if(!color1_in->link && !color2_in->link) { + float3 color1 = node->get_float3(color1_in->socket_type); + float3 color2 = node->get_float3(color2_in->socket_type); + if(color1 == color2) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + /* remove no-op mix color node when factor is 1.0 */ + if(fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + break; + } + break; + case NODE_MIX_ADD: + /* 0 + X (fac 1) == X */ + if(is_zero(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + /* X + 0 (fac ?) == X */ + else if(is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + break; + case NODE_MIX_SUB: + /* X - 0 (fac ?) == X */ + if(is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* X - X (fac 1) == 0 */ + else if(color1_in->link && color1_in->link == color2_in->link && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_MUL: + /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ + if(is_one(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + else if(is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ + else if(is_zero(color1_in)) { + make_zero(); + } + else if(is_zero(color2_in) && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_DIV: + /* X / 1 (fac ?) == X */ + if(is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 / ? (fac ?) == 0 */ + else if(is_zero(color1_in)) { + make_zero(); + } + break; + default: + break; + } +} + +void ConstantFolder::fold_math(NodeMath type, bool clamp) const +{ + ShaderInput *value1_in = node->input("Value1"); + ShaderInput *value2_in = node->input("Value2"); + + switch(type) { + case NODE_MATH_ADD: + /* X + 0 == 0 + X == X */ + if(is_zero(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if(is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_SUBTRACT: + /* X - 0 == X */ + if(is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_MULTIPLY: + /* X * 1 == 1 * X == X */ + if(is_one(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if(is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* X * 0 == 0 * X == 0 */ + else if(is_zero(value1_in) || is_zero(value2_in)) { + make_zero(); + } + break; + case NODE_MATH_DIVIDE: + /* X / 1 == X */ + if(is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* 0 / X == 0 */ + else if(is_zero(value1_in)) { + make_zero(); + } + break; + default: + break; + } +} + +void ConstantFolder::fold_vector_math(NodeVectorMath type) const +{ + ShaderInput *vector1_in = node->input("Vector1"); + ShaderInput *vector2_in = node->input("Vector2"); + + switch(type) { + case NODE_VECTOR_MATH_ADD: + /* X + 0 == 0 + X == X */ + if(is_zero(vector1_in)) { + try_bypass_or_make_constant(vector2_in); + } + else if(is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_SUBTRACT: + /* X - 0 == X */ + if(is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + case NODE_VECTOR_MATH_CROSS_PRODUCT: + /* X * 0 == 0 * X == 0 */ + if(is_zero(vector1_in) || is_zero(vector2_in)) { + make_zero(); + } + break; + default: + break; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h new file mode 100644 index 00000000000..2b31c2a5887 --- /dev/null +++ b/intern/cycles/render/constant_fold.h @@ -0,0 +1,70 @@ +/* + * 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 __CONSTANT_FOLD_H__ +#define __CONSTANT_FOLD_H__ + +#include "util_types.h" +#include "svm_types.h" + +CCL_NAMESPACE_BEGIN + +class ShaderGraph; +class ShaderInput; +class ShaderNode; +class ShaderOutput; + +class ConstantFolder { +public: + ShaderGraph *const graph; + ShaderNode *const node; + ShaderOutput *const output; + + ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output); + + bool all_inputs_constant() const; + + /* Constant folding helpers */ + void make_constant(float value) const; + void make_constant(float3 value) const; + void make_constant_clamp(float value, bool clamp) const; + void make_constant_clamp(float3 value, bool clamp) const; + void make_zero() const; + + /* Bypass node, relinking to another output socket. */ + void bypass(ShaderOutput *output) const; + + /* For closure nodes, discard node entirely or bypass to one of its inputs. */ + void discard() const; + void bypass_or_discard(ShaderInput *input) const; + + /* Bypass or make constant, unless we can't due to clamp being true. */ + bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const; + + /* Test if shader inputs of the current nodes have fixed values. */ + bool is_zero(ShaderInput *input) const; + bool is_one(ShaderInput *input) const; + + /* Specific nodes. */ + void fold_mix(NodeMix type, bool clamp) const; + void fold_math(NodeMath type, bool clamp) const; + void fold_vector_math(NodeVectorMath type) const; +}; + +CCL_NAMESPACE_END + +#endif /* __CONSTANT_FOLD_H__ */ + diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h index 3d9b4e1f347..e41967eebf5 100644 --- a/intern/cycles/render/curves.h +++ b/intern/cycles/render/curves.h @@ -63,23 +63,23 @@ public: ParticleCurveData(); ~ParticleCurveData(); - vector<int> psys_firstcurve; - vector<int> psys_curvenum; - vector<int> psys_shader; - - vector<float> psys_rootradius; - vector<float> psys_tipradius; - vector<float> psys_shape; - vector<bool> psys_closetip; - - vector<int> curve_firstkey; - vector<int> curve_keynum; - vector<float> curve_length; - vector<float3> curve_uv; - vector<float3> curve_vcol; - - vector<float3> curvekey_co; - vector<float> curvekey_time; + array<int> psys_firstcurve; + array<int> psys_curvenum; + array<int> psys_shader; + + array<float> psys_rootradius; + array<float> psys_tipradius; + array<float> psys_shape; + array<bool> psys_closetip; + + array<int> curve_firstkey; + array<int> curve_keynum; + array<float> curve_length; + array<float3> curve_uv; + array<float3> curve_vcol; + + array<float3> curvekey_co; + array<float> curvekey_time; }; /* HairSystem Manager */ diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 12dce6ad999..e10a938e1eb 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -465,7 +465,7 @@ void Film::device_free(Device * /*device*/, bool Film::modified(const Film& film) { - return Node::modified(film) || !Pass::equals(passes, film.passes); + return !Node::equals(film) || !Pass::equals(passes, film.passes); } void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_) diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 24e4c9f33d5..3eeb7ffc2bc 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * 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. @@ -18,6 +18,7 @@ #include "graph.h" #include "nodes.h" #include "shader.h" +#include "constant_fold.h" #include "util_algorithm.h" #include "util_debug.h" @@ -51,73 +52,19 @@ bool check_node_inputs_traversed(const ShaderNode *node, return true; } -bool check_node_inputs_equals(const ShaderNode *node_a, - const ShaderNode *node_b) -{ - if(node_a->inputs.size() != node_b->inputs.size()) { - /* Happens with BSDF closure nodes which are currently sharing the same - * name for all the BSDF types, making it impossible to filter out - * incompatible nodes. - */ - return false; - } - for(int i = 0; i < node_a->inputs.size(); ++i) { - ShaderInput *input_a = node_a->inputs[i], - *input_b = node_b->inputs[i]; - if(input_a->link == NULL && input_b->link == NULL) { - /* Unconnected inputs are expected to have the same value. */ - if(input_a->value != input_b->value) { - return false; - } - } - else if(input_a->link != NULL && input_b->link != NULL) { - /* Expect links are to come from the same exact socket. */ - if(input_a->link != input_b->link) { - return false; - } - } - else { - /* One socket has a link and another has not, inputs can't be - * considered equal. - */ - return false; - } - } - return true; -} - } /* namespace */ -/* Input and Output */ - -ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) -{ - parent = parent_; - name = name_; - type = type_; - link = NULL; - value = make_float3(0.0f, 0.0f, 0.0f); - stack_offset = SVM_STACK_INVALID; - default_value = NONE; - usage = USE_ALL; -} - -ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) -{ - parent = parent_; - name = name_; - type = type_; - stack_offset = SVM_STACK_INVALID; -} - /* Node */ -ShaderNode::ShaderNode(const char *name_) +ShaderNode::ShaderNode(const NodeType *type) +: Node(type) { - name = name_; + name = type->name; id = -1; bump = SHADER_BUMP_NONE; special_type = SHADER_SPECIAL_TYPE_NONE; + + create_inputs_outputs(type); } ShaderNode::~ShaderNode() @@ -129,10 +76,23 @@ ShaderNode::~ShaderNode() delete socket; } +void ShaderNode::create_inputs_outputs(const NodeType *type) +{ + foreach(const SocketType& socket, type->inputs) { + if(socket.flags & SocketType::LINKABLE) { + inputs.push_back(new ShaderInput(socket, this)); + } + } + + foreach(const SocketType& socket, type->outputs) { + outputs.push_back(new ShaderOutput(socket, this)); + } +} + ShaderInput *ShaderNode::input(const char *name) { foreach(ShaderInput *socket, inputs) { - if(strcmp(socket->name, name) == 0) + if(socket->name() == name) return socket; } @@ -142,56 +102,42 @@ ShaderInput *ShaderNode::input(const char *name) ShaderOutput *ShaderNode::output(const char *name) { foreach(ShaderOutput *socket, outputs) - if(strcmp(socket->name, name) == 0) + if(socket->name() == name) return socket; return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage) +ShaderInput *ShaderNode::input(ustring name) { - ShaderInput *input = new ShaderInput(this, name, type); - input->value.x = value; - input->usage = usage; - inputs.push_back(input); - return input; -} + foreach(ShaderInput *socket, inputs) { + if(socket->name() == name) + return socket; + } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage) -{ - ShaderInput *input = new ShaderInput(this, name, type); - input->value = value; - input->usage = usage; - inputs.push_back(input); - return input; + return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage) +ShaderOutput *ShaderNode::output(ustring name) { - ShaderInput *input = add_input(name, type); - input->default_value = value; - input->usage = usage; - return input; -} + foreach(ShaderOutput *socket, outputs) + if(socket->name() == name) + return socket; -ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type) -{ - ShaderOutput *output = new ShaderOutput(this, name, type); - outputs.push_back(output); - return output; + return NULL; } void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) { foreach(ShaderInput *input, inputs) { if(!input->link) { - if(input->default_value == ShaderInput::TEXTURE_GENERATED) { + if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { if(shader->has_surface) attributes->add(ATTR_STD_GENERATED); if(shader->has_volume) attributes->add(ATTR_STD_GENERATED_TRANSFORM); } - else if(input->default_value == ShaderInput::TEXTURE_UV) { + else if(input->flags() & SocketType::LINK_TEXTURE_UV) { if(shader->has_surface) attributes->add(ATTR_STD_UV); } @@ -199,6 +145,49 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) } } +bool ShaderNode::equals(const ShaderNode& other) +{ + if (type != other.type || bump != other.bump) + return false; + + assert(inputs.size() == other.inputs.size()); + + /* Compare unlinkable sockets */ + foreach(const SocketType& socket, type->inputs) { + if(!(socket.flags & SocketType::LINKABLE)) { + if(!Node::equals_value(other, socket)) { + return false; + } + } + } + + /* Compare linkable input sockets */ + for(int i = 0; i < inputs.size(); ++i) { + ShaderInput *input_a = inputs[i], + *input_b = other.inputs[i]; + if(input_a->link == NULL && input_b->link == NULL) { + /* Unconnected inputs are expected to have the same value. */ + if(!Node::equals_value(other, input_a->socket_type)) { + return false; + } + } + else if(input_a->link != NULL && input_b->link != NULL) { + /* Expect links are to come from the same exact socket. */ + if(input_a->link != input_b->link) { + return false; + } + } + else { + /* One socket has a link and another has not, inputs can't be + * considered equal. + */ + return false; + } + } + + return true; +} + /* Graph */ ShaderGraph::ShaderGraph() @@ -256,18 +245,18 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) return; } - if(from->type != to->type) { + if(from->type() != to->type()) { /* for closures we can't do automatic conversion */ - if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) { + if(from->type() == SocketType::CLOSURE || to->type() == SocketType::CLOSURE) { fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure " "(%s.%s to %s.%s).\n", - from->parent->name.c_str(), from->name, - to->parent->name.c_str(), to->name); + from->parent->name.c_str(), from->name().c_str(), + to->parent->name.c_str(), to->name().c_str()); return; } /* add automatic conversion node in case of type mismatch */ - ShaderNode *convert = add(new ConvertNode(from->type, to->type, true)); + ShaderNode *convert = add(new ConvertNode(from->type(), to->type(), true)); connect(from, convert->inputs[0]); connect(convert->outputs[0], to); @@ -279,6 +268,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) } } +void ShaderGraph::disconnect(ShaderOutput *from) +{ + assert(!finalized); + + foreach(ShaderInput *sock, from->links) { + sock->link = NULL; + } + + from->links.clear(); +} + void ShaderGraph::disconnect(ShaderInput *to) { assert(!finalized); @@ -374,24 +374,12 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) ShaderNode *nnode = node->clone(); nnodemap[node] = nnode; + /* create new inputs and outputs to recreate links and ensure + * that we still point to valid SocketType if the NodeType + * changed in cloning, as it does for OSL nodes */ nnode->inputs.clear(); nnode->outputs.clear(); - - foreach(ShaderInput *input, node->inputs) { - ShaderInput *ninput = new ShaderInput(*input); - nnode->inputs.push_back(ninput); - - ninput->parent = nnode; - ninput->link = NULL; - } - - foreach(ShaderOutput *output, node->outputs) { - ShaderOutput *noutput = new ShaderOutput(*output); - nnode->outputs.push_back(noutput); - - noutput->parent = nnode; - noutput->links.clear(); - } + nnode->create_inputs_outputs(nnode->type); } /* recreate links */ @@ -401,8 +389,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) /* find new input and output */ ShaderNode *nfrom = nnodemap[input->link->parent]; ShaderNode *nto = nnodemap[input->parent]; - ShaderOutput *noutput = nfrom->output(input->link->name); - ShaderInput *ninput = nto->input(input->name); + ShaderOutput *noutput = nfrom->output(input->link->name()); + ShaderInput *ninput = nto->input(input->name()); /* connect */ connect(noutput, ninput); @@ -447,10 +435,10 @@ void ShaderGraph::remove_proxy_nodes() vector<ShaderInput*> links = tonode->outputs[0]->links; foreach(ShaderInput *autoin, links) { - if(autoin->default_value == ShaderInput::NONE) - all_links_removed = false; - else + if(autoin->flags() & SocketType::DEFAULT_LINK_MASK) disconnect(autoin); + else + all_links_removed = false; } if(all_links_removed) @@ -460,8 +448,7 @@ void ShaderGraph::remove_proxy_nodes() disconnect(to); /* transfer the default input value to the target socket */ - to->set(input->value); - to->set(input->value_string); + tonode->copy_value(to->socket_type, *proxy, input->socket_type); } } @@ -527,16 +514,8 @@ void ShaderGraph::constant_fold() } } /* Optimize current node. */ - float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f); - if(node->constant_fold(this, output, &optimized_value)) { - /* Apply optimized value to connected sockets. */ - vector<ShaderInput*> links(output->links); - foreach(ShaderInput *input, links) { - /* Assign value and disconnect the optimizedinput. */ - input->value = optimized_value; - disconnect(input); - } - } + ConstantFolder folder(this, node, output); + node->constant_fold(folder); } } } @@ -561,8 +540,8 @@ void ShaderGraph::deduplicate_nodes() * already deduplicated. */ - ShaderNodeSet scheduled; - map<ustring, ShaderNodeSet> done; + ShaderNodeSet scheduled, done; + map<ustring, ShaderNodeSet> candidates; queue<ShaderNode*> traverse_queue; /* Schedule nodes which doesn't have any dependencies. */ @@ -576,7 +555,7 @@ void ShaderGraph::deduplicate_nodes() while(!traverse_queue.empty()) { ShaderNode *node = traverse_queue.front(); traverse_queue.pop(); - done[node->name].insert(node); + done.insert(node); /* Schedule the nodes which were depending on the current node. */ foreach(ShaderOutput *output, node->outputs) { foreach(ShaderInput *input, output->links) { @@ -587,35 +566,28 @@ void ShaderGraph::deduplicate_nodes() continue; } /* Schedule node if its inputs are fully done. */ - if(check_node_inputs_traversed(input->parent, done[input->parent->name])) { + if(check_node_inputs_traversed(input->parent, done)) { traverse_queue.push(input->parent); scheduled.insert(input->parent); } } } /* Try to merge this node with another one. */ - foreach(ShaderNode *other_node, done[node->name]) { - if(node == other_node) { - /* Don't merge with self. */ - continue; - } - if(node->name != other_node->name) { - /* Can only de-duplicate nodes of the same type. */ - continue; - } - if(!check_node_inputs_equals(node, other_node)) { - /* Node inputs are different, can't merge them, */ - continue; + ShaderNode *merge_with = NULL; + foreach(ShaderNode *other_node, candidates[node->type->name]) { + if (node != other_node && node->equals(*other_node)) { + merge_with = other_node; + break; } - if(!node->equals(other_node)) { - /* Node settings are different. */ - continue; - } - /* TODO(sergey): Consider making it an utility function. */ + } + /* If found an equivalent, merge; otherwise keep node for later merges */ + if (merge_with != NULL) { for(int i = 0; i < node->outputs.size(); ++i) { - relink(node, node->outputs[i], other_node->outputs[i]); + relink(node, node->outputs[i], merge_with->outputs[i]); } - break; + } + else { + candidates[node->type->name].insert(node); } } } @@ -706,38 +678,38 @@ void ShaderGraph::default_inputs(bool do_osl) foreach(ShaderNode *node, nodes) { foreach(ShaderInput *input, node->inputs) { - if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) { - if(input->default_value == ShaderInput::TEXTURE_GENERATED) { + if(!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) { + if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { if(!texco) texco = new TextureCoordinateNode(); connect(texco->output("Generated"), input); } - else if(input->default_value == ShaderInput::TEXTURE_UV) { + else if(input->flags() & SocketType::LINK_TEXTURE_UV) { if(!texco) texco = new TextureCoordinateNode(); connect(texco->output("UV"), input); } - else if(input->default_value == ShaderInput::INCOMING) { + else if(input->flags() & SocketType::LINK_INCOMING) { if(!geom) geom = new GeometryNode(); connect(geom->output("Incoming"), input); } - else if(input->default_value == ShaderInput::NORMAL) { + else if(input->flags() & SocketType::LINK_NORMAL) { if(!geom) geom = new GeometryNode(); connect(geom->output("Normal"), input); } - else if(input->default_value == ShaderInput::POSITION) { + else if(input->flags() & SocketType::LINK_POSITION) { if(!geom) geom = new GeometryNode(); connect(geom->output("Position"), input); } - else if(input->default_value == ShaderInput::TANGENT) { + else if(input->flags() & SocketType::LINK_TANGENT) { if(!geom) geom = new GeometryNode(); @@ -785,8 +757,8 @@ void ShaderGraph::refine_bump_nodes() pair.second->bump = SHADER_BUMP_DY; ShaderOutput *out = bump_input->link; - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); connect(out_dx, node->input("SampleX")); connect(out_dy, node->input("SampleY")); @@ -860,9 +832,9 @@ void ShaderGraph::bump_from_displacement() ShaderNode *bump = add(new BumpNode()); ShaderOutput *out = displacement_in->link; - ShaderOutput *out_center = nodes_center[out->parent]->output(out->name); - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + ShaderOutput *out_center = nodes_center[out->parent]->output(out->name()); + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); connect(out_center, bump->input("SampleCenter")); connect(out_dx, bump->input("SampleX")); @@ -882,7 +854,7 @@ void ShaderGraph::bump_from_displacement() continue; } foreach(ShaderInput *input, node->inputs) { - if(!input->link && input->default_value == ShaderInput::NORMAL) + if(!input->link && (input->flags() & SocketType::LINK_NORMAL)) connect(set_normal->output("Normal"), input); } } @@ -918,14 +890,15 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(fin) { /* mix closure: add node to mix closure weights */ - ShaderNode *mix_node = add(new MixClosureWeightNode()); + MixClosureWeightNode *mix_node = new MixClosureWeightNode(); + add(mix_node); ShaderInput *fac_in = mix_node->input("Fac"); ShaderInput *weight_in = mix_node->input("Weight"); if(fin->link) connect(fin->link, fac_in); else - fac_in->value = fin->value; + mix_node->fac = node->get_float(fin->socket_type); if(weight_out) connect(weight_out, weight_in); @@ -952,20 +925,20 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight return; /* already has a weight connected to it? add weights */ - if(weight_in->link || weight_in->value.x != 0.0f) { - ShaderNode *math_node = add(new MathNode()); - ShaderInput *value1_in = math_node->input("Value1"); - ShaderInput *value2_in = math_node->input("Value2"); + float weight_value = node->get_float(weight_in->socket_type); + if(weight_in->link || weight_value != 0.0f) { + MathNode *math_node = new MathNode(); + add(math_node); if(weight_in->link) - connect(weight_in->link, value1_in); + connect(weight_in->link, math_node->input("Value1")); else - value1_in->value = weight_in->value; + math_node->value1 = weight_value; if(weight_out) - connect(weight_out, value2_in); + connect(weight_out, math_node->input("Value2")); else - value2_in->value.x = 1.0f; + math_node->value2 = 1.0f; weight_out = math_node->output("Value"); if(weight_in->link) @@ -976,7 +949,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(weight_out) connect(weight_out, weight_in); else - weight_in->value.x += 1.0f; + node->set(weight_in->socket_type, weight_value + 1.0f); } } @@ -994,6 +967,9 @@ int ShaderGraph::get_num_closures() else if(CLOSURE_IS_GLASS(closure_type)) { num_closures += 2; } + else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) { + num_closures += 2; + } else { ++num_closures; } @@ -1024,7 +1000,7 @@ void ShaderGraph::dump_graph(const char *filename) if(socket != node->inputs[0]) { fprintf(fd, "|"); } - fprintf(fd, "<IN_%p>%s", socket, socket->name); + fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str()); } fprintf(fd, "}|"); } @@ -1044,7 +1020,7 @@ void ShaderGraph::dump_graph(const char *filename) if(socket != node->outputs[0]) { fprintf(fd, "|"); } - fprintf(fd, "<OUT_%p>%s", socket, socket->name); + fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str()); } fprintf(fd, "}"); } @@ -1058,7 +1034,7 @@ void ShaderGraph::dump_graph(const char *filename) "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n", output, input, - output->name, input->name); + output->name().c_str(), input->name().c_str()); fprintf(fd, "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n", output->parent, diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index bd3f5ca689a..b35be48d8ca 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * 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. @@ -17,6 +17,9 @@ #ifndef __GRAPH_H__ #define __GRAPH_H__ +#include "node.h" +#include "node_type.h" + #include "kernel_types.h" #include "util_list.h" @@ -38,23 +41,7 @@ class ShaderGraph; class SVMCompiler; class OSLCompiler; class OutputNode; - -/* Socket Type - * - * Data type for inputs and outputs */ - -enum ShaderSocketType { - SHADER_SOCKET_UNDEFINED, - - SHADER_SOCKET_FLOAT, - SHADER_SOCKET_INT, - SHADER_SOCKET_COLOR, - SHADER_SOCKET_VECTOR, - SHADER_SOCKET_POINT, - SHADER_SOCKET_NORMAL, - SHADER_SOCKET_CLOSURE, - SHADER_SOCKET_STRING -}; +class ConstantFolder; /* Bump * @@ -86,30 +73,6 @@ enum ShaderNodeSpecialType { SHADER_SPECIAL_TYPE_BUMP, }; -/* Enum - * - * Utility class for enum values. */ - -class ShaderEnum { -public: - bool empty() const { return left.empty(); } - void insert(const char *x, int y) { - left[ustring(x)] = y; - right[y] = ustring(x); - } - - bool exists(ustring x) { return left.find(x) != left.end(); } - bool exists(int y) { return right.find(y) != right.end(); } - - int operator[](const char *x) { return left[ustring(x)]; } - int operator[](ustring x) { return left[x]; } - ustring operator[](int y) { return right[y]; } - -protected: - map<ustring, int> left; - map<int, ustring> right; -}; - /* Input * * Input socket for a shader node. May be linked to an output or not. If not @@ -118,39 +81,21 @@ protected: class ShaderInput { public: - enum DefaultValue { - TEXTURE_GENERATED, - TEXTURE_UV, - INCOMING, - NORMAL, - POSITION, - TANGENT, - NONE - }; - - enum Usage { - USE_SVM = 1, - USE_OSL = 2, - USE_ALL = USE_SVM|USE_OSL - }; - - ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type); - void set(const float3& v) { value = v; } - void set(float f) { value = make_float3(f, 0, 0); } - void set(const ustring v) { value_string = v; } - - const char *name; - ShaderSocketType type; + ShaderInput(const SocketType& socket_type_, ShaderNode* parent_) + : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID) + {} - ShaderNode *parent; - ShaderOutput *link; + ustring name() { return socket_type.ui_name; } + int flags() { return socket_type.flags; } + SocketType::Type type() { return socket_type.type; } - DefaultValue default_value; - float3 value; - ustring value_string; + void set(float f) { ((Node*)parent)->set(socket_type, f); } + void set(float3 f) { ((Node*)parent)->set(socket_type, f); } + const SocketType& socket_type; + ShaderNode *parent; + ShaderOutput *link; int stack_offset; /* for SVM compiler */ - int usage; }; /* Output @@ -159,14 +104,16 @@ public: class ShaderOutput { public: - ShaderOutput(ShaderNode *parent, const char *name, ShaderSocketType type); + ShaderOutput(const SocketType& socket_type_, ShaderNode* parent_) + : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID) + {} - const char *name; - ShaderNode *parent; - ShaderSocketType type; + ustring name() { return socket_type.ui_name; } + SocketType::Type type() { return socket_type.type; } + const SocketType& socket_type; + ShaderNode *parent; vector<ShaderInput*> links; - int stack_offset; /* for SVM compiler */ }; @@ -175,18 +122,17 @@ public: * Shader node in graph, with input and output sockets. This is the virtual * base class for all node types. */ -class ShaderNode { +class ShaderNode : public Node { public: - explicit ShaderNode(const char *name); + explicit ShaderNode(const NodeType *type); virtual ~ShaderNode(); + void create_inputs_outputs(const NodeType *type); + ShaderInput *input(const char *name); ShaderOutput *output(const char *name); - - ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL); - ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL); - ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL); - ShaderOutput *add_output(const char *name, ShaderSocketType type); + ShaderInput *input(ustring name); + ShaderOutput *output(ustring name); virtual ShaderNode *clone() const = 0; virtual void attributes(Shader *shader, AttributeRequestSet *attributes); @@ -195,7 +141,7 @@ public: /* ** Node optimization ** */ /* Check whether the node can be replaced with single constant. */ - virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; } + virtual void constant_fold(const ConstantFolder& /*folder*/) {} /* Simplify settings used by artists to the ones which are simpler to * evaluate in the kernel but keep the final result unchanged. @@ -213,7 +159,6 @@ public: vector<ShaderInput*> inputs; vector<ShaderOutput*> outputs; - ustring name; /* name, not required to be unique */ int id; /* index in graph node array */ ShaderBump bump; /* for bump mapping utility */ @@ -249,23 +194,21 @@ public: * NOTE: If some node can't be de-duplicated for whatever reason it * is to be handled in the subclass. */ - virtual bool equals(const ShaderNode *other) - { - return name == other->name && - bump == other->bump; - } + virtual bool equals(const ShaderNode& other); }; /* Node definition utility macros */ #define SHADER_NODE_CLASS(type) \ + NODE_DECLARE; \ type(); \ virtual ShaderNode *clone() const { return new type(*this); } \ virtual void compile(SVMCompiler& compiler); \ virtual void compile(OSLCompiler& compiler); \ #define SHADER_NODE_NO_CLONE_CLASS(type) \ + NODE_DECLARE; \ type(); \ virtual void compile(SVMCompiler& compiler); \ virtual void compile(OSLCompiler& compiler); \ @@ -307,6 +250,7 @@ public: OutputNode *output(); void connect(ShaderOutput *from, ShaderInput *to); + void disconnect(ShaderOutput *from); void disconnect(ShaderInput *to); void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 6650c98aa38..614620c14af 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -36,59 +36,66 @@ ImageManager::ImageManager(const DeviceInfo& info) osl_texture_system = NULL; animation_frame = 0; - /* Set image limits */ + /* In case of multiple devices used we need to know type of an actual + * compute device. + * + * NOTE: We assume that all the devices are same type, otherwise we'll + * be screwed on so many levels.. + */ + DeviceType device_type = info.type; + if (device_type == DEVICE_MULTI) { + device_type = info.multi_devices[0].type; + } - /* CPU */ - if(info.type == DEVICE_CPU) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CPU; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CPU; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CPU; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CPU; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CPU; + /* Set image limits */ +#define SET_TEX_IMAGES_LIMITS(ARCH) \ + { \ + tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF4] = TEX_NUM_HALF4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF] = TEX_NUM_HALF_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF4] = TEX_START_HALF4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF] = TEX_START_HALF_ ## ARCH; \ } - /* CUDA (Fermi) */ - else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.has_bindless_textures) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA; + + if(device_type == DEVICE_CPU) { + SET_TEX_IMAGES_LIMITS(CPU); } - /* CUDA (Kepler and above) */ - else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.has_bindless_textures) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA_KEPLER; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA_KEPLER; - tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA_KEPLER; - tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA_KEPLER; + else if(device_type == DEVICE_CUDA) { + if(info.has_bindless_textures) { + SET_TEX_IMAGES_LIMITS(CUDA_KEPLER); + } + else { + SET_TEX_IMAGES_LIMITS(CUDA); + } } - /* OpenCL */ - else if(info.pack_images) { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_OPENCL; - tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_OPENCL; - tex_image_byte4_start = TEX_IMAGE_BYTE4_START_OPENCL; - tex_image_float_start = TEX_IMAGE_FLOAT_START_OPENCL; - tex_image_byte_start = TEX_IMAGE_BYTE_START_OPENCL; + else if(device_type == DEVICE_OPENCL) { + SET_TEX_IMAGES_LIMITS(OPENCL); } - /* Should never happen */ else { - tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; + /* Should not happen. */ tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = 0; + tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0; - tex_image_byte4_start = 0; - tex_image_float_start = 0; - tex_image_byte_start = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF] = 0; + tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0; + tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0; + tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0; + tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF] = 0; assert(0); } + +#undef SET_TEX_IMAGES_LIMITS } ImageManager::~ImageManager() @@ -129,7 +136,7 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen void *builtin_data, bool& is_linear) { - bool is_float = false; + bool is_float = false, is_half = false; is_linear = false; int channels = 4; @@ -168,6 +175,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen } } + /* check if it's half float */ + if(spec.format == TypeDesc::HALF) + is_half = true; + channels = spec.nchannels; /* basic color space detection, not great but better than nothing @@ -193,7 +204,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen delete in; } - if(is_float) { + if(is_half) { + return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + } + else if(is_float) { return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; } else { @@ -207,34 +221,20 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen * to device ones and vice versa. */ int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type) { - if(type == IMAGE_DATA_TYPE_BYTE4) - return slot + tex_image_byte4_start; - else if(type == IMAGE_DATA_TYPE_FLOAT) - return slot + tex_image_float_start; - else if(type == IMAGE_DATA_TYPE_BYTE) - return slot + tex_image_byte_start; - else - return slot; + return slot + tex_start_images[type]; } int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type) { - if(flat_slot >= tex_image_byte_start) { - *type = IMAGE_DATA_TYPE_BYTE; - return flat_slot - tex_image_byte_start; - } - else if(flat_slot >= tex_image_float_start) { - *type = IMAGE_DATA_TYPE_FLOAT; - return flat_slot - tex_image_float_start; - } - else if(flat_slot >= tex_image_byte4_start) { - *type = IMAGE_DATA_TYPE_BYTE4; - return flat_slot - tex_image_byte4_start; - } - else { - *type = IMAGE_DATA_TYPE_FLOAT4; - return flat_slot; + for(int i = IMAGE_DATA_NUM_TYPES - 1; i >= 0; i--) { + if(flat_slot >= tex_start_images[i]) { + *type = (ImageDataType)i; + return flat_slot - tex_start_images[i]; + } } + + /* Should not happen. */ + return flat_slot; } string ImageManager::name_from_type(int type) @@ -245,6 +245,10 @@ string ImageManager::name_from_type(int type) return "float"; else if(type == IMAGE_DATA_TYPE_BYTE) return "byte"; + else if(type == IMAGE_DATA_TYPE_HALF4) + return "half4"; + else if(type == IMAGE_DATA_TYPE_HALF) + return "half"; else return "byte4"; } @@ -280,11 +284,16 @@ int ImageManager::add_image(const string& filename, if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4) is_float = true; - /* No single channel textures on CUDA (Fermi) and OpenCL, use available slots */ - if(type == IMAGE_DATA_TYPE_FLOAT && tex_num_images[type] == 0) + /* No single channel and half textures on CUDA (Fermi) and OpenCL, use available slots */ + if((type == IMAGE_DATA_TYPE_FLOAT || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_HALF) && + tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_FLOAT4; - if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) + } + if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_BYTE4; + } /* Fnd existing image. */ for(slot = 0; slot < images[type].size(); slot++) { @@ -660,6 +669,107 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_ return true; } +template<typename T> +bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img) +{ + ImageInput *in = NULL; + int width, height, depth, components; + + if(!file_load_image_generic(img, &in, width, height, depth, components)) + return false; + + /* read RGBA pixels */ + half *pixels = (half*)tex_img.resize(width, height, depth); + if(pixels == NULL) { + return false; + } + + if(in) { + half *readpixels = pixels; + vector<half> tmppixels; + + if(components > 4) { + tmppixels.resize(((size_t)width)*height*components); + readpixels = &tmppixels[0]; + } + + if(depth <= 1) { + int scanlinesize = width*components*sizeof(half); + + in->read_image(TypeDesc::HALF, + (uchar*)readpixels + (height-1)*scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); + } + else { + in->read_image(TypeDesc::HALF, (uchar*)readpixels); + } + + if(components > 4) { + size_t dimensions = ((size_t)width)*height; + for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i*4+3] = tmppixels[i*components+3]; + pixels[i*4+2] = tmppixels[i*components+2]; + pixels[i*4+1] = tmppixels[i*components+1]; + pixels[i*4+0] = tmppixels[i*components+0]; + } + + tmppixels.clear(); + } + + in->close(); + delete in; + } +#if 0 + /* TODO(dingto): Support half for ImBuf. */ + else { + builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels); + } +#endif + + /* Check if we actually have a half4 slot, in case components == 1, but device + * doesn't support single channel textures. */ + if(type == IMAGE_DATA_TYPE_HALF4) { + size_t num_pixels = ((size_t)width) * height * depth; + if(components == 2) { + /* grayscale + alpha */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = pixels[i*2+1]; + pixels[i*4+2] = pixels[i*2+0]; + pixels[i*4+1] = pixels[i*2+0]; + pixels[i*4+0] = pixels[i*2+0]; + } + } + else if(components == 3) { + /* RGB */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i*3+2]; + pixels[i*4+1] = pixels[i*3+1]; + pixels[i*4+0] = pixels[i*3+0]; + } + } + else if(components == 1) { + /* grayscale */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i]; + pixels[i*4+1] = pixels[i]; + pixels[i*4+0] = pixels[i]; + } + } + + if(img->use_alpha == false) { + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + } + } + } + + return true; +} + void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) { if(progress->get_cancel()) @@ -759,7 +869,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -782,6 +892,55 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + pixels[1] = TEX_IMAGE_MISSING_G; + pixels[2] = TEX_IMAGE_MISSING_B; + pixels[3] = TEX_IMAGE_MISSING_A; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } img->need_load = false; } @@ -827,7 +986,7 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -837,6 +996,26 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } delete images[type][slot]; images[type][slot] = NULL; @@ -897,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device, } } +uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot) +{ + uint8_t options = 0; + + /* Image Options are packed into one uint: + * bit 0 -> Interpolation + * bit 1 + 2 + 3-> Extension */ + if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST) + options |= (1 << 0); + + if(images[type][slot]->extension == EXTENSION_REPEAT) + options |= (1 << 1); + else if(images[type][slot]->extension == EXTENSION_EXTEND) + options |= (1 << 2); + else /* EXTENSION_CLIP */ + options |= (1 << 3); + + return options; +} + void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progress& /*progess*/) @@ -928,11 +1127,9 @@ void ImageManager::device_pack_images(Device *device, device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot]; - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -960,11 +1157,8 @@ void ImageManager::device_pack_images(Device *device, /* todo: support 3D textures, only CPU for now */ - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 2ab16dd8967..07998684b23 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -41,6 +41,8 @@ public: IMAGE_DATA_TYPE_BYTE4 = 1, IMAGE_DATA_TYPE_FLOAT = 2, IMAGE_DATA_TYPE_BYTE = 3, + IMAGE_DATA_TYPE_HALF4 = 4, + IMAGE_DATA_TYPE_HALF = 5, IMAGE_DATA_NUM_TYPES }; @@ -96,9 +98,8 @@ public: private: int tex_num_images[IMAGE_DATA_NUM_TYPES]; - int tex_image_byte4_start; - int tex_image_float_start; - int tex_image_byte_start; + int tex_start_images[IMAGE_DATA_NUM_TYPES]; + thread_mutex device_mutex; int animation_frame; @@ -114,10 +115,15 @@ private: template<typename T> bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + template<typename T> + bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + int type_index_to_flattened_slot(int slot, ImageDataType type); int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); string name_from_type(int type); + uint8_t pack_image_options(ImageDataType type, size_t slot); + void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 41e2571dc24..63914e57319 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -176,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene max_samples = max(max_samples, volume_samples); } - max_samples *= (max_bounce + transparent_max_bounce + 3); + max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS); int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM; dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); @@ -204,6 +204,11 @@ void Integrator::device_free(Device *device, DeviceScene *dscene) dscene->sobol_directions.clear(); } +bool Integrator::modified(const Integrator& integrator) +{ + return !Node::equals(integrator); +} + void Integrator::tag_update(Scene *scene) { foreach(Shader *shader, scene->shaders) { diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index a5cfb0c7863..39eaaf246d4 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -86,6 +86,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene); + bool modified(const Integrator& integrator); void tag_update(Scene *scene); }; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index c20bf6b5e9e..ae6042cef34 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -209,6 +209,29 @@ void LightManager::disable_ineffective_light(Device *device, Scene *scene) } } +bool LightManager::object_usable_as_light(Object *object) { + Mesh *mesh = object->mesh; + /* Skip if we are not visible for BSDFs. */ + if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) { + return false; + } + /* Skip motion blurred deforming meshes, not supported yet. */ + if(mesh->has_motion_blur()) { + return false; + } + /* Skip if we have no emission shaders. */ + /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll + * iterate all mesh shaders twice (when counting and when calculating + * triangle area. + */ + foreach(const Shader *shader, mesh->used_shaders) { + if(shader->use_mis && shader->has_surface_emission) { + return true; + } + } + return false; +} + void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { progress.set_status("Updating Lights", "Computing distribution"); @@ -226,39 +249,28 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen } foreach(Object *object, scene->objects) { - Mesh *mesh = object->mesh; - bool have_emission = false; - - /* skip if we are not visible for BSDFs */ - if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) - continue; + if(progress.get_cancel()) return; - /* skip motion blurred deforming meshes, not supported yet */ - if(mesh->has_motion_blur()) + if(!object_usable_as_light(object)) { continue; - - /* skip if we have no emission shaders */ - foreach(Shader *shader, mesh->used_shaders) { - if(shader->use_mis && shader->has_surface_emission) { - have_emission = true; - break; - } } + /* Count triangles. */ + Mesh *mesh = object->mesh; + size_t mesh_num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < mesh_num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) + ? mesh->used_shaders[shader_index] + : scene->default_surface; - /* count triangles */ - if(have_emission) { - for(size_t i = 0; i < mesh->triangles.size(); i++) { - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) ? - mesh->used_shaders[shader_index] : scene->default_surface; - - if(shader->use_mis && shader->has_surface_emission) - num_triangles++; + if(shader->use_mis && shader->has_surface_emission) { + num_triangles++; } } } size_t num_distribution = num_triangles + num_lights; + VLOG(1) << "Total " << num_distribution << " of light distribution primitives."; /* emission area */ float4 *distribution = dscene->light_distribution.resize(num_distribution + 1); @@ -269,86 +281,68 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen int j = 0; foreach(Object *object, scene->objects) { - Mesh *mesh = object->mesh; - bool have_emission = false; + if(progress.get_cancel()) return; - /* skip if we are not visible for BSDFs */ - if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) { + if(!object_usable_as_light(object)) { j++; continue; } + /* Sum area. */ + Mesh *mesh = object->mesh; + bool transform_applied = mesh->transform_applied; + Transform tfm = object->tfm; + int object_id = j; + int shader_flag = 0; - /* skip motion blurred deforming meshes, not supported yet */ - if(mesh->has_motion_blur()) { - j++; - continue; - } + if(transform_applied) + object_id = ~object_id; - /* skip if we have no emission shaders */ - foreach(Shader *shader, mesh->used_shaders) { - if(shader->use_mis && shader->has_surface_emission) { - have_emission = true; - break; - } + if(!(object->visibility & PATH_RAY_DIFFUSE)) { + shader_flag |= SHADER_EXCLUDE_DIFFUSE; + use_light_visibility = true; + } + if(!(object->visibility & PATH_RAY_GLOSSY)) { + shader_flag |= SHADER_EXCLUDE_GLOSSY; + use_light_visibility = true; + } + if(!(object->visibility & PATH_RAY_TRANSMIT)) { + shader_flag |= SHADER_EXCLUDE_TRANSMIT; + use_light_visibility = true; + } + if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) { + shader_flag |= SHADER_EXCLUDE_SCATTER; + use_light_visibility = true; } - /* sum area */ - if(have_emission) { - bool transform_applied = mesh->transform_applied; - Transform tfm = object->tfm; - int object_id = j; - int shader_flag = 0; - - if(transform_applied) - object_id = ~object_id; - - if(!(object->visibility & PATH_RAY_DIFFUSE)) { - shader_flag |= SHADER_EXCLUDE_DIFFUSE; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_GLOSSY)) { - shader_flag |= SHADER_EXCLUDE_GLOSSY; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_TRANSMIT)) { - shader_flag |= SHADER_EXCLUDE_TRANSMIT; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) { - shader_flag |= SHADER_EXCLUDE_SCATTER; - use_light_visibility = true; - } + size_t mesh_num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < mesh_num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) + ? mesh->used_shaders[shader_index] + : scene->default_surface; - for(size_t i = 0; i < mesh->triangles.size(); i++) { - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) ? - mesh->used_shaders[shader_index] : scene->default_surface; - - if(shader->use_mis && shader->has_surface_emission) { - distribution[offset].x = totarea; - distribution[offset].y = __int_as_float(i + mesh->tri_offset); - distribution[offset].z = __int_as_float(shader_flag); - distribution[offset].w = __int_as_float(object_id); - offset++; - - Mesh::Triangle t = mesh->triangles[i]; - float3 p1 = mesh->verts[t.v[0]]; - float3 p2 = mesh->verts[t.v[1]]; - float3 p3 = mesh->verts[t.v[2]]; - - if(!transform_applied) { - p1 = transform_point(&tfm, p1); - p2 = transform_point(&tfm, p2); - p3 = transform_point(&tfm, p3); - } - - totarea += triangle_area(p1, p2, p3); + if(shader->use_mis && shader->has_surface_emission) { + distribution[offset].x = totarea; + distribution[offset].y = __int_as_float(i + mesh->tri_offset); + distribution[offset].z = __int_as_float(shader_flag); + distribution[offset].w = __int_as_float(object_id); + offset++; + + Mesh::Triangle t = mesh->get_triangle(i); + float3 p1 = mesh->verts[t.v[0]]; + float3 p2 = mesh->verts[t.v[1]]; + float3 p3 = mesh->verts[t.v[2]]; + + if(!transform_applied) { + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + p3 = transform_point(&tfm, p3); } + + totarea += triangle_area(p1, p2, p3); } } - if(progress.get_cancel()) return; - j++; } @@ -441,9 +435,9 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen device->tex_alloc("__light_distribution", dscene->light_distribution); /* Portals */ - if(num_background_lights > 0 && light_index != scene->lights.size()) { + if(num_background_lights > 0 && light_index != num_lights) { kintegrator->portal_offset = light_index; - kintegrator->num_portals = scene->lights.size() - light_index; + kintegrator->num_portals = num_lights - light_index; kintegrator->portal_pdf = background_mis? 0.5f: 1.0f; } else { @@ -607,10 +601,21 @@ void LightManager::device_update_points(Device *device, Scene *scene) { int num_scene_lights = scene->lights.size(); - if(num_scene_lights == 0) + int num_lights = 0; + + foreach(Light *light, scene->lights) { + if(light->is_enabled) { + num_lights++; + } + } + + float4 *light_data = dscene->light_data.resize(num_lights*LIGHT_SIZE); + + if(num_lights == 0) { + VLOG(1) << "No effective light, ignoring points update."; return; + } - float4 *light_data = dscene->light_data.resize(num_scene_lights*LIGHT_SIZE); int light_index = 0; foreach(Light *light, scene->lights) { diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index 2f1df1c9417..745caa96159 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN class Device; class DeviceScene; +class Object; class Progress; class Scene; class Shader; @@ -108,6 +109,9 @@ protected: DeviceScene *dscene, Scene *scene, Progress& progress); + + /* Check whether light manager can use the object as a light-emissive. */ + bool object_usable_as_light(Object *object); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index d26404035eb..4cf0a785897 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -35,9 +35,6 @@ #include "util_progress.h" #include "util_set.h" -#include "subd_split.h" -#include "subd_patch.h" - CCL_NAMESPACE_BEGIN /* Triangle */ @@ -51,14 +48,45 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const /* Curve */ -void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const +void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const +{ + float3 P[4]; + + P[0] = curve_keys[max(first_key + k - 1,first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + +void Mesh::Curve::bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform& aligned_space, + BoundBox& bounds) const { float3 P[4]; - P[0] = float4_to_float3(curve_keys[max(first_key + k - 1,first_key)]); - P[1] = float4_to_float3(curve_keys[first_key + k]); - P[2] = float4_to_float3(curve_keys[first_key + k + 1]); - P[3] = float4_to_float3(curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]); + P[0] = curve_keys[max(first_key + k - 1,first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + + P[0] = transform_point(&aligned_space, P[0]); + P[1] = transform_point(&aligned_space, P[1]); + P[2] = transform_point(&aligned_space, P[2]); + P[3] = transform_point(&aligned_space, P[3]); float3 lower; float3 upper; @@ -67,27 +95,62 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b curvebounds(&lower.y, &upper.y, P, 1); curvebounds(&lower.z, &upper.z, P, 2); - float mr = max(curve_keys[first_key + k].w, curve_keys[first_key + k + 1].w); + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); bounds.grow(lower, mr); bounds.grow(upper, mr); } +/* SubdFace */ + +float3 Mesh::SubdFace::normal(const Mesh *mesh) const +{ + float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner+0]]; + float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner+1]]; + float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner+2]]; + + return safe_normalize(cross(v1 - v0, v2 - v0)); +} + + /* Mesh */ +NODE_DEFINE(Mesh) +{ + NodeType* type = NodeType::add("mesh", create); + + static NodeEnum displacement_method_enum; + displacement_method_enum.insert("bump", DISPLACE_BUMP); + displacement_method_enum.insert("true", DISPLACE_TRUE); + displacement_method_enum.insert("both", DISPLACE_BOTH); + SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP); + + SOCKET_UINT(motion_steps, "Motion Steps", 3); + SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + + SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); + SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>()); + SOCKET_INT_ARRAY(shader, "Shader", array<int>()); + SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>()); + + SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); + SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); + SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); + SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); + + return type; +} + Mesh::Mesh() +: Node(node_type) { need_update = true; need_update_rebuild = false; transform_applied = false; transform_negative_scaled = false; transform_normal = transform_identity(); - displacement_method = DISPLACE_BUMP; bounds = BoundBox::empty; - motion_steps = 3; - use_motion_blur = false; - bvh = NULL; tri_offset = 0; @@ -96,11 +159,24 @@ Mesh::Mesh() curve_offset = 0; curvekey_offset = 0; + patch_offset = 0; + face_offset = 0; + corner_offset = 0; + + num_subd_verts = 0; + attributes.triangle_mesh = this; curve_attributes.curve_mesh = this; + subd_attributes.subd_mesh = this; + + geometry_flags = GEOMETRY_NONE; has_volume = false; has_surface_bssrdf = false; + + num_ngons = 0; + + subdivision_type = SUBDIVISION_NONE; } Mesh::~Mesh() @@ -108,21 +184,73 @@ Mesh::~Mesh() delete bvh; } -void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys) +void Mesh::resize_mesh(int numverts, int numtris) { - /* reserve space to add verts and triangles later */ verts.resize(numverts); - triangles.resize(numtris); + triangles.resize(numtris * 3); shader.resize(numtris); smooth.resize(numtris); - forms_quad.resize(numtris); + if(subd_faces.size()) { + triangle_patch.resize(numtris); + vert_patch_uv.resize(numverts); + } + + attributes.resize(); +} + +void Mesh::reserve_mesh(int numverts, int numtris) +{ + /* reserve space to add verts and triangles later */ + verts.reserve(numverts); + triangles.reserve(numtris * 3); + shader.reserve(numtris); + smooth.reserve(numtris); + + if(subd_faces.size()) { + triangle_patch.reserve(numtris); + vert_patch_uv.reserve(numverts); + } + + attributes.resize(true); +} + +void Mesh::resize_curves(int numcurves, int numkeys) +{ + curve_keys.resize(numkeys); + curve_radius.resize(numkeys); + curve_first_key.resize(numcurves); + curve_shader.resize(numcurves); + + curve_attributes.resize(); +} + +void Mesh::reserve_curves(int numcurves, int numkeys) +{ + curve_keys.reserve(numkeys); + curve_radius.reserve(numkeys); + curve_first_key.reserve(numcurves); + curve_shader.reserve(numcurves); + + curve_attributes.resize(true); +} + +void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners) +{ + subd_faces.resize(numfaces); + subd_face_corners.resize(numcorners); + num_ngons = num_ngons_; + + subd_attributes.resize(); +} - curve_keys.resize(numcurvekeys); - curves.resize(numcurves); +void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners) +{ + subd_faces.reserve(numfaces); + subd_face_corners.reserve(numcorners); + num_ngons = num_ngons_; - attributes.reserve(); - curve_attributes.reserve(); + subd_attributes.resize(true); } void Mesh::clear() @@ -133,13 +261,22 @@ void Mesh::clear() shader.clear(); smooth.clear(); - forms_quad.clear(); + triangle_patch.clear(); + vert_patch_uv.clear(); curve_keys.clear(); - curves.clear(); + curve_radius.clear(); + curve_first_key.clear(); + curve_shader.clear(); + + subd_faces.clear(); + subd_face_corners.clear(); + + num_subd_verts = 0; attributes.clear(); curve_attributes.clear(); + subd_attributes.clear(); used_shaders.clear(); transform_applied = false; @@ -151,7 +288,7 @@ void Mesh::clear() int Mesh::split_vertex(int vertex) { /* copy vertex location and vertex attributes */ - verts.push_back(verts[vertex]); + add_vertex_slow(verts[vertex]); foreach(Attribute& attr, attributes.attributes) { if(attr.element == ATTR_ELEMENT_VERTEX) { @@ -161,51 +298,77 @@ int Mesh::split_vertex(int vertex) } } + foreach(Attribute& attr, subd_attributes.attributes) { + if(attr.element == ATTR_ELEMENT_VERTEX) { + vector<char> tmp(attr.data_sizeof()); + memcpy(&tmp[0], attr.data() + tmp.size()*vertex, tmp.size()); + attr.add(&tmp[0]); + } + } + return verts.size() - 1; } -void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_) +void Mesh::add_vertex(float3 P) +{ + verts.push_back_reserved(P); + + if(subd_faces.size()) { + vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f)); + } +} + +void Mesh::add_vertex_slow(float3 P) { - Triangle tri; - tri.v[0] = v0; - tri.v[1] = v1; - tri.v[2] = v2; - - triangles[i] = tri; - shader[i] = shader_; - smooth[i] = smooth_; - forms_quad[i] = forms_quad_; + verts.push_back_slow(P); + + if(subd_faces.size()) { + vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f)); + } } -void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_) +void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) { - Triangle tri; - tri.v[0] = v0; - tri.v[1] = v1; - tri.v[2] = v2; - - triangles.push_back(tri); - shader.push_back(shader_); - smooth.push_back(smooth_); - forms_quad.push_back(forms_quad_); + triangles.push_back_reserved(v0); + triangles.push_back_reserved(v1); + triangles.push_back_reserved(v2); + shader.push_back_reserved(shader_); + smooth.push_back_reserved(smooth_); + + if(subd_faces.size()) { + triangle_patch.push_back_reserved(-1); + } } void Mesh::add_curve_key(float3 co, float radius) { - float4 key = float3_to_float4(co); - key.w = radius; + curve_keys.push_back_reserved(co); + curve_radius.push_back_reserved(radius); +} - curve_keys.push_back(key); +void Mesh::add_curve(int first_key, int shader) +{ + curve_first_key.push_back_reserved(first_key); + curve_shader.push_back_reserved(shader); } -void Mesh::add_curve(int first_key, int num_keys, int shader) +void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth_) { - Curve curve; - curve.first_key = first_key; - curve.num_keys = num_keys; - curve.shader = shader; + int start_corner = subd_face_corners.size(); + + for(int i = 0; i < num_corners; i++) { + subd_face_corners.push_back_reserved(corners[i]); + } - curves.push_back(curve); + int ptex_offset = 0; + + if(subd_faces.size()) { + SubdFace& s = subd_faces[subd_faces.size()-1]; + ptex_offset = s.ptex_offset + s.num_ptex_faces(); + } + + SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset}; + subd_faces.push_back_reserved(face); } void Mesh::compute_bounds() @@ -219,7 +382,7 @@ void Mesh::compute_bounds() bnds.grow(verts[i]); for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w); + bnds.grow(curve_keys[i], curve_radius[i]); Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if(use_motion_blur && attr) { @@ -247,7 +410,7 @@ void Mesh::compute_bounds() bnds.grow_safe(verts[i]); for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w); + bnds.grow_safe(curve_keys[i], curve_radius[i]); if(use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); @@ -301,15 +464,14 @@ void Mesh::add_face_normals() float3 *fN = attr_fN->data_float3(); /* compute face normals */ - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); bool flip = transform_negative_scaled; if(triangles_size) { float3 *verts_ptr = &verts[0]; - Triangle *triangles_ptr = &triangles[0]; for(size_t i = 0; i < triangles_size; i++) { - fN[i] = compute_face_normal(triangles_ptr[i], verts_ptr); + fN[i] = compute_face_normal(get_triangle(i), verts_ptr); if(flip) fN[i] = -fN[i]; @@ -329,7 +491,7 @@ void Mesh::add_vertex_normals() { bool flip = transform_negative_scaled; size_t verts_size = verts.size(); - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); /* static vertex normals */ if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) { @@ -344,11 +506,10 @@ void Mesh::add_vertex_normals() memset(vN, 0, verts.size()*sizeof(float3)); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; for(size_t i = 0; i < triangles_size; i++) for(size_t j = 0; j < 3; j++) - vN[triangles_ptr[i].v[j]] += fN[i]; + vN[get_triangle(i).v[j]] += fN[i]; } for(size_t i = 0; i < verts_size; i++) { @@ -374,12 +535,10 @@ void Mesh::add_vertex_normals() memset(mN, 0, verts.size()*sizeof(float3)); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; - for(size_t i = 0; i < triangles_size; i++) { for(size_t j = 0; j < 3; j++) { - float3 fN = compute_face_normal(triangles_ptr[i], mP); - mN[triangles_ptr[i].v[j]] += fN; + float3 fN = compute_face_normal(get_triangle(i), mP); + mN[get_triangle(i).v[j]] += fN; } } } @@ -402,8 +561,8 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal) uint last_shader = -1; bool last_smooth = false; - size_t triangles_size = triangles.size(); - uint *shader_ptr = (shader.size())? &shader[0]: NULL; + size_t triangles_size = num_triangles(); + int *shader_ptr = (shader.size())? &shader[0]: NULL; bool do_transform = transform_applied; Transform ntfm = transform_normal; @@ -433,32 +592,34 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal) } } -void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) +void Mesh::pack_verts(const vector<uint>& tri_prim_index, + uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv, + size_t vert_offset, + size_t tri_offset) { size_t verts_size = verts.size(); - if(verts_size) { - float3 *verts_ptr = &verts[0]; + if(verts_size && subd_faces.size()) { + float2 *vert_patch_uv_ptr = &vert_patch_uv[0]; for(size_t i = 0; i < verts_size; i++) { - float3 p = verts_ptr[i]; - tri_verts[i] = make_float4(p.x, p.y, p.z, 0.0f); + tri_patch_uv[i] = vert_patch_uv_ptr[i]; } } - size_t triangles_size = triangles.size(); + size_t triangles_size = num_triangles(); if(triangles_size) { - Triangle *triangles_ptr = &triangles[0]; - for(size_t i = 0; i < triangles_size; i++) { - Triangle t = triangles_ptr[i]; + Triangle t = get_triangle(i); + tri_vindex[i] = make_uint4(t.v[0] + vert_offset, + t.v[1] + vert_offset, + t.v[2] + vert_offset, + tri_prim_index[i + tri_offset]); - tri_vindex[i] = make_float4( - __int_as_float(t.v[0] + vert_offset), - __int_as_float(t.v[1] + vert_offset), - __int_as_float(t.v[2] + vert_offset), - 0); + tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i]*8 + patch_offset); } } } @@ -466,27 +627,25 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset) { size_t curve_keys_size = curve_keys.size(); - float4 *keys_ptr = NULL; /* pack curve keys */ if(curve_keys_size) { - keys_ptr = &curve_keys[0]; + float3 *keys_ptr = &curve_keys[0]; + float *radius_ptr = &curve_radius[0]; for(size_t i = 0; i < curve_keys_size; i++) - curve_key_co[i] = keys_ptr[i]; + curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); } /* pack curve segments */ - size_t curve_num = curves.size(); + size_t curve_num = num_curves(); if(curve_num) { - Curve *curve_ptr = &curves[0]; - int shader_id = 0; - for(size_t i = 0; i < curve_num; i++) { - Curve curve = curve_ptr[i]; - Shader *shader = (curve.shader < used_shaders.size()) ? - used_shaders[curve.shader] : scene->default_surface; + Curve curve = get_curve(i); + int shader_id = curve_shader[i]; + Shader *shader = (shader_id < used_shaders.size()) ? + used_shaders[shader_id] : scene->default_surface; shader_id = scene->shader_manager->get_shader_id(shader, this, false); curve_data[i] = make_float4( @@ -498,7 +657,60 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s } } -void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total) +void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset) +{ + size_t num_faces = subd_faces.size(); + int ngons = 0; + + if(num_faces) { + for(size_t f = 0; f < num_faces; f++) { + SubdFace face = subd_faces[f]; + + if(face.is_quad()) { + int c[4]; + memcpy(c, &subd_face_corners[face.start_corner], sizeof(int)*4); + + *(patch_data++) = c[0] + vert_offset; + *(patch_data++) = c[1] + vert_offset; + *(patch_data++) = c[2] + vert_offset; + *(patch_data++) = c[3] + vert_offset; + + *(patch_data++) = f+face_offset; + *(patch_data++) = face.num_corners; + *(patch_data++) = face.start_corner + corner_offset; + *(patch_data++) = 0; + } + else { + for(int i = 0; i < face.num_corners; i++) { + int c[4]; + c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)]; + c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)]; + c[2] = verts.size() - num_subd_verts + ngons; + c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)]; + + *(patch_data++) = c[0] + vert_offset; + *(patch_data++) = c[1] + vert_offset; + *(patch_data++) = c[2] + vert_offset; + *(patch_data++) = c[3] + vert_offset; + + *(patch_data++) = f+face_offset; + *(patch_data++) = face.num_corners | (i << 16); + *(patch_data++) = face.start_corner + corner_offset; + *(patch_data++) = subd_face_corners.size() + ngons + corner_offset; + } + + ngons++; + } + } + } +} + + +void Mesh::compute_bvh(DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total) { if(progress->get_cancel()) return; @@ -529,6 +741,8 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total BVHParams bparams; bparams.use_spatial_split = params->use_bvh_spatial_split; bparams.use_qbvh = params->use_qbvh; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, objects); @@ -621,8 +835,9 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att osl_attr.value = attr; osl_attr.offset = 0; - og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr; og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; } /* find mesh attributes */ @@ -652,11 +867,11 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att if(req.std != ATTR_STD_NONE) { /* if standard attribute, add lookup by geom: name convention */ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; } else if(req.name != ustring()) { /* add lookup by mesh attribute name */ - og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; } } @@ -681,6 +896,28 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; } } + + if(req.subd_element != ATTR_ELEMENT_NONE) { + osl_attr.elem = req.subd_element; + osl_attr.offset = req.subd_offset; + + if(req.subd_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if(req.subd_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else + osl_attr.type = TypeDesc::TypeColor; + + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; + } + } } } #else @@ -732,7 +969,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce else id = scene->shader_manager->get_attribute_id(req.std); - if(mesh->triangles.size()) { + if(mesh->num_triangles()) { attr_map[index].x = id; attr_map[index].y = req.triangle_element; attr_map[index].z = as_uint(req.triangle_offset); @@ -747,7 +984,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce index++; - if(mesh->curves.size()) { + if(mesh->num_curves()) { attr_map[index].x = id; attr_map[index].y = req.curve_element; attr_map[index].z = as_uint(req.curve_offset); @@ -761,22 +998,32 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce } index++; - } - /* terminator */ - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; + if(mesh->subd_faces.size()) { + attr_map[index].x = id; + attr_map[index].y = req.subd_element; + attr_map[index].z = as_uint(req.subd_offset); - index++; + if(req.subd_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if(req.subd_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; + index++; + } + + /* terminator */ + for(int i = 0; i < ATTR_PRIM_TYPES; i++) { + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; - index++; + index++; + } } /* copy to device */ @@ -786,17 +1033,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce static void update_attribute_element_size(Mesh *mesh, Attribute *mattr, + AttributePrimitive prim, size_t *attr_float_size, size_t *attr_float3_size, size_t *attr_uchar4_size) { if(mattr) { - size_t size = mattr->element_size( - mesh->verts.size(), - mesh->triangles.size(), - mesh->motion_steps, - mesh->curves.size(), - mesh->curve_keys.size()); + size_t size = mattr->element_size(mesh, prim); if(mattr->element == ATTR_ELEMENT_VOXEL) { /* pass */ @@ -824,6 +1067,7 @@ static void update_attribute_element_offset(Mesh *mesh, vector<uchar4>& attr_uchar4, size_t& attr_uchar4_offset, Attribute *mattr, + AttributePrimitive prim, TypeDesc& type, int& offset, AttributeElement& element) @@ -834,12 +1078,7 @@ static void update_attribute_element_offset(Mesh *mesh, type = mattr->type; /* store attribute data in arrays */ - size_t size = mattr->element_size( - mesh->verts.size(), - mesh->triangles.size(), - mesh->motion_steps, - mesh->curves.size(), - mesh->curve_keys.size()); + size_t size = mattr->element_size(mesh, prim); if(mattr->element == ATTR_ELEMENT_VOXEL) { /* store slot in offset value */ @@ -893,10 +1132,18 @@ static void update_attribute_element_offset(Mesh *mesh, offset -= mesh->vert_offset; else if(element == ATTR_ELEMENT_VERTEX_MOTION) offset -= mesh->vert_offset; - else if(element == ATTR_ELEMENT_FACE) - offset -= mesh->tri_offset; - else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) - offset -= 3*mesh->tri_offset; + else if(element == ATTR_ELEMENT_FACE) { + if(prim == ATTR_PRIM_TRIANGLE) + offset -= mesh->tri_offset; + else + offset -= mesh->face_offset; + } + else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if(prim == ATTR_PRIM_TRIANGLE) + offset -= 3*mesh->tri_offset; + else + offset -= mesh->corner_offset; + } else if(element == ATTR_ELEMENT_CURVE) offset -= mesh->curve_offset; else if(element == ATTR_ELEMENT_CURVE_KEY) @@ -946,23 +1193,23 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, foreach(AttributeRequest& req, attributes.requests) { Attribute *triangle_mattr = mesh->attributes.find(req); Attribute *curve_mattr = mesh->curve_attributes.find(req); - - /* todo: get rid of this exception, it's only here for giving some - * working texture coordinate for subdivision as we can't preserve - * any attributes yet */ - if(!triangle_mattr && req.std == ATTR_STD_GENERATED) { - triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED); - if(mesh->verts.size()) - memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); - } + Attribute *subd_mattr = mesh->subd_attributes.find(req); update_attribute_element_size(mesh, triangle_mattr, + ATTR_PRIM_TRIANGLE, &attr_float_size, &attr_float3_size, &attr_uchar4_size); update_attribute_element_size(mesh, curve_mattr, + ATTR_PRIM_CURVE, + &attr_float_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + subd_mattr, + ATTR_PRIM_SUBD, &attr_float_size, &attr_float3_size, &attr_uchar4_size); @@ -987,12 +1234,14 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, foreach(AttributeRequest& req, attributes.requests) { Attribute *triangle_mattr = mesh->attributes.find(req); Attribute *curve_mattr = mesh->curve_attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); update_attribute_element_offset(mesh, attr_float, attr_float_offset, attr_float3, attr_float3_offset, attr_uchar4, attr_uchar4_offset, triangle_mattr, + ATTR_PRIM_TRIANGLE, req.triangle_type, req.triangle_offset, req.triangle_element); @@ -1002,10 +1251,21 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, attr_float3, attr_float3_offset, attr_uchar4, attr_uchar4_offset, curve_mattr, + ATTR_PRIM_CURVE, req.curve_type, req.curve_offset, req.curve_element); + update_attribute_element_offset(mesh, + attr_float, attr_float_offset, + attr_float3, attr_float3_offset, + attr_uchar4, attr_uchar4_offset, + subd_mattr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_offset, + req.subd_element); + if(progress.get_cancel()) return; } } @@ -1035,15 +1295,18 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, } } -void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void MeshManager::mesh_calc_offset(Scene *scene) { - /* count and update offsets */ size_t vert_size = 0; size_t tri_size = 0; size_t curve_key_size = 0; size_t curve_size = 0; + size_t patch_size = 0; + size_t face_size = 0; + size_t corner_size = 0; + foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; @@ -1051,26 +1314,97 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene mesh->curvekey_offset = curve_key_size; mesh->curve_offset = curve_size; + mesh->patch_offset = patch_size; + mesh->face_offset = face_size; + mesh->corner_offset = corner_size; + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->num_curves(); + + if(mesh->subd_faces.size()) { + Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + } + face_size += mesh->subd_faces.size(); + corner_size += mesh->subd_face_corners.size(); + } +} + +void MeshManager::device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress& progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + + size_t patch_size = 0; + + foreach(Mesh *mesh, scene->meshes) { vert_size += mesh->verts.size(); - tri_size += mesh->triangles.size(); + tri_size += mesh->num_triangles(); curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->curves.size(); + curve_size += mesh->num_curves(); + + if(mesh->subd_faces.size()) { + Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + } } + /* Create mapping from triangle to primitive triangle array. */ + vector<uint> tri_prim_index(tri_size); + if(for_displacement) { + /* For displacement kernels we do some trickery to make them believe + * we've got all required data ready. However, that data is different + * from final render kernels since we don't have BVH yet, so can't + * really use same semantic of arrays. + */ + foreach(Mesh *mesh, scene->meshes) { + for(size_t i = 0; i < mesh->num_triangles(); ++i) { + tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset); + } + } + } + else { + PackedBVH& pack = bvh->pack; + for(size_t i = 0; i < pack.prim_index.size(); ++i) { + if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i]; + } + } + } + + /* Fill in all the arrays. */ if(tri_size != 0) { /* normals */ progress.set_status("Updating Mesh", "Computing normals"); uint *tri_shader = dscene->tri_shader.resize(tri_size); float4 *vnormal = dscene->tri_vnormal.resize(vert_size); - float4 *tri_verts = dscene->tri_verts.resize(vert_size); - float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + uint *tri_patch = dscene->tri_patch.resize(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.resize(vert_size); foreach(Mesh *mesh, scene->meshes) { - mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]); - mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); - + mesh->pack_normals(scene, + &tri_shader[mesh->tri_offset], + &vnormal[mesh->vert_offset]); + mesh->pack_verts(tri_prim_index, + &tri_vindex[mesh->tri_offset], + &tri_patch[mesh->tri_offset], + &tri_patch_uv[mesh->vert_offset], + mesh->vert_offset, + mesh->tri_offset); if(progress.get_cancel()) return; } @@ -1079,8 +1413,9 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene device->tex_alloc("__tri_shader", dscene->tri_shader); device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); - device->tex_alloc("__tri_verts", dscene->tri_verts); device->tex_alloc("__tri_vindex", dscene->tri_vindex); + device->tex_alloc("__tri_patch", dscene->tri_patch); + device->tex_alloc("__tri_patch_uv", dscene->tri_patch_uv); } if(curve_size != 0) { @@ -1097,6 +1432,33 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene device->tex_alloc("__curve_keys", dscene->curve_keys); device->tex_alloc("__curves", dscene->curves); } + + if(patch_size != 0) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.resize(patch_size); + + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset); + if(progress.get_cancel()) return; + } + + device->tex_alloc("__patches", dscene->patches); + } + + if(for_displacement) { + float4 *prim_tri_verts = dscene->prim_tri_verts.resize(tri_size * 3); + foreach(Mesh *mesh, scene->meshes) { + for(size_t i = 0; i < mesh->num_triangles(); ++i) { + Mesh::Triangle t = mesh->get_triangle(i); + size_t offset = 3 * (i + mesh->tri_offset); + prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); + prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); + prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); + } + } + device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts); + } } void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -1111,6 +1473,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * bparams.top_level = true; bparams.use_qbvh = scene->params.use_qbvh; bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, scene->objects); @@ -1135,9 +1499,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size()); device->tex_alloc("__object_node", dscene->object_node); } - if(pack.tri_storage.size()) { - dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size()); - device->tex_alloc("__tri_storage", dscene->tri_storage); + if(pack.prim_tri_index.size()) { + dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size()); + device->tex_alloc("__prim_tri_index", dscene->prim_tri_index); + } + if(pack.prim_tri_verts.size()) { + dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size()); + device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts); } if(pack.prim_type.size()) { dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size()); @@ -1238,7 +1606,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen VLOG(1) << "Total " << scene->meshes.size() << " meshes."; - /* update normals */ + /* Update normals. */ foreach(Mesh *mesh, scene->meshes) { foreach(Shader *shader, mesh->used_shaders) { if(shader->need_update_attributes) @@ -1254,17 +1622,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } /* Update images needed for true displacement. */ - bool need_displacement_images = false; + bool true_displacement_used = false; bool old_need_object_flags_update = false; foreach(Mesh *mesh, scene->meshes) { if(mesh->need_update && mesh->displacement_method != Mesh::DISPLACE_BUMP) { - need_displacement_images = true; + true_displacement_used = true; break; } } - if(need_displacement_images) { + if(true_displacement_used) { VLOG(1) << "Updating images used for true displacement."; device_update_displacement_images(device, dscene, scene, progress); old_need_object_flags_update = scene->object_manager->need_flags_update; @@ -1275,42 +1643,46 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen false); } - /* device update */ + /* Device update. */ device_free(device, dscene); - device_update_mesh(device, dscene, scene, progress); + mesh_calc_offset(scene); + if(true_displacement_used) { + device_update_mesh(device, dscene, scene, true, progress); + } if(progress.get_cancel()) return; device_update_attributes(device, dscene, scene, progress); if(progress.get_cancel()) return; - /* update displacement */ + /* Update displacement. */ bool displacement_done = false; - - foreach(Mesh *mesh, scene->meshes) - if(mesh->need_update && displace(device, dscene, scene, mesh, progress)) + foreach(Mesh *mesh, scene->meshes) { + if(mesh->need_update && + displace(device, dscene, scene, mesh, progress)) + { displacement_done = true; + } + } - /* todo: properly handle cancel halfway displacement */ + /* TODO: properly handle cancel halfway displacement */ if(progress.get_cancel()) return; - /* device re-update after displacement */ + /* Device re-update after displacement. */ if(displacement_done) { device_free(device, dscene); - device_update_mesh(device, dscene, scene, progress); - if(progress.get_cancel()) return; - device_update_attributes(device, dscene, scene, progress); if(progress.get_cancel()) return; } - /* update bvh */ + /* Update bvh. */ size_t i = 0, num_bvh = 0; - - foreach(Mesh *mesh, scene->meshes) - if(mesh->need_update && mesh->need_build_bvh()) + foreach(Mesh *mesh, scene->meshes) { + if(mesh->need_update && mesh->need_build_bvh()) { num_bvh++; + } + } TaskPool pool; @@ -1318,6 +1690,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen if(mesh->need_update) { pool.push(function_bind(&Mesh::compute_bvh, mesh, + dscene, &scene->params, &progress, i, @@ -1333,8 +1706,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); - foreach(Shader *shader, scene->shaders) + foreach(Shader *shader, scene->shaders) { shader->need_update_attributes = false; + } #ifdef __OBJECT_MOTION__ Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading); @@ -1343,18 +1717,23 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen bool motion_blur = false; #endif - /* update obejcts */ + /* Update objects. */ vector<Object *> volume_objects; - foreach(Object *object, scene->objects) + foreach(Object *object, scene->objects) { object->compute_bounds(motion_blur); + } if(progress.get_cancel()) return; device_update_bvh(device, dscene, scene, progress); + if(progress.get_cancel()) return; + + device_update_mesh(device, dscene, scene, false, progress); + if(progress.get_cancel()) return; need_update = false; - if(need_displacement_images) { + if(true_displacement_used) { /* Re-tag flags for update, so they're re-evaluated * for meshes with correct bounding boxes. * @@ -1370,7 +1749,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->bvh_nodes); device->tex_free(dscene->bvh_leaf_nodes); device->tex_free(dscene->object_node); - device->tex_free(dscene->tri_storage); + device->tex_free(dscene->prim_tri_verts); + device->tex_free(dscene->prim_tri_index); device->tex_free(dscene->prim_type); device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); @@ -1378,9 +1758,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tri_shader); device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); - device->tex_free(dscene->tri_verts); + device->tex_free(dscene->tri_patch); + device->tex_free(dscene->tri_patch_uv); device->tex_free(dscene->curves); device->tex_free(dscene->curve_keys); + device->tex_free(dscene->patches); device->tex_free(dscene->attributes_map); device->tex_free(dscene->attributes_float); device->tex_free(dscene->attributes_float3); @@ -1388,7 +1770,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->bvh_nodes.clear(); dscene->object_node.clear(); - dscene->tri_storage.clear(); + dscene->prim_tri_verts.clear(); + dscene->prim_tri_index.clear(); dscene->prim_type.clear(); dscene->prim_visibility.clear(); dscene->prim_index.clear(); @@ -1396,9 +1779,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_shader.clear(); dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); - dscene->tri_verts.clear(); + dscene->tri_patch.clear(); + dscene->tri_patch_uv.clear(); dscene->curves.clear(); dscene->curve_keys.clear(); + dscene->patches.clear(); dscene->attributes_map.clear(); dscene->attributes_float.clear(); dscene->attributes_float3.clear(); @@ -1448,74 +1833,5 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name) return false; } -void Mesh::tessellate(DiagSplit *split) -{ - int num_faces = triangles.size(); - - add_face_normals(); - add_vertex_normals(); - - Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); - float3 *fN = attr_fN->data_float3(); - - Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); - float3 *vN = attr_vN->data_float3(); - - for(int f = 0; f < num_faces; f++) { - if(!forms_quad[f]) { - /* triangle */ - LinearTrianglePatch patch; - float3 *hull = patch.hull; - float3 *normals = patch.normals; - - for(int i = 0; i < 3; i++) { - hull[i] = verts[triangles[f].v[i]]; - } - - if(smooth[f]) { - for(int i = 0; i < 3; i++) { - normals[i] = vN[triangles[f].v[i]]; - } - } - else { - for(int i = 0; i < 3; i++) { - normals[i] = fN[f]; - } - } - - split->split_triangle(&patch); - } - else { - /* quad */ - LinearQuadPatch patch; - float3 *hull = patch.hull; - float3 *normals = patch.normals; - - hull[0] = verts[triangles[f ].v[0]]; - hull[1] = verts[triangles[f ].v[1]]; - hull[3] = verts[triangles[f ].v[2]]; - hull[2] = verts[triangles[f+1].v[2]]; - - if(smooth[f]) { - normals[0] = vN[triangles[f ].v[0]]; - normals[1] = vN[triangles[f ].v[1]]; - normals[3] = vN[triangles[f ].v[2]]; - normals[2] = vN[triangles[f+1].v[2]]; - } - else { - for(int i = 0; i < 4; i++) { - normals[i] = fN[f]; - } - } - - split->split_quad(&patch); - - // consume second triangle in quad - f++; - } - - } -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 557b664bff3..c9ae9aab888 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -18,6 +18,7 @@ #define __MESH_H__ #include "attribute.h" +#include "node.h" #include "shader.h" #include "util_boundbox.h" @@ -42,8 +43,10 @@ class DiagSplit; /* Mesh */ -class Mesh { +class Mesh : public Node { public: + NODE_DECLARE; + /* Mesh Triangle */ struct Triangle { int v[3]; @@ -51,15 +54,60 @@ public: void bounds_grow(const float3 *verts, BoundBox& bounds) const; }; + Triangle get_triangle(size_t i) const + { + Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}}; + return tri; + } + + size_t num_triangles() const + { + return triangles.size() / 3; + } + /* Mesh Curve */ struct Curve { int first_key; int num_keys; - uint shader; int num_segments() { return num_keys - 1; } - void bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox& bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform& aligned_space, + BoundBox& bounds) const; + }; + + Curve get_curve(size_t i) const + { + int first = curve_first_key[i]; + int next_first = (i+1 < curve_first_key.size()) ? curve_first_key[i+1] : curve_keys.size(); + + Curve curve = {first, next_first - first}; + return curve; + } + + size_t num_curves() const + { + return curve_first_key.size(); + } + + /* Mesh SubdFace */ + struct SubdFace { + int start_corner; + int num_corners; + int shader; + bool smooth; + int ptex_offset; + + bool is_quad() { return num_corners == 4; } + float3 normal(const Mesh *mesh) const; + int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; } }; /* Displacement */ @@ -71,7 +119,13 @@ public: DISPLACE_NUM_METHODS, }; - ustring name; + enum SubdivisionType { + SUBDIVISION_NONE, + SUBDIVISION_LINEAR, + SUBDIVISION_CATMULL_CLARK, + }; + + SubdivisionType subdivision_type; /* Mesh Data */ enum GeometryFlags { @@ -82,21 +136,31 @@ public: int geometry_flags; /* used to distinguish meshes with no verts and meshed for which geometry is not created */ - vector<float3> verts; - vector<Triangle> triangles; - vector<uint> shader; - vector<bool> smooth; - vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */ + array<int> triangles; + array<float3> verts; + array<int> shader; + array<bool> smooth; + + /* used for storing patch info for subd triangles, only allocated if there are patches */ + array<int> triangle_patch; /* must be < 0 for non subd triangles */ + array<float2> vert_patch_uv; bool has_volume; /* Set in the device_update_flags(). */ bool has_surface_bssrdf; /* Set in the device_update_flags(). */ - vector<float4> curve_keys; /* co + radius */ - vector<Curve> curves; + array<float3> curve_keys; + array<float> curve_radius; + array<int> curve_first_key; + array<int> curve_shader; + + array<SubdFace> subd_faces; + array<int> subd_face_corners; + int num_ngons; vector<Shader*> used_shaders; AttributeSet attributes; AttributeSet curve_attributes; + AttributeSet subd_attributes; BoundBox bounds; bool transform_applied; @@ -119,16 +183,29 @@ public: size_t curve_offset; size_t curvekey_offset; + size_t patch_offset; + size_t face_offset; + size_t corner_offset; + + size_t num_subd_verts; + /* Functions */ Mesh(); ~Mesh(); - void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys); + void resize_mesh(int numverts, int numfaces); + void reserve_mesh(int numverts, int numfaces); + void resize_curves(int numcurves, int numkeys); + void reserve_curves(int numcurves, int numkeys); + void resize_subd_faces(int numfaces, int num_ngons, int numcorners); + void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); void clear(); - void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false); - void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false); + void add_vertex(float3 P); + void add_vertex_slow(float3 P); + void add_triangle(int v0, int v1, int v2, int shader, bool smooth); void add_curve_key(float3 loc, float radius); - void add_curve(int first_key, int num_keys, int shader); + void add_curve(int first_key, int shader); + void add_subd_face(int* corners, int num_corners, int shader_, bool smooth_); int split_vertex(int vertex); void compute_bounds(); @@ -136,9 +213,20 @@ public: void add_vertex_normals(); void pack_normals(Scene *scene, uint *shader, float4 *vnormal); - void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset); + void pack_verts(const vector<uint>& tri_prim_index, + uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv, + size_t vert_offset, + size_t tri_offset); void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); - void compute_bvh(SceneParams *params, Progress *progress, int n, int total); + void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); + + void compute_bvh(DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total); bool need_attribute(Scene *scene, AttributeStandard std); bool need_attribute(Scene *scene, ustring name); @@ -182,15 +270,41 @@ public: void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); + +protected: + /* Calculate verts/triangles/curves offsets in global arrays. */ + void mesh_calc_offset(Scene *scene); + + void device_update_object(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress& progress); + + void device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_displacement_images(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index d19bf2084d7..95f46ff02a2 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -60,8 +60,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me uint4 *d_input_data = d_input.resize(num_verts); size_t d_input_size = 0; - for(size_t i = 0; i < mesh->triangles.size(); i++) { - Mesh::Triangle t = mesh->triangles[i]; + size_t num_triangles = mesh->num_triangles(); + for(size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; @@ -146,8 +147,8 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me float4 *offset = (float4*)d_output.data_pointer; Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(size_t i = 0; i < mesh->triangles.size(); i++) { - Mesh::Triangle t = mesh->triangles[i]; + for(size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); int shader_index = mesh->shader[i]; Shader *shader = (shader_index < mesh->used_shaders.size()) ? mesh->used_shaders[shader_index] : scene->default_surface; diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp new file mode 100644 index 00000000000..fe8e41e8d35 --- /dev/null +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -0,0 +1,224 @@ +/* + * 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. + */ + +#include "mesh.h" +#include "attribute.h" + +#include "subd_split.h" +#include "subd_patch.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +void Mesh::tessellate(DiagSplit *split) +{ + int num_faces = subd_faces.size(); + + Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL); + float3* vN = attr_vN->data_float3(); + + for(int f = 0; f < num_faces; f++) { + SubdFace& face = subd_faces[f]; + + if(face.is_quad()) { + /* quad */ + LinearQuadPatch patch; + float3 *hull = patch.hull; + float3 *normals = patch.normals; + + patch.patch_index = face.ptex_offset; + patch.shader = face.shader; + + for(int i = 0; i < 4; i++) { + hull[i] = verts[subd_face_corners[face.start_corner+i]]; + } + + if(face.smooth) { + for(int i = 0; i < 4; i++) { + normals[i] = vN[subd_face_corners[face.start_corner+i]]; + } + } + else { + float3 N = face.normal(this); + for(int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + swap(hull[2], hull[3]); + swap(normals[2], normals[3]); + + /* Quad faces need to be split at least once to line up with split ngons, we do this + * here in this manner because if we do it later edge factors may end up slightly off. + */ + QuadDice::SubPatch subpatch; + subpatch.patch = &patch; + + subpatch.P00 = make_float2(0.0f, 0.0f); + subpatch.P10 = make_float2(0.5f, 0.0f); + subpatch.P01 = make_float2(0.0f, 0.5f); + subpatch.P11 = make_float2(0.5f, 0.5f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.0f); + subpatch.P10 = make_float2(1.0f, 0.0f); + subpatch.P01 = make_float2(0.5f, 0.5f); + subpatch.P11 = make_float2(1.0f, 0.5f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.0f, 0.5f); + subpatch.P10 = make_float2(0.5f, 0.5f); + subpatch.P01 = make_float2(0.0f, 1.0f); + subpatch.P11 = make_float2(0.5f, 1.0f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.5f); + subpatch.P10 = make_float2(1.0f, 0.5f); + subpatch.P01 = make_float2(0.5f, 1.0f); + subpatch.P11 = make_float2(1.0f, 1.0f); + split->split_quad(&patch, &subpatch); + } + else { + /* ngon */ + float3 center_vert = make_float3(0.0f, 0.0f, 0.0f); + float3 center_normal = make_float3(0.0f, 0.0f, 0.0f); + + float inv_num_corners = 1.0f/float(face.num_corners); + for(int corner = 0; corner < face.num_corners; corner++) { + center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + } + + for(int corner = 0; corner < face.num_corners; corner++) { + LinearQuadPatch patch; + float3 *hull = patch.hull; + float3 *normals = patch.normals; + + patch.patch_index = face.ptex_offset + corner; + + patch.shader = face.shader; + + hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + hull[3] = center_vert; + + hull[1] = (hull[1] + hull[0]) * 0.5; + hull[2] = (hull[2] + hull[0]) * 0.5; + + if(face.smooth) { + normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + normals[3] = center_normal; + + normals[1] = (normals[1] + normals[0]) * 0.5; + normals[2] = (normals[2] + normals[0]) * 0.5; + } + else { + float3 N = face.normal(this); + for(int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + split->split_quad(&patch); + } + } + } + + /* interpolate center points for attributes */ + foreach(Attribute& attr, subd_attributes.attributes) { + char* data = attr.data(); + size_t stride = attr.data_sizeof(); + int ngons = 0; + + switch(attr.element) { + case ATTR_ELEMENT_VERTEX: { + for(int f = 0; f < num_faces; f++) { + SubdFace& face = subd_faces[f]; + + if(!face.is_quad()) { + char* center = data + (verts.size() - num_subd_verts + ngons) * stride; + attr.zero_data(center); + + float inv_num_corners = 1.0f / float(face.num_corners); + + for(int corner = 0; corner < face.num_corners; corner++) { + attr.add_with_weight(center, + data + subd_face_corners[face.start_corner + corner] * stride, + inv_num_corners); + } + + ngons++; + } + } + } break; + case ATTR_ELEMENT_VERTEX_MOTION: { + // TODO(mai): implement + } break; + case ATTR_ELEMENT_CORNER: { + for(int f = 0; f < num_faces; f++) { + SubdFace& face = subd_faces[f]; + + if(!face.is_quad()) { + char* center = data + (subd_face_corners.size() + ngons) * stride; + attr.zero_data(center); + + float inv_num_corners = 1.0f / float(face.num_corners); + + for(int corner = 0; corner < face.num_corners; corner++) { + attr.add_with_weight(center, + data + (face.start_corner + corner) * stride, + inv_num_corners); + } + + ngons++; + } + } + } break; + case ATTR_ELEMENT_CORNER_BYTE: { + for(int f = 0; f < num_faces; f++) { + SubdFace& face = subd_faces[f]; + + if(!face.is_quad()) { + uchar* center = (uchar*)data + (subd_face_corners.size() + ngons) * stride; + + float inv_num_corners = 1.0f / float(face.num_corners); + float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + for(int corner = 0; corner < face.num_corners; corner++) { + for(int i = 0; i < 4; i++) { + val[i] += float(*(data + (face.start_corner + corner) * stride + i)) * inv_num_corners; + } + } + + for(int i = 0; i < 4; i++) { + center[i] = uchar(min(max(val[i], 0.0f), 255.0f)); + } + + ngons++; + } + } + } break; + default: break; + } + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index f75fef1c13e..cf366367873 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -19,8 +19,11 @@ #include "nodes.h" #include "scene.h" #include "svm.h" +#include "svm_color_util.h" +#include "svm_ramp_util.h" #include "svm_math_util.h" #include "osl.h" +#include "constant_fold.h" #include "util_sky_model.h" #include "util_foreach.h" @@ -30,64 +33,40 @@ CCL_NAMESPACE_BEGIN /* Texture Mapping */ -static ShaderEnum texture_mapping_type_init() -{ - ShaderEnum enm; - - enm.insert("Point", TextureMapping::POINT); - enm.insert("Texture", TextureMapping::TEXTURE); - enm.insert("Vector", TextureMapping::VECTOR); - enm.insert("Normal", TextureMapping::NORMAL); - - return enm; -} - -static ShaderEnum texture_mapping_mapping_init() -{ - ShaderEnum enm; - - enm.insert("None", TextureMapping::NONE); - enm.insert("X", TextureMapping::X); - enm.insert("Y", TextureMapping::Y); - enm.insert("Z", TextureMapping::Z); - - return enm; -} - -static ShaderEnum texture_mapping_projection_init() -{ - ShaderEnum enm; - - enm.insert("Flat", TextureMapping::FLAT); - enm.insert("Cube", TextureMapping::CUBE); - enm.insert("Tube", TextureMapping::TUBE); - enm.insert("Sphere", TextureMapping::SPHERE); - - return enm; -} - -ShaderEnum TextureMapping::type_enum = texture_mapping_type_init(); -ShaderEnum TextureMapping::mapping_enum = texture_mapping_mapping_init(); -ShaderEnum TextureMapping::projection_enum = texture_mapping_projection_init(); +#define TEXTURE_MAPPING_DEFINE(TextureNode) \ + SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ + \ + SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ + SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ + SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ + \ + static NodeEnum mapping_axis_enum; \ + mapping_axis_enum.insert("none", TextureMapping::NONE); \ + mapping_axis_enum.insert("x", TextureMapping::X); \ + mapping_axis_enum.insert("y", TextureMapping::Y); \ + mapping_axis_enum.insert("z", TextureMapping::Z); \ + SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \ + SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \ + SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \ + \ + static NodeEnum mapping_type_enum; \ + mapping_type_enum.insert("point", TextureMapping::POINT); \ + mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \ + mapping_type_enum.insert("vector", TextureMapping::VECTOR); \ + mapping_type_enum.insert("normal", TextureMapping::NORMAL); \ + SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \ + \ + static NodeEnum mapping_projection_enum; \ + mapping_projection_enum.insert("flat", TextureMapping::FLAT); \ + mapping_projection_enum.insert("cube", TextureMapping::CUBE); \ + mapping_projection_enum.insert("tube", TextureMapping::TUBE); \ + mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \ + SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT); TextureMapping::TextureMapping() { - translation = make_float3(0.0f, 0.0f, 0.0f); - rotation = make_float3(0.0f, 0.0f, 0.0f); - scale = make_float3(1.0f, 1.0f, 1.0f); - - min = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - max = make_float3(FLT_MAX, FLT_MAX, FLT_MAX); - - use_minmax = false; - - x_mapping = X; - y_mapping = Y; - z_mapping = Z; - - type = TEXTURE; - - projection = FLAT; } Transform TextureMapping::compute_transform() @@ -193,7 +172,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in) { if(!skip()) { int offset_in = compiler.stack_assign(vector_in); - int offset_out = compiler.stack_find_offset(SHADER_SOCKET_VECTOR); + int offset_out = compiler.stack_find_offset(SocketType::VECTOR); compile(compiler, offset_in, offset_out); @@ -206,7 +185,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in) void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset) { if(!skip()) { - compiler.stack_clear_offset(vector_in->type, vector_offset); + compiler.stack_clear_offset(vector_in->type(), vector_offset); } } @@ -222,72 +201,66 @@ void TextureMapping::compile(OSLCompiler &compiler) /* Image Texture */ -static ShaderEnum color_space_init() +NODE_DEFINE(ImageTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER); - enm.insert("None", 0); - enm.insert("Color", 1); + TEXTURE_MAPPING_DEFINE(ImageTextureNode); - return enm; -} + SOCKET_STRING(filename, "Filename", ustring("")); -static ShaderEnum image_projection_init() -{ - ShaderEnum enm; + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); - enm.insert("Flat", NODE_IMAGE_PROJ_FLAT); - enm.insert("Box", NODE_IMAGE_PROJ_BOX); - enm.insert("Sphere", NODE_IMAGE_PROJ_SPHERE); - enm.insert("Tube", NODE_IMAGE_PROJ_TUBE); + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); - return enm; -} + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); -static const char* get_osl_interpolation_parameter(InterpolationType interpolation) -{ - switch(interpolation) { - case INTERPOLATION_CLOSEST: - return "closest"; - case INTERPOLATION_CUBIC: - return "cubic"; - case INTERPOLATION_SMART: - return "smart"; - case INTERPOLATION_LINEAR: - default: - return "linear"; - } -} + static NodeEnum extension_enum; + extension_enum.insert("periodic", EXTENSION_REPEAT); + extension_enum.insert("clamp", EXTENSION_EXTEND); + extension_enum.insert("black", EXTENSION_CLIP); + SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT); + + static NodeEnum projection_enum; + projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT); + projection_enum.insert("box", NODE_IMAGE_PROJ_BOX); + projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE); + projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT); + + SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f); -ShaderEnum ImageTextureNode::color_space_enum = color_space_init(); -ShaderEnum ImageTextureNode::projection_enum = image_projection_init(); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} ImageTextureNode::ImageTextureNode() -: ImageSlotTextureNode("image_texture") +: ImageSlotTextureNode(node_type) { image_manager = NULL; slot = -1; is_float = -1; is_linear = false; - use_alpha = true; - filename = ""; builtin_data = NULL; - color_space = ustring("Color"); - projection = ustring("Flat"); - interpolation = INTERPOLATION_LINEAR; - extension = EXTENSION_REPEAT; - projection_blend = 0.0f; animated = false; - - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); } ImageTextureNode::~ImageTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, extension); @@ -328,7 +301,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -341,10 +314,10 @@ void ImageTextureNode::compile(SVMCompiler& compiler) } if(slot != -1) { - int srgb = (is_linear || color_space != "Color")? 0: 1; + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - if(projection != "Box") { + if(projection != NODE_IMAGE_PROJ_BOX) { compiler.add_node(NODE_TEX_IMAGE, slot, compiler.encode_uchar4( @@ -352,7 +325,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(alpha_out), srgb), - projection_enum[projection]); + projection); } else { compiler.add_node(NODE_TEX_IMAGE_BOX, @@ -390,13 +363,13 @@ void ImageTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageManager::ImageDataType type; - type = image_manager->get_image_metadata(filename, NULL, is_linear); + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } else { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -410,7 +383,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) } if(slot == -1) { - compiler.parameter("filename", filename.c_str()); + compiler.parameter(this, "filename"); } else { /* TODO(sergey): It's not so simple to pass custom attribute @@ -421,71 +394,72 @@ void ImageTextureNode::compile(OSLCompiler& compiler) */ compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - if(is_linear || color_space != "Color") - compiler.parameter("color_space", "Linear"); + if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) + compiler.parameter("color_space", "linear"); else compiler.parameter("color_space", "sRGB"); - compiler.parameter("projection", projection); - compiler.parameter("projection_blend", projection_blend); + compiler.parameter(this, "projection"); + compiler.parameter(this, "projection_blend"); compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); - compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation)); - - switch(extension) { - case EXTENSION_EXTEND: - compiler.parameter("wrap", "clamp"); - break; - case EXTENSION_CLIP: - compiler.parameter("wrap", "black"); - break; - case EXTENSION_REPEAT: - default: - compiler.parameter("wrap", "periodic"); - break; - } + compiler.parameter(this, "interpolation"); + compiler.parameter(this, "extension"); compiler.add(this, "node_image_texture"); } /* Environment Texture */ -static ShaderEnum env_projection_init() +NODE_DEFINE(EnvironmentTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER); - enm.insert("Equirectangular", 0); - enm.insert("Mirror Ball", 1); + TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode); - return enm; -} + SOCKET_STRING(filename, "Filename", ustring("")); + + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); + + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); + + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + + static NodeEnum projection_enum; + projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR); + projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); -ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init(); -ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init(); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} EnvironmentTextureNode::EnvironmentTextureNode() -: ImageSlotTextureNode("environment_texture") +: ImageSlotTextureNode(node_type) { image_manager = NULL; slot = -1; is_float = -1; is_linear = false; - use_alpha = true; - filename = ""; builtin_data = NULL; - color_space = ustring("Color"); - interpolation = INTERPOLATION_LINEAR; - projection = ustring("Equirectangular"); animated = false; - - add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); } EnvironmentTextureNode::~EnvironmentTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, EXTENSION_REPEAT); @@ -524,7 +498,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(slot == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -537,7 +511,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) } if(slot != -1) { - int srgb = (is_linear || color_space != "Color")? 0: 1; + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; int vector_offset = tex_mapping.compile_begin(compiler, vector_in); compiler.add_node(NODE_TEX_ENVIRONMENT, @@ -547,7 +521,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(alpha_out), srgb), - projection_enum[projection]); + projection); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -577,13 +551,13 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageManager::ImageDataType type; - type = image_manager->get_image_metadata(filename, NULL, is_linear); + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } else { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -597,19 +571,18 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) } if(slot == -1) { - compiler.parameter("filename", filename.c_str()); + compiler.parameter(this, "filename"); } else { compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - compiler.parameter("projection", projection); - if(is_linear || color_space != "Color") - compiler.parameter("color_space", "Linear"); + compiler.parameter(this, "projection"); + if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) + compiler.parameter("color_space", "linear"); else compiler.parameter("color_space", "sRGB"); - compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation)); - + compiler.parameter(this, "interpolation"); compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); compiler.add(this, "node_environment_texture"); @@ -640,10 +613,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma) static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity) { /* - * We re-use the SunSky struct of the new model, to avoid extra variables - * zenith_Y/x/y is now radiance_x/y/z - * perez_Y/x/y is now config_x/y/z - */ + * We re-use the SunSky struct of the new model, to avoid extra variables + * zenith_Y/x/y is now radiance_x/y/z + * perez_Y/x/y is now config_x/y/z + */ float2 spherical = sky_spherical_coordinates(dir); float theta = spherical.x; @@ -738,29 +711,31 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi arhosekskymodelstate_free(sky_state); } -static ShaderEnum sky_type_init() +NODE_DEFINE(SkyTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER); - enm.insert("Preetham", NODE_SKY_OLD); - enm.insert("Hosek / Wilkie", NODE_SKY_NEW); + TEXTURE_MAPPING_DEFINE(SkyTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("preetham", NODE_SKY_OLD); + type_enum.insert("hosek_wilkie", NODE_SKY_NEW); + SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW); -ShaderEnum SkyTextureNode::type_enum = sky_type_init(); + SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f)); + SOCKET_FLOAT(turbidity, "Turbidity", 2.2f); + SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} SkyTextureNode::SkyTextureNode() -: TextureNode("sky_texture") +: TextureNode(node_type) { - type = ustring("Hosek / Wilkie"); - - sun_direction = make_float3(0.0f, 0.0f, 1.0f); - turbidity = 2.2f; - ground_albedo = 0.3f; - - add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); - add_output("Color", SHADER_SOCKET_COLOR); } void SkyTextureNode::compile(SVMCompiler& compiler) @@ -769,18 +744,17 @@ void SkyTextureNode::compile(SVMCompiler& compiler) ShaderOutput *color_out = output("Color"); SunSky sunsky; - if(type_enum[type] == NODE_SKY_OLD) + if(type == NODE_SKY_OLD) sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type_enum[type] == NODE_SKY_NEW) + else if(type == NODE_SKY_NEW) sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); else assert(false); int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - int sky_model = type_enum[type]; compiler.stack_assign(color_out); - compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model); + compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type); compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y)); compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2])); compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6])); @@ -798,15 +772,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler) tex_mapping.compile(compiler); SunSky sunsky; - - if(type_enum[type] == NODE_SKY_OLD) + if(type == NODE_SKY_OLD) sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type_enum[type] == NODE_SKY_NEW) + else if(type == NODE_SKY_NEW) sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); else assert(false); - compiler.parameter("sky_model", type); + compiler.parameter(this, "type"); compiler.parameter("theta", sunsky.theta); compiler.parameter("phi", sunsky.phi); compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); @@ -818,31 +791,33 @@ void SkyTextureNode::compile(OSLCompiler& compiler) /* Gradient Texture */ -static ShaderEnum gradient_type_init() +NODE_DEFINE(GradientTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER); - enm.insert("Linear", NODE_BLEND_LINEAR); - enm.insert("Quadratic", NODE_BLEND_QUADRATIC); - enm.insert("Easing", NODE_BLEND_EASING); - enm.insert("Diagonal", NODE_BLEND_DIAGONAL); - enm.insert("Radial", NODE_BLEND_RADIAL); - enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE); - enm.insert("Spherical", NODE_BLEND_SPHERICAL); + TEXTURE_MAPPING_DEFINE(GradientTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("linear", NODE_BLEND_LINEAR); + type_enum.insert("quadratic", NODE_BLEND_QUADRATIC); + type_enum.insert("easing", NODE_BLEND_EASING); + type_enum.insert("diagonal", NODE_BLEND_DIAGONAL); + type_enum.insert("radial", NODE_BLEND_RADIAL); + type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE); + type_enum.insert("spherical", NODE_BLEND_SPHERICAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -ShaderEnum GradientTextureNode::type_enum = gradient_type_init(); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} GradientTextureNode::GradientTextureNode() -: TextureNode("gradient_texture") +: TextureNode(node_type) { - type = ustring("Linear"); - - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); } void GradientTextureNode::compile(SVMCompiler& compiler) @@ -855,7 +830,7 @@ void GradientTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_GRADIENT, compiler.encode_uchar4( - type_enum[type], + type, vector_offset, compiler.stack_assign_if_linked(fac_out), compiler.stack_assign_if_linked(color_out))); @@ -867,22 +842,32 @@ void GradientTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); + compiler.parameter(this, "type"); compiler.add(this, "node_gradient_texture"); } /* Noise Texture */ -NoiseTextureNode::NoiseTextureNode() -: TextureNode("noise_texture") +NODE_DEFINE(NoiseTextureNode) { - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f); + NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(NoiseTextureNode); + + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); +NoiseTextureNode::NoiseTextureNode() +: TextureNode(node_type) +{ } void NoiseTextureNode::compile(SVMCompiler& compiler) @@ -906,9 +891,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out))); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(distortion_in->value.x)); + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -922,28 +907,29 @@ void NoiseTextureNode::compile(OSLCompiler& compiler) /* Voronoi Texture */ -static ShaderEnum voronoi_coloring_init() +NODE_DEFINE(VoronoiTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER); - enm.insert("Intensity", NODE_VORONOI_INTENSITY); - enm.insert("Cells", NODE_VORONOI_CELLS); + TEXTURE_MAPPING_DEFINE(VoronoiTextureNode); - return enm; -} + static NodeEnum coloring_enum; + coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY); + coloring_enum.insert("cells", NODE_VORONOI_CELLS); + SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY); -ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init(); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -VoronoiTextureNode::VoronoiTextureNode() -: TextureNode("voronoi_texture") -{ - coloring = ustring("Intensity"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); + return type; +} - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); +VoronoiTextureNode::VoronoiTextureNode() +: TextureNode(node_type) +{ } void VoronoiTextureNode::compile(SVMCompiler& compiler) @@ -956,13 +942,13 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler) int vector_offset = tex_mapping.compile_begin(compiler, vector_in); compiler.add_node(NODE_TEX_VORONOI, - coloring_enum[coloring], + coloring, compiler.encode_uchar4( compiler.stack_assign_if_linked(scale_in), vector_offset, compiler.stack_assign(fac_out), compiler.stack_assign(color_out)), - __float_as_int(scale_in->value.x)); + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -971,42 +957,43 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Coloring", coloring); + compiler.parameter(this, "coloring"); compiler.add(this, "node_voronoi_texture"); } /* Musgrave Texture */ -static ShaderEnum musgrave_type_init() +NODE_DEFINE(MusgraveTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER); - enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL); - enm.insert("fBM", NODE_MUSGRAVE_FBM); - enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); - enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); - enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + TEXTURE_MAPPING_DEFINE(MusgraveTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL); + type_enum.insert("fBM", NODE_MUSGRAVE_FBM); + type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); + type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); + type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM); -ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init(); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f); + SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(gain, "Gain", 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -MusgraveTextureNode::MusgraveTextureNode() -: TextureNode("musgrave_texture") -{ - type = ustring("fBM"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f); + return type; +} - add_output("Fac", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); +MusgraveTextureNode::MusgraveTextureNode() +: TextureNode(node_type) +{ } void MusgraveTextureNode::compile(SVMCompiler& compiler) @@ -1025,7 +1012,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_MUSGRAVE, compiler.encode_uchar4( - type_enum[type], + type, vector_offset, compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out)), @@ -1037,12 +1024,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(gain_in), compiler.stack_assign_if_linked(scale_in))); - compiler.add_node(__float_as_int(dimension_in->value.x), - __float_as_int(lacunarity_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(offset_in->value.x)); - compiler.add_node(__float_as_int(gain_in->value.x), - __float_as_int(scale_in->value.x)); + compiler.add_node(__float_as_int(dimension), + __float_as_int(lacunarity), + __float_as_int(detail), + __float_as_int(offset)); + compiler.add_node(__float_as_int(gain), + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1051,50 +1038,43 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); - + compiler.parameter(this, "type"); compiler.add(this, "node_musgrave_texture"); } /* Wave Texture */ -static ShaderEnum wave_type_init() +NODE_DEFINE(WaveTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER); - enm.insert("Bands", NODE_WAVE_BANDS); - enm.insert("Rings", NODE_WAVE_RINGS); + TEXTURE_MAPPING_DEFINE(WaveTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("bands", NODE_WAVE_BANDS); + type_enum.insert("rings", NODE_WAVE_RINGS); + SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS); -static ShaderEnum wave_profile_init() -{ - ShaderEnum enm; + static NodeEnum profile_enum; + profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN); + profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW); + SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN); - enm.insert("Sine", NODE_WAVE_PROFILE_SIN); - enm.insert("Saw", NODE_WAVE_PROFILE_SAW); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - return enm; -} + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); -ShaderEnum WaveTextureNode::type_enum = wave_type_init(); -ShaderEnum WaveTextureNode::profile_enum = wave_profile_init(); + return type; +} WaveTextureNode::WaveTextureNode() -: TextureNode("wave_texture") +: TextureNode(node_type) { - type = ustring("Bands"); - profile = ustring("Sine"); - - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f); - add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); } void WaveTextureNode::compile(SVMCompiler& compiler) @@ -1111,7 +1091,7 @@ void WaveTextureNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TEX_WAVE, compiler.encode_uchar4( - type_enum[type], + type, compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out), compiler.stack_assign_if_linked(dscale_in)), @@ -1120,13 +1100,13 @@ void WaveTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(scale_in), compiler.stack_assign_if_linked(detail_in), compiler.stack_assign_if_linked(distortion_in)), - profile_enum[profile]); + profile); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(detail_in->value.x), - __float_as_int(distortion_in->value.x), - __float_as_int(dscale_in->value.x)); + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion), + __float_as_int(detail_scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1135,25 +1115,35 @@ void WaveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Type", type); - compiler.parameter("Profile", profile); + compiler.parameter(this, "type"); + compiler.parameter(this, "profile"); compiler.add(this, "node_wave_texture"); } /* Magic Texture */ -MagicTextureNode::MagicTextureNode() -: TextureNode("magic_texture") +NODE_DEFINE(MagicTextureNode) { - depth = 2; + NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(MagicTextureNode); + + SOCKET_INT(depth, "Depth", 2); - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f); - add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +MagicTextureNode::MagicTextureNode() +: TextureNode(node_type) +{ } void MagicTextureNode::compile(SVMCompiler& compiler) @@ -1176,8 +1166,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(scale_in), compiler.stack_assign_if_linked(distortion_in))); compiler.add_node( - __float_as_int(scale_in->value.x), - __float_as_int(distortion_in->value.x)); + __float_as_int(scale), + __float_as_int(distortion)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1186,22 +1176,32 @@ void MagicTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Depth", depth); + compiler.parameter(this, "depth"); compiler.add(this, "node_magic_texture"); } /* Checker Texture */ -CheckerTextureNode::CheckerTextureNode() -: TextureNode("checker_texture") +NODE_DEFINE(CheckerTextureNode) { - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f); + NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + TEXTURE_MAPPING_DEFINE(CheckerTextureNode); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +CheckerTextureNode::CheckerTextureNode() +: TextureNode(node_type) +{ } void CheckerTextureNode::compile(SVMCompiler& compiler) @@ -1225,7 +1225,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out)), - __float_as_int(scale_in->value.x)); + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1239,26 +1239,37 @@ void CheckerTextureNode::compile(OSLCompiler& compiler) /* Brick Texture */ -BrickTextureNode::BrickTextureNode() -: TextureNode("brick_texture") +NODE_DEFINE(BrickTextureNode) { - offset = 0.5f; - offset_frequency = 2; - squash = 1.0f; - squash_frequency = 2; - - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_input("Mortar", SHADER_SOCKET_COLOR); - add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f); - add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f); - add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f); + NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(BrickTextureNode); + + SOCKET_FLOAT(offset, "Offset", 0.5f); + SOCKET_INT(offset_frequency, "Offset Frequency", 2); + SOCKET_FLOAT(squash, "Squash", 1.0f); + SOCKET_INT(squash_frequency, "Squash Frequency", 2); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f); + SOCKET_IN_FLOAT(bias, "Bias", 0.0f); + SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f); + SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Fac", SHADER_SOCKET_FLOAT); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +BrickTextureNode::BrickTextureNode() +: TextureNode(node_type) +{ } void BrickTextureNode::compile(SVMCompiler& compiler) @@ -1295,12 +1306,12 @@ void BrickTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(fac_out))); compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), - __float_as_int(scale_in->value.x), - __float_as_int(mortar_size_in->value.x), - __float_as_int(bias_in->value.x)); + __float_as_int(scale), + __float_as_int(mortar_size), + __float_as_int(bias)); - compiler.add_node(__float_as_int(brick_width_in->value.x), - __float_as_int(row_height_in->value.x), + compiler.add_node(__float_as_int(brick_width), + __float_as_int(row_height), __float_as_int(offset), __float_as_int(squash)); @@ -1311,48 +1322,55 @@ void BrickTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("Offset", offset); - compiler.parameter("OffsetFrequency", offset_frequency); - compiler.parameter("Squash", squash); - compiler.parameter("SquashFrequency", squash_frequency); + compiler.parameter(this, "offset"); + compiler.parameter(this, "offset_frequency"); + compiler.parameter(this, "squash"); + compiler.parameter(this, "squash_frequency"); compiler.add(this, "node_brick_texture"); } /* Point Density Texture */ -static ShaderEnum point_density_space_init() +NODE_DEFINE(PointDensityTextureNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER); - enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT); - enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD); + SOCKET_STRING(filename, "Filename", ustring("")); - return enm; -} + static NodeEnum space_enum; + space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT); + space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT); -ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init(); + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + + SOCKET_OUT_FLOAT(density, "Density"); + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} PointDensityTextureNode::PointDensityTextureNode() -: ShaderNode("point_density") +: ShaderNode(node_type) { image_manager = NULL; slot = -1; - filename = ""; - space = ustring("Object"); builtin_data = NULL; - interpolation = INTERPOLATION_LINEAR; - - tfm = transform_identity(); - - add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION); - add_output("Density", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); } PointDensityTextureNode::~PointDensityTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, EXTENSION_CLIP); @@ -1390,7 +1408,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) if(use_density || use_color) { if(slot == -1) { bool is_float, is_linear; - slot = image_manager->add_image(filename, builtin_data, + slot = image_manager->add_image(filename.string(), builtin_data, false, 0, is_float, is_linear, interpolation, @@ -1405,8 +1423,8 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign_if_linked(density_out), compiler.stack_assign_if_linked(color_out), - space_enum[space])); - if(space == "World") { + space)); + if(space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.add_node(tfm.x); compiler.add_node(tfm.y); compiler.add_node(tfm.z); @@ -1442,7 +1460,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) if(use_density || use_color) { if(slot == -1) { bool is_float, is_linear; - slot = image_manager->add_image(filename, builtin_data, + slot = image_manager->add_image(filename.string(), builtin_data, false, 0, is_float, is_linear, interpolation, @@ -1453,37 +1471,34 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) if(slot != -1) { compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - if(space == "World") { + if(space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.parameter("mapping", transform_transpose(tfm)); compiler.parameter("use_mapping", 1); } - switch(interpolation) { - case INTERPOLATION_CLOSEST: - compiler.parameter("interpolation", "closest"); - break; - case INTERPOLATION_CUBIC: - compiler.parameter("interpolation", "cubic"); - break; - case INTERPOLATION_LINEAR: - default: - compiler.parameter("interpolation", "linear"); - break; - } - + compiler.parameter(this, "interpolation"); compiler.add(this, "node_voxel_texture"); } } /* Normal */ -NormalNode::NormalNode() -: ShaderNode("normal") +NODE_DEFINE(NormalNode) { - direction = make_float3(0.0f, 0.0f, 1.0f); + NodeType* type = NodeType::add("normal", create, NodeType::SHADER); + + SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); - add_input("Normal", SHADER_SOCKET_NORMAL); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("Dot", SHADER_SOCKET_FLOAT); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_FLOAT(dot, "Dot"); + + return type; +} + +NormalNode::NormalNode() +: ShaderNode(node_type) +{ } void NormalNode::compile(SVMCompiler& compiler) @@ -1504,17 +1519,27 @@ void NormalNode::compile(SVMCompiler& compiler) void NormalNode::compile(OSLCompiler& compiler) { - compiler.parameter_normal("Direction", direction); + compiler.parameter(this, "direction"); compiler.add(this, "node_normal"); } /* Mapping */ +NODE_DEFINE(MappingNode) +{ + NodeType* type = NodeType::add("mapping", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(MappingNode); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_POINT(vector, "Vector"); + + return type; +} + MappingNode::MappingNode() -: ShaderNode("mapping") +: ShaderNode(node_type) { - add_input("Vector", SHADER_SOCKET_POINT); - add_output("Vector", SHADER_SOCKET_POINT); } void MappingNode::compile(SVMCompiler& compiler) @@ -1536,146 +1561,170 @@ void MappingNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mapping"); } +/* RGBToBW */ + +NODE_DEFINE(RGBToBWNode) +{ + NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_FLOAT(val, "Val"); + + return type; +} + +RGBToBWNode::RGBToBWNode() +: ShaderNode(node_type) +{ +} + +void RGBToBWNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(linear_rgb_to_gray(color)); + } +} + +void RGBToBWNode::compile(SVMCompiler& compiler) +{ + compiler.add_node(NODE_CONVERT, + NODE_CONVERT_CF, + compiler.stack_assign(inputs[0]), + compiler.stack_assign(outputs[0])); +} + +void RGBToBWNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_rgb_to_bw"); +} + /* Convert */ -ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert) -: ShaderNode("convert") +const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE]; +bool ConvertNode::initialized = ConvertNode::register_types(); + +Node* ConvertNode::create(const NodeType *type) +{ + return new ConvertNode(type->inputs[0].type, type->outputs[0].type); +} + +bool ConvertNode::register_types() +{ + const int num_types = 8; + SocketType::Type types[num_types] = {SocketType::FLOAT, + SocketType::INT, + SocketType::COLOR, + SocketType::VECTOR, + SocketType::POINT, + SocketType::NORMAL, + SocketType::STRING, + SocketType::CLOSURE}; + + for(size_t i = 0; i < num_types; i++) { + SocketType::Type from = types[i]; + ustring from_name(SocketType::type_name(from)); + ustring from_value_name("value_" + from_name.string()); + + for(size_t j = 0; j < num_types; j++) { + SocketType::Type to = types[j]; + ustring to_name(SocketType::type_name(to)); + ustring to_value_name("value_" + to_name.string()); + + string node_name = "convert_" + from_name.string() + "_to_" + to_name.string(); + NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER); + + type->register_input(from_value_name, from_value_name, from, + SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(), + NULL, NULL, SocketType::LINKABLE); + type->register_output(to_value_name, to_value_name, to); + + assert(from < MAX_TYPE); + assert(to < MAX_TYPE); + + node_types[from][to] = type; + } + } + + return true; +} + +ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert) +: ShaderNode(node_types[from_][to_]) { from = from_; to = to_; - if(autoconvert) { - if(from == to) - special_type = SHADER_SPECIAL_TYPE_PROXY; - else - special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; - } - - if(from == SHADER_SOCKET_FLOAT) - add_input("Val", SHADER_SOCKET_FLOAT); - else if(from == SHADER_SOCKET_INT) - add_input("ValInt", SHADER_SOCKET_INT); - else if(from == SHADER_SOCKET_COLOR) - add_input("Color", SHADER_SOCKET_COLOR); - else if(from == SHADER_SOCKET_VECTOR) - add_input("Vector", SHADER_SOCKET_VECTOR); - else if(from == SHADER_SOCKET_POINT) - add_input("Point", SHADER_SOCKET_POINT); - else if(from == SHADER_SOCKET_NORMAL) - add_input("Normal", SHADER_SOCKET_NORMAL); - else if(from == SHADER_SOCKET_STRING) - add_input("String", SHADER_SOCKET_STRING); - else if(from == SHADER_SOCKET_CLOSURE) - add_input("Closure", SHADER_SOCKET_CLOSURE); - else - assert(0); - - if(to == SHADER_SOCKET_FLOAT) - add_output("Val", SHADER_SOCKET_FLOAT); - else if(to == SHADER_SOCKET_INT) - add_output("ValInt", SHADER_SOCKET_INT); - else if(to == SHADER_SOCKET_COLOR) - add_output("Color", SHADER_SOCKET_COLOR); - else if(to == SHADER_SOCKET_VECTOR) - add_output("Vector", SHADER_SOCKET_VECTOR); - else if(to == SHADER_SOCKET_POINT) - add_output("Point", SHADER_SOCKET_POINT); - else if(to == SHADER_SOCKET_NORMAL) - add_output("Normal", SHADER_SOCKET_NORMAL); - else if(to == SHADER_SOCKET_STRING) - add_output("String", SHADER_SOCKET_STRING); - else if(to == SHADER_SOCKET_CLOSURE) - add_output("Closure", SHADER_SOCKET_CLOSURE); - else - assert(0); + if(from == to) + special_type = SHADER_SPECIAL_TYPE_PROXY; + else if(autoconvert) + special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } -bool ConvertNode::constant_fold(ShaderGraph * /*graph*/, - ShaderOutput * /*socket*/, - float3 *optimized_value) +void ConvertNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *in = inputs[0]; - float3 value = in->value; + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ - if(in->link == NULL) { - if(from == SHADER_SOCKET_FLOAT) { - if(to == SHADER_SOCKET_INT) - /* float to int */ - return false; - else - /* float to float3 */ - *optimized_value = make_float3(value.x, value.x, value.x); - } - else if(from == SHADER_SOCKET_INT) { - if(to == SHADER_SOCKET_FLOAT) - /* int to float */ - return false; - else - /* int to vector/point/normal */ - return false; - } - else if(to == SHADER_SOCKET_FLOAT) { - if(from == SHADER_SOCKET_COLOR) - /* color to float */ - optimized_value->x = linear_rgb_to_gray(value); - else - /* vector/point/normal to float */ - optimized_value->x = average(value); - } - else if(to == SHADER_SOCKET_INT) { - if(from == SHADER_SOCKET_COLOR) - /* color to int */ - return false; - else - /* vector/point/normal to int */ - return false; + if(folder.all_inputs_constant()) { + if(from == SocketType::FLOAT) { + if(SocketType::is_float3(to)) { + folder.make_constant(make_float3(value_float, value_float, value_float)); + } } - else { - *optimized_value = value; + else if(SocketType::is_float3(from)) { + if(to == SocketType::FLOAT) { + if(from == SocketType::COLOR) { + /* color to float */ + folder.make_constant(linear_rgb_to_gray(value_color)); + } + else { + /* vector/point/normal to float */ + folder.make_constant(average(value_vector)); + } + } + else if(SocketType::is_float3(to)) { + folder.make_constant(value_color); + } } - - return true; } - - return false; } void ConvertNode::compile(SVMCompiler& compiler) { - /* constant folding should eliminate proxy nodes */ - assert(from != to); + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); ShaderInput *in = inputs[0]; ShaderOutput *out = outputs[0]; - if(from == SHADER_SOCKET_FLOAT) { - if(to == SHADER_SOCKET_INT) + if(from == SocketType::FLOAT) { + if(to == SocketType::INT) /* float to int */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out)); else /* float to float3 */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(from == SHADER_SOCKET_INT) { - if(to == SHADER_SOCKET_FLOAT) + else if(from == SocketType::INT) { + if(to == SocketType::FLOAT) /* int to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out)); else /* int to vector/point/normal */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(to == SHADER_SOCKET_FLOAT) { - if(from == SHADER_SOCKET_COLOR) + else if(to == SocketType::FLOAT) { + if(from == SocketType::COLOR) /* color to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out)); else /* vector/point/normal to float */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out)); } - else if(to == SHADER_SOCKET_INT) { - if(from == SHADER_SOCKET_COLOR) + else if(to == SocketType::INT) { + if(from == SocketType::COLOR) /* color to int */ compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out)); else @@ -1691,27 +1740,27 @@ void ConvertNode::compile(SVMCompiler& compiler) else { /* set 0,0,0 value */ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out)); - compiler.add_node(NODE_VALUE_V, in->value); + compiler.add_node(NODE_VALUE_V, value_color); } } } void ConvertNode::compile(OSLCompiler& compiler) { - /* constant folding should eliminate proxy nodes */ - assert(from != to); + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); - if(from == SHADER_SOCKET_FLOAT) + if(from == SocketType::FLOAT) compiler.add(this, "node_convert_from_float"); - else if(from == SHADER_SOCKET_INT) + else if(from == SocketType::INT) compiler.add(this, "node_convert_from_int"); - else if(from == SHADER_SOCKET_COLOR) + else if(from == SocketType::COLOR) compiler.add(this, "node_convert_from_color"); - else if(from == SHADER_SOCKET_VECTOR) + else if(from == SocketType::VECTOR) compiler.add(this, "node_convert_from_vector"); - else if(from == SHADER_SOCKET_POINT) + else if(from == SocketType::POINT) compiler.add(this, "node_convert_from_point"); - else if(from == SHADER_SOCKET_NORMAL) + else if(from == SocketType::NORMAL) compiler.add(this, "node_convert_from_normal"); else assert(0); @@ -1719,23 +1768,10 @@ void ConvertNode::compile(OSLCompiler& compiler) /* BSDF Closure */ -BsdfNode::BsdfNode(bool scattering_) -: ShaderNode("bsdf"), scattering(scattering_) +BsdfNode::BsdfNode(const NodeType *node_type) +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_CLOSURE; - - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); - - if(scattering) { - closure = CLOSURE_BSSRDF_CUBIC_ID; - add_output("BSSRDF", SHADER_SOCKET_CLOSURE); - } - else { - closure = CLOSURE_BSDF_DIFFUSE_ID; - add_output("BSDF", SHADER_SOCKET_CLOSURE); - } } void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4) @@ -1747,9 +1783,9 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); - int normal_offset = compiler.stack_assign_if_linked(normal_in); + int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID; int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID; int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID; int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID; @@ -1759,8 +1795,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value.x: 0.0f), - __float_as_int((param2)? param2->value.x: 0.0f)); + __float_as_int((param1)? get_float(param1->socket_type): 0.0f), + __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset); } @@ -1777,29 +1813,36 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/) /* Anisotropic BSDF Closure */ -static ShaderEnum aniso_distribution_init() +NODE_DEFINE(AnisotropicBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); - enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + + SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f); + SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f); -ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} AnisotropicBsdfNode::AnisotropicBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - distribution = ustring("GGX"); - - add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT); - - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); - add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f); } void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -1816,45 +1859,54 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib void AnisotropicBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); + if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } void AnisotropicBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter(this, "distribution"); compiler.add(this, "node_anisotropic_bsdf"); } /* Glossy BSDF Closure */ -static ShaderEnum glossy_distribution_init() +NODE_DEFINE(GlossyBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); - enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); -ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} GlossyBsdfNode::GlossyBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_MICROFACET_GGX_ID; - distribution = ustring("GGX"); - distribution_orig = ustring(""); - - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); + distribution_orig = NBUILTIN_CLOSURES; } void GlossyBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -1863,67 +1915,75 @@ void GlossyBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness <= 1e-4f) { + distribution = CLOSURE_BSDF_REFLECTION_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool GlossyBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void GlossyBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) + BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); else BsdfNode::compile(compiler, input("Roughness"), NULL); } void GlossyBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter(this, "distribution"); compiler.add(this, "node_glossy_bsdf"); } /* Glass BSDF Closure */ -static ShaderEnum glass_distribution_init() +NODE_DEFINE(GlassBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); -ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init(); + return type; +} GlassBsdfNode::GlassBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_SHARP_GLASS_ID; - distribution = ustring("Sharp"); - distribution_orig = ustring(""); - - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); + distribution_orig = NBUILTIN_CLOSURES; } void GlassBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -1932,67 +1992,75 @@ void GlassBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness <= 1e-4f) { + distribution = CLOSURE_BSDF_SHARP_GLASS_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool GlassBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void GlassBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) BsdfNode::compile(compiler, NULL, input("IOR")); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) + BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); else BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } void GlassBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter(this, "distribution"); compiler.add(this, "node_glass_bsdf"); } /* Refraction BSDF Closure */ -static ShaderEnum refraction_distribution_init() +NODE_DEFINE(RefractionBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); -ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} RefractionBsdfNode::RefractionBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_REFRACTION_ID; - distribution = ustring("Sharp"); - distribution_orig = ustring(""); - - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); + distribution_orig = NBUILTIN_CLOSURES; } void RefractionBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == "") { + if(distribution_orig == NBUILTIN_CLOSURES) { distribution_orig = distribution; } Integrator *integrator = scene->integrator; @@ -2001,26 +2069,26 @@ void RefractionBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value.x <= 1e-4f) { - distribution = ustring("Sharp"); + if(!roughness_input->link && roughness <= 1e-4f) { + distribution = CLOSURE_BSDF_REFRACTION_ID; } } else { /* Rollback to original distribution when filter glossy is used. */ distribution = distribution_orig; } - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; } bool RefractionBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value.x <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void RefractionBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)distribution_enum[distribution]; + closure = distribution; if(closure == CLOSURE_BSDF_REFRACTION_ID) BsdfNode::compile(compiler, NULL, input("IOR")); @@ -2030,53 +2098,71 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler) void RefractionBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution); + compiler.parameter(this, "distribution"); compiler.add(this, "node_refraction_bsdf"); } /* Toon BSDF Closure */ -static ShaderEnum toon_component_init() +NODE_DEFINE(ToonBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER); - enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); - enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum component_enum; + component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); + component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID); + SOCKET_IN_FLOAT(size, "Size", 0.5f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); -ShaderEnum ToonBsdfNode::component_enum = toon_component_init(); + return type; +} ToonBsdfNode::ToonBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_DIFFUSE_TOON_ID; - component = ustring("Diffuse"); - - add_input("Size", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f); } void ToonBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)component_enum[component]; + closure = component; BsdfNode::compile(compiler, input("Size"), input("Smooth")); } void ToonBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component); + compiler.parameter(this, "component"); compiler.add(this, "node_toon_bsdf"); } /* Velvet BSDF Closure */ +NODE_DEFINE(VelvetBsdfNode) +{ + NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + VelvetBsdfNode::VelvetBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; - - add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f); } void VelvetBsdfNode::compile(SVMCompiler& compiler) @@ -2091,10 +2177,24 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler) /* Diffuse BSDF Closure */ +NODE_DEFINE(DiffuseBsdfNode) +{ + NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + DiffuseBsdfNode::DiffuseBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_DIFFUSE_ID; - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f); } void DiffuseBsdfNode::compile(SVMCompiler& compiler) @@ -2108,33 +2208,40 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler) } /* Disney BSDF Closure */ +NODE_DEFINE(DisneyBsdfNode) +{ + NodeType* type = NodeType::add("disney_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(base_color, "BaseColor", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_COLOR(subsurface_color, "SubsurfaceColor", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f); + SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f); + SOCKET_IN_FLOAT(specular, "Specular", 0.0f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(specularTint, "SpecularTint", 0.0f); + SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); + SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); + SOCKET_IN_FLOAT(sheenTint, "SheenTint", 0.0f); + SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); + SOCKET_IN_FLOAT(clearcoatGloss, "ClearcoatGloss", 0.0f); + SOCKET_IN_FLOAT(ior, "IOR", 0.0f); + SOCKET_IN_FLOAT(transparency, "Transparency", 0.0f); + SOCKET_IN_FLOAT(refractionRoughness, "RefractionRoughness", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(clearcoatNormal, "ClearcoatNormal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + DisneyBsdfNode::DisneyBsdfNode() - : ShaderNode("bsdf") + : ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_CLOSURE; closure = CLOSURE_BSDF_DISNEY_ID; - - add_input("BaseColor", SHADER_SOCKET_COLOR, make_float3(0.646f, 0.415f, 0.017f)); - add_input("SubsurfaceColor", SHADER_SOCKET_COLOR, make_float3(0.646f, 0.415f, 0.017f)); - add_input("Metallic", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Subsurface", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Specular", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Roughness", SHADER_SOCKET_FLOAT, 0.5f); - add_input("SpecularTint", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Anisotropic", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Sheen", SHADER_SOCKET_FLOAT, 0.0f); - add_input("SheenTint", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Clearcoat", SHADER_SOCKET_FLOAT, 0.0f); - add_input("ClearcoatGloss", SHADER_SOCKET_FLOAT, 1.0f); - add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f); - add_input("Transparency", SHADER_SOCKET_FLOAT, 0.0f); - add_input("RefractionRoughness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("ClearcoatNormal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); - - add_output("BSDF", SHADER_SOCKET_CLOSURE); } void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface, @@ -2176,8 +2283,8 @@ void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, Shade compiler.stack_assign(metallic), compiler.stack_assign(subsurface), compiler.closure_mix_weight_offset()), - __float_as_int(metallic->value.x), - __float_as_int(subsurface->value.x)); + __float_as_int((metallic) ? get_float(metallic->socket_type) : 0.0f), + __float_as_int((subsurface) ? get_float(subsurface->socket_type) : 0.0f)); compiler.add_node(normal_offset, tangent_offset, compiler.encode_uchar4(specular_offset, roughness_offset, specularTint_offset, anisotropic_offset), @@ -2186,13 +2293,17 @@ void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, Shade compiler.add_node(compiler.encode_uchar4(ior_offset, transparency_offset, refr_roughness_offset, SVM_STACK_INVALID), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID); + float3 bc_default = get_float3(base_color_in->socket_type); + compiler.add_node(((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID), - __float_as_int(base_color_in->value.x), __float_as_int(base_color_in->value.y), __float_as_int(base_color_in->value.z)); + __float_as_int(bc_default.x), __float_as_int(bc_default.y), __float_as_int(bc_default.z)); compiler.add_node(clearcoat_normal_offset, SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID); + float3 ss_default = get_float3(subsurface_color_in->socket_type); + compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : SVM_STACK_INVALID), - __float_as_int(subsurface_color_in->value.x), __float_as_int(subsurface_color_in->value.y), __float_as_int(subsurface_color_in->value.z)); + __float_as_int(ss_default.x), __float_as_int(ss_default.y), __float_as_int(ss_default.z)); } void DisneyBsdfNode::compile(SVMCompiler& compiler) @@ -2216,7 +2327,21 @@ bool DisneyBsdfNode::has_bssrdf_bump() /* Translucent BSDF Closure */ +NODE_DEFINE(TranslucentBsdfNode) +{ + NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + TranslucentBsdfNode::TranslucentBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_TRANSLUCENT_ID; } @@ -2233,9 +2358,21 @@ void TranslucentBsdfNode::compile(OSLCompiler& compiler) /* Transparent BSDF Closure */ +NODE_DEFINE(TransparentBsdfNode) +{ + NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + TransparentBsdfNode::TransparentBsdfNode() +: BsdfNode(node_type) { - name = "transparent"; closure = CLOSURE_BSDF_TRANSPARENT_ID; } @@ -2251,39 +2388,45 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler) /* Subsurface Scattering Closure */ -static ShaderEnum subsurface_falloff_init() +NODE_DEFINE(SubsurfaceScatteringNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER); - enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID); - enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); - enm.insert("Burley", CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum falloff_enum; + falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID); + falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); + falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_IN_FLOAT(scale, "Scale", 0.01f); + SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f)); + SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f); + SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f); + + SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF"); -ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init(); + return type; +} SubsurfaceScatteringNode::SubsurfaceScatteringNode() -: BsdfNode(true) +: BsdfNode(node_type) { - name = "subsurface_scattering"; - closure = CLOSURE_BSSRDF_CUBIC_ID; - - add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f); - add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f)); - add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f); - add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f); + closure = falloff; } void SubsurfaceScatteringNode::compile(SVMCompiler& compiler) { + closure = falloff; BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness")); } void SubsurfaceScatteringNode::compile(OSLCompiler& compiler) { - compiler.parameter("Falloff", falloff_enum[closure]); + closure = falloff; + compiler.parameter(this, "falloff"); compiler.add(this, "node_subsurface_scattering"); } @@ -2296,14 +2439,22 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump() /* Emissive Closure */ -EmissionNode::EmissionNode() -: ShaderNode("emission") +NODE_DEFINE(EmissionNode) { - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + NodeType* type = NodeType::add("emission", create, NodeType::SHADER); - add_output("Emission", SHADER_SOCKET_CLOSURE); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 10.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(emission, "Emission"); + + return type; +} + +EmissionNode::EmissionNode() +: ShaderNode(node_type) +{ } void EmissionNode::compile(SVMCompiler& compiler) @@ -2314,10 +2465,10 @@ void EmissionNode::compile(SVMCompiler& compiler) if(color_in->link || strength_in->link) { compiler.add_node(NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), - compiler.stack_assign(strength_in)); + compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength); compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); } @@ -2327,25 +2478,35 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +void EmissionNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value.x == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Background Closure */ -BackgroundNode::BackgroundNode() -: ShaderNode("background") +NODE_DEFINE(BackgroundNode) { - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(background, "Background"); + + return type; +} - add_output("Background", SHADER_SOCKET_CLOSURE); +BackgroundNode::BackgroundNode() +: ShaderNode(node_type) +{ } void BackgroundNode::compile(SVMCompiler& compiler) @@ -2359,7 +2520,7 @@ void BackgroundNode::compile(SVMCompiler& compiler) compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength); compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); } @@ -2369,24 +2530,34 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +void BackgroundNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value.x == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Holdout Closure */ -HoldoutNode::HoldoutNode() -: ShaderNode("holdout") +NODE_DEFINE(HoldoutNode) { - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); - add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + NodeType* type = NodeType::add("holdout", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); - add_output("Holdout", SHADER_SOCKET_CLOSURE); + SOCKET_OUT_CLOSURE(holdout, "Holdout"); + + return type; +} + +HoldoutNode::HoldoutNode() +: ShaderNode(node_type) +{ } void HoldoutNode::compile(SVMCompiler& compiler) @@ -2404,14 +2575,22 @@ void HoldoutNode::compile(OSLCompiler& compiler) /* Ambient Occlusion */ -AmbientOcclusionNode::AmbientOcclusionNode() -: ShaderNode("ambient_occlusion") +NODE_DEFINE(AmbientOcclusionNode) { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER); - add_output("AO", SHADER_SOCKET_CLOSURE); + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(AO, "AO"); + + return type; +} + +AmbientOcclusionNode::AmbientOcclusionNode() +: ShaderNode(node_type) +{ } void AmbientOcclusionNode::compile(SVMCompiler& compiler) @@ -2421,7 +2600,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler) if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset()); } @@ -2433,16 +2612,10 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler) /* Volume Closure */ -VolumeNode::VolumeNode() -: ShaderNode("volume") +VolumeNode::VolumeNode(const NodeType *node_type) +: ShaderNode(node_type) { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - - add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Density", SHADER_SOCKET_FLOAT, 1.0f); - add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); - - add_output("Volume", SHADER_SOCKET_CLOSURE); } void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) @@ -2452,15 +2625,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); compiler.add_node(NODE_CLOSURE_VOLUME, compiler.encode_uchar4(closure, (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value.x: 0.0f), - __float_as_int((param2)? param2->value.x: 0.0f)); + __float_as_int((param1)? get_float(param1->socket_type): 0.0f), + __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); } void VolumeNode::compile(SVMCompiler& compiler) @@ -2475,7 +2648,21 @@ void VolumeNode::compile(OSLCompiler& /*compiler*/) /* Absorption Volume Closure */ +NODE_DEFINE(AbsorptionVolumeNode) +{ + NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(volume, "Volume"); + + return type; +} + AbsorptionVolumeNode::AbsorptionVolumeNode() +: VolumeNode(node_type) { closure = CLOSURE_VOLUME_ABSORPTION_ID; } @@ -2492,11 +2679,24 @@ void AbsorptionVolumeNode::compile(OSLCompiler& compiler) /* Scatter Volume Closure */ +NODE_DEFINE(ScatterVolumeNode) +{ + NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(volume, "Volume"); + + return type; +} + ScatterVolumeNode::ScatterVolumeNode() +: VolumeNode(node_type) { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - - add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f); } void ScatterVolumeNode::compile(SVMCompiler& compiler) @@ -2511,59 +2711,71 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler) /* Hair BSDF Closure */ -static ShaderEnum hair_component_init() +NODE_DEFINE(HairBsdfNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER); - enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); - enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum component_enum; + component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); + component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f); + SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f); + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); -ShaderEnum HairBsdfNode::component_enum = hair_component_init(); + return type; +} HairBsdfNode::HairBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_HAIR_REFLECTION_ID; - component = ustring("Reflection"); - - add_input("Offset", SHADER_SOCKET_FLOAT); - add_input("RoughnessU", SHADER_SOCKET_FLOAT); - add_input("RoughnessV", SHADER_SOCKET_FLOAT); - add_input("Tangent", SHADER_SOCKET_VECTOR); } void HairBsdfNode::compile(SVMCompiler& compiler) { - closure = (ClosureType)component_enum[component]; + closure = component; BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset")); } void HairBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component); - + compiler.parameter(this, "component"); compiler.add(this, "node_hair_bsdf"); } /* Geometry */ +NODE_DEFINE(GeometryNode) +{ + NodeType* type = NodeType::add("geometry", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + + SOCKET_OUT_POINT(position, "Position"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_NORMAL(tangent, "Tangent"); + SOCKET_OUT_NORMAL(true_normal, "True Normal"); + SOCKET_OUT_VECTOR(incoming, "Incoming"); + SOCKET_OUT_POINT(parametric, "Parametric"); + SOCKET_OUT_FLOAT(backfacing, "Backfacing"); + SOCKET_OUT_FLOAT(pointiness, "Pointiness"); + + return type; +} + GeometryNode::GeometryNode() -: ShaderNode("geometry") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_GEOMETRY; - - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Position", SHADER_SOCKET_POINT); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("Tangent", SHADER_SOCKET_NORMAL); - add_output("True Normal", SHADER_SOCKET_NORMAL); - add_output("Incoming", SHADER_SOCKET_VECTOR); - add_output("Parametric", SHADER_SOCKET_POINT); - add_output("Backfacing", SHADER_SOCKET_FLOAT); - add_output("Pointiness", SHADER_SOCKET_FLOAT); } void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2658,21 +2870,30 @@ void GeometryNode::compile(OSLCompiler& compiler) /* TextureCoordinate */ -TextureCoordinateNode::TextureCoordinateNode() -: ShaderNode("texture_coordinate") +NODE_DEFINE(TextureCoordinateNode) { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Generated", SHADER_SOCKET_POINT); - add_output("Normal", SHADER_SOCKET_NORMAL); - add_output("UV", SHADER_SOCKET_POINT); - add_output("Object", SHADER_SOCKET_POINT); - add_output("Camera", SHADER_SOCKET_POINT); - add_output("Window", SHADER_SOCKET_POINT); - add_output("Reflection", SHADER_SOCKET_NORMAL); + NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER); + + SOCKET_BOOLEAN(from_dupli, "From Dupli", false); + SOCKET_BOOLEAN(use_transform, "Use Transform", false); + SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity()); + + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - from_dupli = false; - use_transform = false; - ob_tfm = transform_identity(); + SOCKET_OUT_POINT(generated, "Generated"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_POINT(UV, "UV"); + SOCKET_OUT_POINT(object, "Object"); + SOCKET_OUT_POINT(camera, "Camera"); + SOCKET_OUT_POINT(window, "Window"); + SOCKET_OUT_NORMAL(reflection, "Reflection"); + + return type; +} + +TextureCoordinateNode::TextureCoordinateNode() +: ShaderNode(node_type) +{ } void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2796,22 +3017,32 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler) compiler.parameter("is_background", true); if(compiler.output_type() == SHADER_TYPE_VOLUME) compiler.parameter("is_volume", true); - compiler.parameter("use_transform", use_transform); + compiler.parameter(this, "use_transform"); Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm)); compiler.parameter("object_itfm", ob_itfm); - compiler.parameter("from_dupli", from_dupli); + compiler.parameter(this, "from_dupli"); compiler.add(this, "node_texture_coordinate"); } -UVMapNode::UVMapNode() -: ShaderNode("uvmap") +/* UV Map */ + +NODE_DEFINE(UVMapNode) { - attribute = ""; - from_dupli = false; + NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER); + + SOCKET_IN_STRING(attribute, "attribute", ustring("")); + SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false); + + SOCKET_OUT_POINT(UV, "UV"); - add_output("UV", SHADER_SOCKET_POINT); + return type; +} + +UVMapNode::UVMapNode() +: ShaderNode(node_type) +{ } void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2870,28 +3101,36 @@ void UVMapNode::compile(OSLCompiler& compiler) else compiler.parameter("bump_offset", "center"); - compiler.parameter("from_dupli", from_dupli); - compiler.parameter("name", attribute.c_str()); + compiler.parameter(this, "from_dupli"); + compiler.parameter(this, "attribute"); compiler.add(this, "node_uv_map"); } /* Light Path */ +NODE_DEFINE(LightPathNode) +{ + NodeType* type = NodeType::add("light_path", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray"); + SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray"); + SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray"); + SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray"); + SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray"); + SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray"); + SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray"); + SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray"); + SOCKET_OUT_FLOAT(ray_length, "Ray Length"); + SOCKET_OUT_FLOAT(ray_depth, "Ray Depth"); + SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth"); + SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth"); + + return type; +} + LightPathNode::LightPathNode() -: ShaderNode("light_path") -{ - add_output("Is Camera Ray", SHADER_SOCKET_FLOAT); - add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT); - add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT); - add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT); - add_output("Is Singular Ray", SHADER_SOCKET_FLOAT); - add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT); - add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT); - add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT); - add_output("Ray Length", SHADER_SOCKET_FLOAT); - add_output("Ray Depth", SHADER_SOCKET_FLOAT); - add_output("Transparent Depth", SHADER_SOCKET_FLOAT); - add_output("Transmission Depth", SHADER_SOCKET_FLOAT); +: ShaderNode(node_type) +{ } void LightPathNode::compile(SVMCompiler& compiler) @@ -2967,14 +3206,23 @@ void LightPathNode::compile(OSLCompiler& compiler) /* Light Falloff */ +NODE_DEFINE(LightFalloffNode) +{ + NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(strength, "Strength", 100.0f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + + SOCKET_OUT_FLOAT(quadratic, "Quadratic"); + SOCKET_OUT_FLOAT(linear, "Linear"); + SOCKET_OUT_FLOAT(constant, "Constant"); + + return type; +} + LightFalloffNode::LightFalloffNode() -: ShaderNode("light_fallof") +: ShaderNode(node_type) { - add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f); - add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f); - add_output("Quadratic", SHADER_SOCKET_FLOAT); - add_output("Linear", SHADER_SOCKET_FLOAT); - add_output("Constant", SHADER_SOCKET_FLOAT); } void LightFalloffNode::compile(SVMCompiler& compiler) @@ -3017,13 +3265,21 @@ void LightFalloffNode::compile(OSLCompiler& compiler) /* Object Info */ +NODE_DEFINE(ObjectInfoNode) +{ + NodeType* type = NodeType::add("object_info", create, NodeType::SHADER); + + SOCKET_OUT_VECTOR(location, "Location"); + SOCKET_OUT_FLOAT(object_index, "Object Index"); + SOCKET_OUT_FLOAT(material_index, "Material Index"); + SOCKET_OUT_FLOAT(random, "Random"); + + return type; +} + ObjectInfoNode::ObjectInfoNode() -: ShaderNode("object_info") +: ShaderNode(node_type) { - add_output("Location", SHADER_SOCKET_VECTOR); - add_output("Object Index", SHADER_SOCKET_FLOAT); - add_output("Material Index", SHADER_SOCKET_FLOAT); - add_output("Random", SHADER_SOCKET_FLOAT); } void ObjectInfoNode::compile(SVMCompiler& compiler) @@ -3056,19 +3312,27 @@ void ObjectInfoNode::compile(OSLCompiler& compiler) /* Particle Info */ -ParticleInfoNode::ParticleInfoNode() -: ShaderNode("particle_info") +NODE_DEFINE(ParticleInfoNode) { - add_output("Index", SHADER_SOCKET_FLOAT); - add_output("Age", SHADER_SOCKET_FLOAT); - add_output("Lifetime", SHADER_SOCKET_FLOAT); - add_output("Location", SHADER_SOCKET_POINT); + NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(index, "Index"); + SOCKET_OUT_FLOAT(age, "Age"); + SOCKET_OUT_FLOAT(lifetime, "Lifetime"); + SOCKET_OUT_POINT(location, "Location"); #if 0 /* not yet supported */ - add_output("Rotation", SHADER_SOCKET_QUATERNION); + SOCKET_OUT_QUATERNION(rotation, "Rotation"); #endif - add_output("Size", SHADER_SOCKET_FLOAT); - add_output("Velocity", SHADER_SOCKET_VECTOR); - add_output("Angular Velocity", SHADER_SOCKET_VECTOR); + SOCKET_OUT_FLOAT(size, "Size"); + SOCKET_OUT_VECTOR(velocity, "Velocity"); + SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity"); + + return type; +} + +ParticleInfoNode::ParticleInfoNode() +: ShaderNode(node_type) +{ } void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3150,15 +3414,24 @@ void ParticleInfoNode::compile(OSLCompiler& compiler) /* Hair Info */ +NODE_DEFINE(HairInfoNode) +{ + NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(is_strand, "Is Strand"); + SOCKET_OUT_FLOAT(intercept, "Intercept"); + SOCKET_OUT_FLOAT(thickness, "Thickness"); + SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal"); +#if 0 /*output for minimum hair width transparency - deactivated */ + SOCKET_OUT_FLOAT(fade, "Fade"); +#endif + + return type; +} + HairInfoNode::HairInfoNode() -: ShaderNode("hair_info") +: ShaderNode(node_type) { - add_output("Is Strand", SHADER_SOCKET_FLOAT); - add_output("Intercept", SHADER_SOCKET_FLOAT); - add_output("Thickness", SHADER_SOCKET_FLOAT); - add_output("Tangent Normal", SHADER_SOCKET_NORMAL); - /*output for minimum hair width transparency - deactivated*/ - /*add_output("Fade", SHADER_SOCKET_FLOAT);*/ } void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3212,19 +3485,24 @@ void HairInfoNode::compile(OSLCompiler& compiler) /* Value */ -ValueNode::ValueNode() -: ShaderNode("value") +NODE_DEFINE(ValueNode) { - value = 0.0f; + NodeType* type = NodeType::add("value", create, NodeType::SHADER); + + SOCKET_FLOAT(value, "Value", 0.0f); + SOCKET_OUT_FLOAT(value, "Value"); - add_output("Value", SHADER_SOCKET_FLOAT); + return type; } -bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, - float3 *optimized_value) +ValueNode::ValueNode() +: ShaderNode(node_type) { - *optimized_value = make_float3(value, value, value); - return true; +} + +void ValueNode::constant_fold(const ConstantFolder& folder) +{ + folder.make_constant(value); } void ValueNode::compile(SVMCompiler& compiler) @@ -3242,19 +3520,24 @@ void ValueNode::compile(OSLCompiler& compiler) /* Color */ -ColorNode::ColorNode() -: ShaderNode("color") +NODE_DEFINE(ColorNode) { - value = make_float3(0.0f, 0.0f, 0.0f); + NodeType* type = NodeType::add("color", create, NodeType::SHADER); - add_output("Color", SHADER_SOCKET_COLOR); + SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_COLOR(color, "Color"); + + return type; } -bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, - float3 *optimized_value) +ColorNode::ColorNode() +: ShaderNode(node_type) { - *optimized_value = value; - return true; +} + +void ColorNode::constant_fold(const ConstantFolder& folder) +{ + folder.make_constant(value); } void ColorNode::compile(SVMCompiler& compiler) @@ -3276,14 +3559,21 @@ void ColorNode::compile(OSLCompiler& compiler) /* Add Closure */ +NODE_DEFINE(AddClosureNode) +{ + NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER); + + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); + SOCKET_OUT_CLOSURE(closure, "Closure"); + + return type; +} + AddClosureNode::AddClosureNode() -: ShaderNode("add_closure") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - - add_input("Closure1", SHADER_SOCKET_CLOSURE); - add_input("Closure2", SHADER_SOCKET_CLOSURE); - add_output("Closure", SHADER_SOCKET_CLOSURE); } void AddClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3296,17 +3586,39 @@ void AddClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_add_closure"); } +void AddClosureNode::constant_fold(const ConstantFolder& folder) +{ + ShaderInput *closure1_in = input("Closure1"); + ShaderInput *closure2_in = input("Closure2"); + + /* remove useless add closures nodes */ + if(!closure1_in->link) { + folder.bypass_or_discard(closure2_in); + } + else if(!closure2_in->link) { + folder.bypass_or_discard(closure1_in); + } +} + /* Mix Closure */ +NODE_DEFINE(MixClosureNode) +{ + NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); + + SOCKET_OUT_CLOSURE(closure, "Closure"); + + return type; +} + MixClosureNode::MixClosureNode() -: ShaderNode("mix_closure") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - - add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Closure1", SHADER_SOCKET_CLOSURE); - add_input("Closure2", SHADER_SOCKET_CLOSURE); - add_output("Closure", SHADER_SOCKET_CLOSURE); } void MixClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3319,46 +3631,48 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) +void MixClosureNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *closure1_in = input("Closure1"); ShaderInput *closure2_in = input("Closure2"); - ShaderOutput *closure_out = output("Closure"); /* remove useless mix closures nodes */ if(closure1_in->link == closure2_in->link) { - graph->relink(this, closure_out, closure1_in->link); - return true; + folder.bypass_or_discard(closure1_in); } - - /* remove unused mix closure input when factor is 0.0 or 1.0 */ - /* check for closure links and make sure factor link is disconnected */ - if(closure1_in->link && closure2_in->link && !fac_in->link) { + /* remove unused mix closure input when factor is 0.0 or 1.0 + * check for closure links and make sure factor link is disconnected */ + else if(!fac_in->link) { /* factor 0.0 */ - if(fac_in->value.x == 0.0f) { - graph->relink(this, closure_out, closure1_in->link); - return true; + if(fac <= 0.0f) { + folder.bypass_or_discard(closure1_in); } /* factor 1.0 */ - else if(fac_in->value.x == 1.0f) { - graph->relink(this, closure_out, closure2_in->link); - return true; + else if(fac >= 1.0f) { + folder.bypass_or_discard(closure2_in); } } - - return false; } /* Mix Closure */ +NODE_DEFINE(MixClosureWeightNode) +{ + NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(weight, "Weight", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + + SOCKET_OUT_FLOAT(weight1, "Weight1"); + SOCKET_OUT_FLOAT(weight2, "Weight2"); + + return type; +} + MixClosureWeightNode::MixClosureWeightNode() -: ShaderNode("mix_closure_weight") +: ShaderNode(node_type) { - add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f); - add_output("Weight1", SHADER_SOCKET_FLOAT); - add_output("Weight2", SHADER_SOCKET_FLOAT); } void MixClosureWeightNode::compile(SVMCompiler& compiler) @@ -3383,12 +3697,38 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/) /* Invert */ +NODE_DEFINE(InvertNode) +{ + NodeType* type = NodeType::add("invert", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + InvertNode::InvertNode() -: ShaderNode("invert") +: ShaderNode(node_type) +{ +} + +void InvertNode::constant_fold(const ConstantFolder& folder) { - add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); + + if(!fac_in->link) { + /* evaluate fully constant node */ + if(!color_in->link) { + folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); + } + /* remove no-op node */ + else if(fac == 0.0f) { + folder.bypass(color_in->link); + } + } } void InvertNode::compile(SVMCompiler& compiler) @@ -3410,46 +3750,46 @@ void InvertNode::compile(OSLCompiler& compiler) /* Mix */ -MixNode::MixNode() -: ShaderNode("mix") +NODE_DEFINE(MixNode) { - type = ustring("Mix"); + NodeType* type = NodeType::add("mix", create, NodeType::SHADER); - use_clamp = false; + static NodeEnum type_enum; + type_enum.insert("mix", NODE_MIX_BLEND); + type_enum.insert("add", NODE_MIX_ADD); + type_enum.insert("multiply", NODE_MIX_MUL); + type_enum.insert("screen", NODE_MIX_SCREEN); + type_enum.insert("overlay", NODE_MIX_OVERLAY); + type_enum.insert("subtract", NODE_MIX_SUB); + type_enum.insert("divide", NODE_MIX_DIV); + type_enum.insert("difference", NODE_MIX_DIFF); + type_enum.insert("darken", NODE_MIX_DARK); + type_enum.insert("lighten", NODE_MIX_LIGHT); + type_enum.insert("dodge", NODE_MIX_DODGE); + type_enum.insert("burn", NODE_MIX_BURN); + type_enum.insert("hue", NODE_MIX_HUE); + type_enum.insert("saturation", NODE_MIX_SAT); + type_enum.insert("value", NODE_MIX_VAL); + type_enum.insert("color", NODE_MIX_COLOR); + type_enum.insert("soft_light", NODE_MIX_SOFT); + type_enum.insert("linear_light", NODE_MIX_LINEAR); + SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND); - add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); - add_input("Color1", SHADER_SOCKET_COLOR); - add_input("Color2", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); -} + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); -static ShaderEnum mix_type_init() -{ - ShaderEnum enm; + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); - enm.insert("Mix", NODE_MIX_BLEND); - enm.insert("Add", NODE_MIX_ADD); - enm.insert("Multiply", NODE_MIX_MUL); - enm.insert("Screen", NODE_MIX_SCREEN); - enm.insert("Overlay", NODE_MIX_OVERLAY); - enm.insert("Subtract", NODE_MIX_SUB); - enm.insert("Divide", NODE_MIX_DIV); - enm.insert("Difference", NODE_MIX_DIFF); - enm.insert("Darken", NODE_MIX_DARK); - enm.insert("Lighten", NODE_MIX_LIGHT); - enm.insert("Dodge", NODE_MIX_DODGE); - enm.insert("Burn", NODE_MIX_BURN); - enm.insert("Hue", NODE_MIX_HUE); - enm.insert("Saturation", NODE_MIX_SAT); - enm.insert("Value", NODE_MIX_VAL); - enm.insert("Color", NODE_MIX_COLOR); - enm.insert("Soft Light", NODE_MIX_SOFT); - enm.insert("Linear Light", NODE_MIX_LINEAR); + SOCKET_OUT_COLOR(color, "Color"); - return enm; + return type; } -ShaderEnum MixNode::type_enum = mix_type_init(); +MixNode::MixNode() +: ShaderNode(node_type) +{ +} void MixNode::compile(SVMCompiler& compiler) { @@ -3462,7 +3802,7 @@ void MixNode::compile(SVMCompiler& compiler) compiler.stack_assign(fac_in), compiler.stack_assign(color1_in), compiler.stack_assign(color2_in)); - compiler.add_node(NODE_MIX, type_enum[type], compiler.stack_assign(color_out)); + compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out)); if(use_clamp) { compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out)); @@ -3472,59 +3812,46 @@ void MixNode::compile(SVMCompiler& compiler) void MixNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("Clamp", use_clamp); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * optimized_value) +void MixNode::constant_fold(const ConstantFolder& folder) { - if(type != ustring("Mix")) { - return false; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); } + else { + folder.fold_mix(type, use_clamp); + } +} - ShaderInput *fac_in = input("Fac"); - ShaderInput *color1_in = input("Color1"); - ShaderInput *color2_in = input("Color2"); - ShaderOutput *color_out = output("Color"); +/* Combine RGB */ - /* remove useless mix colors nodes */ - if(color1_in->link && color1_in->link == color2_in->link) { - graph->relink(this, color_out, color1_in->link); - return true; - } +NODE_DEFINE(CombineRGBNode) +{ + NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER); - /* remove unused mix color input when factor is 0.0 or 1.0 */ - if(!fac_in->link) { - /* factor 0.0 */ - if(fac_in->value.x == 0.0f) { - if(color1_in->link) - graph->relink(this, color_out, color1_in->link); - else - *optimized_value = color1_in->value; - return true; - } - /* factor 1.0 */ - else if(fac_in->value.x == 1.0f) { - if(color2_in->link) - graph->relink(this, color_out, color2_in->link); - else - *optimized_value = color2_in->value; - return true; - } - } + SOCKET_IN_FLOAT(r, "R", 0.0f); + SOCKET_IN_FLOAT(g, "G", 0.0f); + SOCKET_IN_FLOAT(b, "B", 0.0f); - return false; + SOCKET_OUT_COLOR(image, "Image"); + + return type; } -/* Combine RGB */ CombineRGBNode::CombineRGBNode() -: ShaderNode("combine_rgb") +: ShaderNode(node_type) +{ +} + +void CombineRGBNode::constant_fold(const ConstantFolder& folder) { - add_input("R", SHADER_SOCKET_FLOAT); - add_input("G", SHADER_SOCKET_FLOAT); - add_input("B", SHADER_SOCKET_FLOAT); - add_output("Image", SHADER_SOCKET_COLOR); + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(r, g, b)); + } } void CombineRGBNode::compile(SVMCompiler& compiler) @@ -3553,13 +3880,30 @@ void CombineRGBNode::compile(OSLCompiler& compiler) } /* Combine XYZ */ + +NODE_DEFINE(CombineXYZNode) +{ + NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(x, "X", 0.0f); + SOCKET_IN_FLOAT(y, "Y", 0.0f); + SOCKET_IN_FLOAT(z, "Z", 0.0f); + + SOCKET_OUT_VECTOR(vector, "Vector"); + + return type; +} + CombineXYZNode::CombineXYZNode() -: ShaderNode("combine_xyz") +: ShaderNode(node_type) +{ +} + +void CombineXYZNode::constant_fold(const ConstantFolder& folder) { - add_input("X", SHADER_SOCKET_FLOAT); - add_input("Y", SHADER_SOCKET_FLOAT); - add_input("Z", SHADER_SOCKET_FLOAT); - add_output("Vector", SHADER_SOCKET_VECTOR); + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(x, y, z)); + } } void CombineXYZNode::compile(SVMCompiler& compiler) @@ -3588,13 +3932,30 @@ void CombineXYZNode::compile(OSLCompiler& compiler) } /* Combine HSV */ + +NODE_DEFINE(CombineHSVNode) +{ + NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(h, "H", 0.0f); + SOCKET_IN_FLOAT(s, "S", 0.0f); + SOCKET_IN_FLOAT(v, "V", 0.0f); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + CombineHSVNode::CombineHSVNode() -: ShaderNode("combine_hsv") +: ShaderNode(node_type) { - add_input("H", SHADER_SOCKET_FLOAT); - add_input("S", SHADER_SOCKET_FLOAT); - add_input("V", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); +} + +void CombineHSVNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); + } } void CombineHSVNode::compile(SVMCompiler& compiler) @@ -3618,28 +3979,28 @@ void CombineHSVNode::compile(OSLCompiler& compiler) } /* Gamma */ -GammaNode::GammaNode() -: ShaderNode("gamma") + +NODE_DEFINE(GammaNode) { - add_input("Color", SHADER_SOCKET_COLOR); - add_input("Gamma", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + NodeType* type = NodeType::add("gamma", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; } -bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +GammaNode::GammaNode() +: ShaderNode(node_type) { - ShaderInput *color_in = input("Color"); - ShaderInput *gamma_in = input("Gamma"); +} - if(socket == output("Color")) { - if(color_in->link == NULL && gamma_in->link == NULL) { - *optimized_value = svm_math_gamma_color(color_in->value, - gamma_in->value.x); - return true; - } +void GammaNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_gamma_color(color, gamma)); } - - return false; } void GammaNode::compile(SVMCompiler& compiler) @@ -3660,13 +4021,30 @@ void GammaNode::compile(OSLCompiler& compiler) } /* Bright Contrast */ + +NODE_DEFINE(BrightContrastNode) +{ + NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(bright, "Bright", 0.0f); + SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + BrightContrastNode::BrightContrastNode() -: ShaderNode("brightness") +: ShaderNode(node_type) +{ +} + +void BrightContrastNode::constant_fold(const ConstantFolder& folder) { - add_input("Color", SHADER_SOCKET_COLOR); - add_input("Bright", SHADER_SOCKET_FLOAT); - add_input("Contrast", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); + if(folder.all_inputs_constant()) { + folder.make_constant(svm_brightness_contrast(color, bright, contrast)); + } } void BrightContrastNode::compile(SVMCompiler& compiler) @@ -3690,13 +4068,35 @@ void BrightContrastNode::compile(OSLCompiler& compiler) } /* Separate RGB */ + +NODE_DEFINE(SeparateRGBNode) +{ + NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(g, "R"); + SOCKET_OUT_FLOAT(g, "G"); + SOCKET_OUT_FLOAT(b, "B"); + + return type; +} + SeparateRGBNode::SeparateRGBNode() -: ShaderNode("separate_rgb") +: ShaderNode(node_type) +{ +} + +void SeparateRGBNode::constant_fold(const ConstantFolder& folder) { - add_input("Image", SHADER_SOCKET_COLOR); - add_output("R", SHADER_SOCKET_FLOAT); - add_output("G", SHADER_SOCKET_FLOAT); - add_output("B", SHADER_SOCKET_FLOAT); + if(folder.all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(color[channel]); + return; + } + } + } } void SeparateRGBNode::compile(SVMCompiler& compiler) @@ -3725,13 +4125,35 @@ void SeparateRGBNode::compile(OSLCompiler& compiler) } /* Separate XYZ */ + +NODE_DEFINE(SeparateXYZNode) +{ + NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER); + + SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(x, "X"); + SOCKET_OUT_FLOAT(y, "Y"); + SOCKET_OUT_FLOAT(z, "Z"); + + return type; +} + SeparateXYZNode::SeparateXYZNode() -: ShaderNode("separate_xyz") +: ShaderNode(node_type) +{ +} + +void SeparateXYZNode::constant_fold(const ConstantFolder& folder) { - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("X", SHADER_SOCKET_FLOAT); - add_output("Y", SHADER_SOCKET_FLOAT); - add_output("Z", SHADER_SOCKET_FLOAT); + if(folder.all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(vector[channel]); + return; + } + } + } } void SeparateXYZNode::compile(SVMCompiler& compiler) @@ -3760,13 +4182,37 @@ void SeparateXYZNode::compile(OSLCompiler& compiler) } /* Separate HSV */ + +NODE_DEFINE(SeparateHSVNode) +{ + NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(h, "H"); + SOCKET_OUT_FLOAT(s, "S"); + SOCKET_OUT_FLOAT(v, "V"); + + return type; +} + SeparateHSVNode::SeparateHSVNode() -: ShaderNode("separate_hsv") +: ShaderNode(node_type) +{ +} + +void SeparateHSVNode::constant_fold(const ConstantFolder& folder) { - add_input("Color", SHADER_SOCKET_COLOR); - add_output("H", SHADER_SOCKET_FLOAT); - add_output("S", SHADER_SOCKET_FLOAT); - add_output("V", SHADER_SOCKET_FLOAT); + if(folder.all_inputs_constant()) { + float3 hsv = rgb_to_hsv(color); + + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(hsv[channel]); + return; + } + } + } } void SeparateHSVNode::compile(SVMCompiler& compiler) @@ -3790,15 +4236,25 @@ void SeparateHSVNode::compile(OSLCompiler& compiler) } /* Hue Saturation Value */ + +NODE_DEFINE(HSVNode) +{ + NodeType* type = NodeType::add("hsv", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(hue, "Hue", 0.5f); + SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f); + SOCKET_IN_FLOAT(value, "Value", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + HSVNode::HSVNode() -: ShaderNode("hsv") +: ShaderNode(node_type) { - add_input("Hue", SHADER_SOCKET_FLOAT); - add_input("Saturation", SHADER_SOCKET_FLOAT); - add_input("Value", SHADER_SOCKET_FLOAT); - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); } void HSVNode::compile(SVMCompiler& compiler) @@ -3828,14 +4284,22 @@ void HSVNode::compile(OSLCompiler& compiler) /* Attribute */ -AttributeNode::AttributeNode() -: ShaderNode("attribute") +NODE_DEFINE(AttributeNode) { - attribute = ""; + NodeType* type = NodeType::add("attribute", create, NodeType::SHADER); + + SOCKET_STRING(attribute, "Attribute", ustring("")); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Vector", SHADER_SOCKET_VECTOR); - add_output("Fac", SHADER_SOCKET_FLOAT); +AttributeNode::AttributeNode() +: ShaderNode(node_type) +{ } void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3911,12 +4375,20 @@ void AttributeNode::compile(OSLCompiler& compiler) /* Camera */ +NODE_DEFINE(CameraNode) +{ + NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER); + + SOCKET_OUT_VECTOR(view_vector, "View Vector"); + SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth"); + SOCKET_OUT_FLOAT(view_distance, "View Distance"); + + return type; +} + CameraNode::CameraNode() -: ShaderNode("camera") +: ShaderNode(node_type) { - add_output("View Vector", SHADER_SOCKET_VECTOR); - add_output("View Z Depth", SHADER_SOCKET_FLOAT); - add_output("View Distance", SHADER_SOCKET_FLOAT); } void CameraNode::compile(SVMCompiler& compiler) @@ -3938,12 +4410,21 @@ void CameraNode::compile(OSLCompiler& compiler) /* Fresnel */ +NODE_DEFINE(FresnelNode) +{ + NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(IOR, "IOR", 1.45f); + + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + FresnelNode::FresnelNode() -: ShaderNode("fresnel") +: ShaderNode(node_type) { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f); - add_output("Fac", SHADER_SOCKET_FLOAT); } void FresnelNode::compile(SVMCompiler& compiler) @@ -3954,7 +4435,7 @@ void FresnelNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_FRESNEL, compiler.stack_assign(IOR_in), - __float_as_int(IOR_in->value.x), + __float_as_int(IOR), compiler.encode_uchar4( compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fac_out))); @@ -3967,14 +4448,22 @@ void FresnelNode::compile(OSLCompiler& compiler) /* Layer Weight */ -LayerWeightNode::LayerWeightNode() -: ShaderNode("layer_weight") +NODE_DEFINE(LayerWeightNode) { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f); + NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(blend, "Blend", 0.5f); + + SOCKET_OUT_FLOAT(fresnel, "Fresnel"); + SOCKET_OUT_FLOAT(facing, "Facing"); + + return type; +} - add_output("Fresnel", SHADER_SOCKET_FLOAT); - add_output("Facing", SHADER_SOCKET_FLOAT); +LayerWeightNode::LayerWeightNode() +: ShaderNode(node_type) +{ } void LayerWeightNode::compile(SVMCompiler& compiler) @@ -3987,7 +4476,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!fresnel_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value.x), + __float_as_int(blend), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fresnel_out))); @@ -3996,7 +4485,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!facing_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value.x), + __float_as_int(blend), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(facing_out))); @@ -4010,13 +4499,20 @@ void LayerWeightNode::compile(OSLCompiler& compiler) /* Wireframe */ +NODE_DEFINE(WireframeNode) +{ + NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER); + + SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false); + SOCKET_IN_FLOAT(size, "Size", 0.01f); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + WireframeNode::WireframeNode() -: ShaderNode("wireframe") +: ShaderNode(node_type) { - add_input("Size", SHADER_SOCKET_FLOAT, 0.01f); - add_output("Fac", SHADER_SOCKET_FLOAT); - - use_pixel_size = false; } void WireframeNode::compile(SVMCompiler& compiler) @@ -4049,17 +4545,25 @@ void WireframeNode::compile(OSLCompiler& compiler) else { compiler.parameter("bump_offset", "center"); } - compiler.parameter("use_pixel_size", use_pixel_size); + compiler.parameter(this, "use_pixel_size"); compiler.add(this, "node_wireframe"); } /* Wavelength */ +NODE_DEFINE(WavelengthNode) +{ + NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + WavelengthNode::WavelengthNode() -: ShaderNode("wavelength") +: ShaderNode(node_type) { - add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f); - add_output("Color", SHADER_SOCKET_COLOR); } void WavelengthNode::compile(SVMCompiler& compiler) @@ -4079,25 +4583,26 @@ void WavelengthNode::compile(OSLCompiler& compiler) /* Blackbody */ -BlackbodyNode::BlackbodyNode() -: ShaderNode("blackbody") +NODE_DEFINE(BlackbodyNode) { - add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f); - add_output("Color", SHADER_SOCKET_COLOR); + NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; } -bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +BlackbodyNode::BlackbodyNode() +: ShaderNode(node_type) { - ShaderInput *temperature_in = input("Temperature"); +} - if(socket == output("Color")) { - if(temperature_in->link == NULL) { - *optimized_value = svm_math_blackbody_color(temperature_in->value.x); - return true; - } +void BlackbodyNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_blackbody_color(temperature)); } - - return false; } void BlackbodyNode::compile(SVMCompiler& compiler) @@ -4117,15 +4622,22 @@ void BlackbodyNode::compile(OSLCompiler& compiler) /* Output */ +NODE_DEFINE(OutputNode) +{ + NodeType* type = NodeType::add("output", create, NodeType::SHADER); + + SOCKET_IN_CLOSURE(surface, "Surface"); + SOCKET_IN_CLOSURE(volume, "Volume"); + SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); + + return type; +} + OutputNode::OutputNode() -: ShaderNode("output") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_OUTPUT; - - add_input("Surface", SHADER_SOCKET_CLOSURE); - add_input("Volume", SHADER_SOCKET_CLOSURE); - add_input("Displacement", SHADER_SOCKET_FLOAT); - add_input("Normal", SHADER_SOCKET_NORMAL); } void OutputNode::compile(SVMCompiler& compiler) @@ -4151,67 +4663,55 @@ void OutputNode::compile(OSLCompiler& compiler) /* Math */ -MathNode::MathNode() -: ShaderNode("math") +NODE_DEFINE(MathNode) { - type = ustring("Add"); + NodeType* type = NodeType::add("math", create, NodeType::SHADER); - use_clamp = false; + static NodeEnum type_enum; + type_enum.insert("add", NODE_MATH_ADD); + type_enum.insert("subtract", NODE_MATH_SUBTRACT); + type_enum.insert("multiply", NODE_MATH_MULTIPLY); + type_enum.insert("divide", NODE_MATH_DIVIDE); + type_enum.insert("sine", NODE_MATH_SINE); + type_enum.insert("cosine", NODE_MATH_COSINE); + type_enum.insert("tangent", NODE_MATH_TANGENT); + type_enum.insert("arcsine", NODE_MATH_ARCSINE); + type_enum.insert("arccosine", NODE_MATH_ARCCOSINE); + type_enum.insert("arctangent", NODE_MATH_ARCTANGENT); + type_enum.insert("power", NODE_MATH_POWER); + type_enum.insert("logarithm", NODE_MATH_LOGARITHM); + type_enum.insert("minimum", NODE_MATH_MINIMUM); + type_enum.insert("maximum", NODE_MATH_MAXIMUM); + type_enum.insert("round", NODE_MATH_ROUND); + type_enum.insert("less_than", NODE_MATH_LESS_THAN); + type_enum.insert("greater_than", NODE_MATH_GREATER_THAN); + type_enum.insert("modulo", NODE_MATH_MODULO); + type_enum.insert("absolute", NODE_MATH_ABSOLUTE); + SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); - add_input("Value1", SHADER_SOCKET_FLOAT); - add_input("Value2", SHADER_SOCKET_FLOAT); - add_output("Value", SHADER_SOCKET_FLOAT); -} + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); -static ShaderEnum math_type_init() -{ - ShaderEnum enm; + SOCKET_IN_FLOAT(value1, "Value1", 0.0f); + SOCKET_IN_FLOAT(value2, "Value2", 0.0f); - enm.insert("Add", NODE_MATH_ADD); - enm.insert("Subtract", NODE_MATH_SUBTRACT); - enm.insert("Multiply", NODE_MATH_MULTIPLY); - enm.insert("Divide", NODE_MATH_DIVIDE); - enm.insert("Sine", NODE_MATH_SINE); - enm.insert("Cosine", NODE_MATH_COSINE); - enm.insert("Tangent", NODE_MATH_TANGENT); - enm.insert("Arcsine", NODE_MATH_ARCSINE); - enm.insert("Arccosine", NODE_MATH_ARCCOSINE); - enm.insert("Arctangent", NODE_MATH_ARCTANGENT); - enm.insert("Power", NODE_MATH_POWER); - enm.insert("Logarithm", NODE_MATH_LOGARITHM); - enm.insert("Minimum", NODE_MATH_MINIMUM); - enm.insert("Maximum", NODE_MATH_MAXIMUM); - enm.insert("Round", NODE_MATH_ROUND); - enm.insert("Less Than", NODE_MATH_LESS_THAN); - enm.insert("Greater Than", NODE_MATH_GREATER_THAN); - enm.insert("Modulo", NODE_MATH_MODULO); - enm.insert("Absolute", NODE_MATH_ABSOLUTE); + SOCKET_OUT_FLOAT(value, "Value"); - return enm; + return type; } -ShaderEnum MathNode::type_enum = math_type_init(); - -bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +MathNode::MathNode() +: ShaderNode(node_type) { - ShaderInput *value1_in = input("Value1"); - ShaderInput *value2_in = input("Value2"); - - if(socket == output("Value")) { - if(value1_in->link == NULL && value2_in->link == NULL) { - optimized_value->x = svm_math((NodeMath)type_enum[type], - value1_in->value.x, - value2_in->value.x); - - if(use_clamp) { - optimized_value->x = saturate(optimized_value->x); - } +} - return true; - } +void MathNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); + } + else { + folder.fold_math(type, use_clamp); } - - return false; } void MathNode::compile(SVMCompiler& compiler) @@ -4220,10 +4720,7 @@ void MathNode::compile(SVMCompiler& compiler) ShaderInput *value2_in = input("Value2"); ShaderOutput *value_out = output("Value"); - compiler.add_node(NODE_MATH, - type_enum[type], - compiler.stack_assign(value1_in), - compiler.stack_assign(value2_in)); + compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in)); compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); if(use_clamp) { @@ -4234,66 +4731,62 @@ void MathNode::compile(SVMCompiler& compiler) void MathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("Clamp", use_clamp); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); compiler.add(this, "node_math"); } /* VectorMath */ -VectorMathNode::VectorMathNode() -: ShaderNode("vector_math") +NODE_DEFINE(VectorMathNode) { - type = ustring("Add"); + NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER); - add_input("Vector1", SHADER_SOCKET_VECTOR); - add_input("Vector2", SHADER_SOCKET_VECTOR); - add_output("Value", SHADER_SOCKET_FLOAT); - add_output("Vector", SHADER_SOCKET_VECTOR); -} + static NodeEnum type_enum; + type_enum.insert("add", NODE_VECTOR_MATH_ADD); + type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT); + type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE); + type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); + type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT); + type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD); -static ShaderEnum vector_math_type_init() -{ - ShaderEnum enm; + SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f)); - enm.insert("Add", NODE_VECTOR_MATH_ADD); - enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT); - enm.insert("Average", NODE_VECTOR_MATH_AVERAGE); - enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT); - enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT); - enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE); + SOCKET_OUT_FLOAT(value, "Value"); + SOCKET_OUT_VECTOR(vector, "Vector"); - return enm; + return type; } -ShaderEnum VectorMathNode::type_enum = vector_math_type_init(); - -bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value) +VectorMathNode::VectorMathNode() +: ShaderNode(node_type) { - ShaderInput *vector1_in = input("Vector1"); - ShaderInput *vector2_in = input("Vector2"); +} +void VectorMathNode::constant_fold(const ConstantFolder& folder) +{ float value; float3 vector; - if(vector1_in->link == NULL && vector2_in->link == NULL) { + if(folder.all_inputs_constant()) { svm_vector_math(&value, &vector, - (NodeVectorMath)type_enum[type], - vector1_in->value, - vector2_in->value); + type, + vector1, + vector2); - if(socket == output("Value")) { - optimized_value->x = value; - return true; + if(folder.output == output("Value")) { + folder.make_constant(value); } - else if(socket == output("Vector")) { - *optimized_value = vector; - return true; + else if(folder.output == output("Vector")) { + folder.make_constant(vector); } } - - return false; + else { + folder.fold_vector_math(type); + } } void VectorMathNode::compile(SVMCompiler& compiler) @@ -4304,7 +4797,7 @@ void VectorMathNode::compile(SVMCompiler& compiler) ShaderOutput *vector_out = output("Vector"); compiler.add_node(NODE_VECTOR_MATH, - type_enum[type], + type, compiler.stack_assign(vector1_in), compiler.stack_assign(vector2_in)); compiler.add_node(NODE_VECTOR_MATH, @@ -4314,90 +4807,87 @@ void VectorMathNode::compile(SVMCompiler& compiler) void VectorMathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); + compiler.parameter(this, "type"); compiler.add(this, "node_vector_math"); } /* VectorTransform */ -VectorTransformNode::VectorTransformNode() -: ShaderNode("vector_transform") +NODE_DEFINE(VectorTransformNode) { - type = ustring("Vector"); - convert_from = ustring("world"); - convert_to = ustring("object"); + NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER); - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("Vector", SHADER_SOCKET_VECTOR); -} + static NodeEnum type_enum; + type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); + type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT); + type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR); -static ShaderEnum vector_transform_type_init() -{ - ShaderEnum enm; + static NodeEnum space_enum; + space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); + space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); + SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); - enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT); - enm.insert("Normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_VECTOR(vector, "Vector"); - return enm; + return type; } -static ShaderEnum vector_transform_convert_space_init() +VectorTransformNode::VectorTransformNode() +: ShaderNode(node_type) { - ShaderEnum enm; - - enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); - enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - enm.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); - - return enm; } -ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init(); -ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init(); - void VectorTransformNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); ShaderOutput *vector_out = output("Vector"); compiler.add_node(NODE_VECTOR_TRANSFORM, - compiler.encode_uchar4(type_enum[type], - convert_space_enum[convert_from], - convert_space_enum[convert_to]), + compiler.encode_uchar4(type, convert_from, convert_to), compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out))); } void VectorTransformNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type); - compiler.parameter("convert_from", convert_from); - compiler.parameter("convert_to", convert_to); + compiler.parameter(this, "type"); + compiler.parameter(this, "convert_from"); + compiler.parameter(this, "convert_to"); compiler.add(this, "node_vector_transform"); } /* BumpNode */ -BumpNode::BumpNode() -: ShaderNode("bump") +NODE_DEFINE(BumpNode) { - invert = false; + NodeType* type = NodeType::add("bump", create, NodeType::SHADER); - special_type = SHADER_SPECIAL_TYPE_BUMP; + SOCKET_BOOLEAN(invert, "Invert", false); /* this input is used by the user, but after graph transform it is no longer * used and moved to sampler center/x/y instead */ - add_input("Height", SHADER_SOCKET_FLOAT); + SOCKET_IN_FLOAT(height, "Height", 1.0f); + + SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f); + SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f); + SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(distance, "Distance", 0.1f); + + SOCKET_OUT_NORMAL(normal, "Normal"); - add_input("SampleCenter", SHADER_SOCKET_FLOAT); - add_input("SampleX", SHADER_SOCKET_FLOAT); - add_input("SampleY", SHADER_SOCKET_FLOAT); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f); + return type; +} - add_output("Normal", SHADER_SOCKET_NORMAL); +BumpNode::BumpNode() +: ShaderNode(node_type) +{ + special_type = SHADER_SPECIAL_TYPE_BUMP; } void BumpNode::compile(SVMCompiler& compiler) @@ -4426,13 +4916,11 @@ void BumpNode::compile(SVMCompiler& compiler) void BumpNode::compile(OSLCompiler& compiler) { - compiler.parameter("invert", invert); + compiler.parameter(this, "invert"); compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, - ShaderOutput * /*socket*/, - float3 * /*optimized_value*/) +void BumpNode::constant_fold(const ConstantFolder& folder) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4440,46 +4928,60 @@ bool BumpNode::constant_fold(ShaderGraph *graph, if(height_in->link == NULL) { if(normal_in->link == NULL) { GeometryNode *geom = new GeometryNode(); - graph->add(geom); - graph->relink(this, outputs[0], geom->output("Normal")); + folder.graph->add(geom); + folder.bypass(geom->output("Normal")); } else { - graph->relink(this, outputs[0], normal_in->link); + folder.bypass(normal_in->link); } - return true; } /* TODO(sergey): Ignore bump with zero strength. */ - - return false; } -/* RGBCurvesNode */ -RGBCurvesNode::RGBCurvesNode() -: ShaderNode("rgb_curves") +/* Curve node */ + +CurvesNode::CurvesNode(const NodeType *node_type) +: ShaderNode(node_type) +{ +} + +void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in) { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Color", SHADER_SOCKET_COLOR); - add_output("Color", SHADER_SOCKET_COLOR); + ShaderInput *fac_in = input("Fac"); - min_x = 0.0f; - max_x = 1.0f; + /* remove no-op node */ + if(!fac_in->link && fac == 0.0f) { + folder.bypass(value_in->link); + } + /* evaluate fully constant node */ + else if(folder.all_inputs_constant()) { + if (curves.size() == 0) + return; + + float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x); + float3 result; + + result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x; + result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y; + result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z; + + folder.make_constant(interp(value, result, fac)); + } } -void RGBCurvesNode::compile(SVMCompiler& compiler) +void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) { if(curves.size() == 0) return; ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_RGB_CURVES, + compiler.add_node(type, compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(color_in), - compiler.stack_assign(color_out)), + compiler.stack_assign(value_in), + compiler.stack_assign(value_out)), __float_as_int(min_x), __float_as_int(max_x)); @@ -4488,72 +4990,149 @@ void RGBCurvesNode::compile(SVMCompiler& compiler) compiler.add_node(float3_to_float4(curves[i])); } -void RGBCurvesNode::compile(OSLCompiler& compiler) +void CurvesNode::compile(OSLCompiler& compiler, const char* name) { if(curves.size() == 0) return; compiler.parameter_color_array("ramp", curves); - compiler.parameter("min_x", min_x); - compiler.parameter("max_x", max_x); - compiler.add(this, "node_rgb_curves"); + compiler.parameter(this, "min_x"); + compiler.parameter(this, "max_x"); + compiler.add(this, name); } -/* VectorCurvesNode */ +void CurvesNode::compile(SVMCompiler& /*compiler*/) +{ + assert(0); +} -VectorCurvesNode::VectorCurvesNode() -: ShaderNode("vector_curves") +void CurvesNode::compile(OSLCompiler& /*compiler*/) +{ + assert(0); +} + +/* RGBCurvesNode */ + +NODE_DEFINE(RGBCurvesNode) { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_input("Vector", SHADER_SOCKET_VECTOR); - add_output("Vector", SHADER_SOCKET_VECTOR); + NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER); + + SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); - min_x = 0.0f; - max_x = 1.0f; + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(value, "Color"); + + return type; } -void VectorCurvesNode::compile(SVMCompiler& compiler) +RGBCurvesNode::RGBCurvesNode() +: CurvesNode(node_type) { - if(curves.size() == 0) - return; +} - ShaderInput *fac_in = input("Fac"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *vector_out = output("Vector"); +void RGBCurvesNode::constant_fold(const ConstantFolder& folder) +{ + CurvesNode::constant_fold(folder, input("Color")); +} - compiler.add_node(NODE_VECTOR_CURVES, - compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(vector_in), - compiler.stack_assign(vector_out)), - __float_as_int(min_x), - __float_as_int(max_x)); +void RGBCurvesNode::compile(SVMCompiler& compiler) +{ + CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); +} - compiler.add_node(curves.size()); - for(int i = 0; i < curves.size(); i++) - compiler.add_node(float3_to_float4(curves[i])); +void RGBCurvesNode::compile(OSLCompiler& compiler) +{ + CurvesNode::compile(compiler, "node_rgb_curves"); } -void VectorCurvesNode::compile(OSLCompiler& compiler) +/* VectorCurvesNode */ + +NODE_DEFINE(VectorCurvesNode) { - if(curves.size() == 0) - return; + NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER); - compiler.parameter_color_array("ramp", curves); - compiler.parameter("min_x", min_x); - compiler.parameter("max_x", max_x); - compiler.add(this, "node_vector_curves"); + SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_VECTOR(value, "Vector"); + + return type; +} + +VectorCurvesNode::VectorCurvesNode() +: CurvesNode(node_type) +{ +} + +void VectorCurvesNode::constant_fold(const ConstantFolder& folder) +{ + CurvesNode::constant_fold(folder, input("Vector")); +} + +void VectorCurvesNode::compile(SVMCompiler& compiler) +{ + CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); +} + +void VectorCurvesNode::compile(OSLCompiler& compiler) +{ + CurvesNode::compile(compiler, "node_vector_curves"); } /* RGBRampNode */ +NODE_DEFINE(RGBRampNode) +{ + NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER); + + SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>()); + SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>()); + SOCKET_BOOLEAN(interpolate, "Interpolate", true); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} + RGBRampNode::RGBRampNode() -: ShaderNode("rgb_ramp") +: ShaderNode(node_type) +{ +} + +void RGBRampNode::constant_fold(const ConstantFolder& folder) { - add_input("Fac", SHADER_SOCKET_FLOAT); - add_output("Color", SHADER_SOCKET_COLOR); - add_output("Alpha", SHADER_SOCKET_FLOAT); + if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) + return; + + if(folder.all_inputs_constant()) { + float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1); - interpolate = true; + /* clamp int as well in case of NaN */ + int i = clamp((int)f, 0, ramp.size()-1); + float t = f - (float)i; + + bool use_lerp = interpolate && t > 0.0f; + + if(folder.output == output("Color")) { + float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size()); + folder.make_constant(color); + } + else if(folder.output == output("Alpha")) { + float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size()); + folder.make_constant(alpha); + } + } } void RGBRampNode::compile(SVMCompiler& compiler) @@ -4584,18 +5163,26 @@ void RGBRampNode::compile(OSLCompiler& compiler) compiler.parameter_color_array("ramp_color", ramp); compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size()); - compiler.parameter("ramp_interpolate", interpolate); + compiler.parameter(this, "interpolate"); compiler.add(this, "node_rgb_ramp"); } /* Set Normal Node */ +NODE_DEFINE(SetNormalNode) +{ + NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER); + + SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_NORMAL(normal, "Normal"); + + return type; +} + SetNormalNode::SetNormalNode() -: ShaderNode("set_normal") +: ShaderNode(node_type) { - add_input("Direction", SHADER_SOCKET_VECTOR); - add_output("Normal", SHADER_SOCKET_NORMAL); } void SetNormalNode::compile(SVMCompiler& compiler) @@ -4613,20 +5200,73 @@ void SetNormalNode::compile(OSLCompiler& compiler) compiler.add(this, "node_set_normal"); } -/* OSLScriptNode */ +/* OSLNode */ -OSLScriptNode::OSLScriptNode() -: ShaderNode("osl_script") +OSLNode::OSLNode() +: ShaderNode(new NodeType(NodeType::SHADER)) { special_type = SHADER_SPECIAL_TYPE_SCRIPT; } -void OSLScriptNode::compile(SVMCompiler& /*compiler*/) +OSLNode::~OSLNode() +{ + delete type; +} + +ShaderNode *OSLNode::clone() const +{ + return OSLNode::create(this->inputs.size(), this); +} + +OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from) +{ + /* allocate space for the node itself and parameters, aligned to 16 bytes + * assuming that's the most parameter types need */ + size_t node_size = align_up(sizeof(OSLNode), 16); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + + char *node_memory = (char*) operator new(node_size + inputs_size); + memset(node_memory, 0, node_size + inputs_size); + + if (!from) { + return new(node_memory) OSLNode(); + } + else { + /* copy input default values and node type for cloning */ + memcpy(node_memory + node_size, (char*)from + node_size, inputs_size); + + OSLNode *node = new(node_memory) OSLNode(*from); + node->type = new NodeType(*(from->type)); + return node; + } +} + +char* OSLNode::input_default_value() +{ + /* pointer to default value storage, which is the same as our actual value */ + size_t num_inputs = type->inputs.size(); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size; +} + +void OSLNode::add_input(ustring name, SocketType::Type socket_type) +{ + char *memory = input_default_value(); + size_t offset = memory - (char*)this; + const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE); +} + +void OSLNode::add_output(ustring name, SocketType::Type socket_type) +{ + const_cast<NodeType*>(type)->register_output(name, name, socket_type); +} + +void OSLNode::compile(SVMCompiler&) { /* doesn't work for SVM, obviously ... */ } -void OSLScriptNode::compile(OSLCompiler& compiler) +void OSLNode::compile(OSLCompiler& compiler) { if(!filepath.empty()) compiler.add(this, filepath.c_str(), true); @@ -4636,37 +5276,37 @@ void OSLScriptNode::compile(OSLCompiler& compiler) /* Normal Map */ -static ShaderEnum normal_map_space_init() +NODE_DEFINE(NormalMapNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER); - enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT); - enm.insert("Object", NODE_NORMAL_MAP_OBJECT); - enm.insert("World", NODE_NORMAL_MAP_WORLD); - enm.insert("Blender Object", NODE_NORMAL_MAP_BLENDER_OBJECT); - enm.insert("Blender World", NODE_NORMAL_MAP_BLENDER_WORLD); + static NodeEnum space_enum; + space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); + space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); + space_enum.insert("world", NODE_NORMAL_MAP_WORLD); + space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT); + space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL); - return enm; -} + SOCKET_STRING(attribute, "Attribute", ustring("")); -ShaderEnum NormalMapNode::space_enum = normal_map_space_init(); + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f)); -NormalMapNode::NormalMapNode() -: ShaderNode("normal_map") -{ - space = ustring("Tangent"); - attribute = ustring(""); + SOCKET_OUT_NORMAL(normal, "Normal"); - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); - add_input("Color", SHADER_SOCKET_COLOR); + return type; +} - add_output("Normal", SHADER_SOCKET_NORMAL); +NormalMapNode::NormalMapNode() +: ShaderNode(node_type) +{ } void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface && space == ustring("Tangent")) { + if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { attributes->add(ATTR_STD_UV_TANGENT); attributes->add(ATTR_STD_UV_TANGENT_SIGN); @@ -4689,7 +5329,7 @@ void NormalMapNode::compile(SVMCompiler& compiler) ShaderOutput *normal_out = output("Normal"); int attr = 0, attr_sign = 0; - if(space == ustring("Tangent")) { + if(space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { attr = compiler.attribute(ATTR_STD_UV_TANGENT); attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); @@ -4705,13 +5345,13 @@ void NormalMapNode::compile(SVMCompiler& compiler) compiler.stack_assign(color_in), compiler.stack_assign(strength_in), compiler.stack_assign(normal_out), - space_enum[space]), + space), attr, attr_sign); } void NormalMapNode::compile(OSLCompiler& compiler) { - if(space == ustring("Tangent")) { + if(space == NODE_NORMAL_MAP_TANGENT) { if(attribute == ustring("")) { compiler.parameter("attr_name", ustring("geom:tangent")); compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); @@ -4722,52 +5362,44 @@ void NormalMapNode::compile(OSLCompiler& compiler) } } - compiler.parameter("space", space); - + compiler.parameter(this, "space"); compiler.add(this, "node_normal_map"); } /* Tangent */ -static ShaderEnum tangent_direction_type_init() +NODE_DEFINE(TangentNode) { - ShaderEnum enm; + NodeType* type = NodeType::add("tangent", create, NodeType::SHADER); - enm.insert("Radial", NODE_TANGENT_RADIAL); - enm.insert("UV Map", NODE_TANGENT_UVMAP); + static NodeEnum direction_type_enum; + direction_type_enum.insert("radial", NODE_TANGENT_RADIAL); + direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP); + SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL); - return enm; -} + static NodeEnum axis_enum; + axis_enum.insert("x", NODE_TANGENT_AXIS_X); + axis_enum.insert("y", NODE_TANGENT_AXIS_Y); + axis_enum.insert("z", NODE_TANGENT_AXIS_Z); + SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X); -static ShaderEnum tangent_axis_init() -{ - ShaderEnum enm; + SOCKET_STRING(attribute, "Attribute", ustring("")); - enm.insert("X", NODE_TANGENT_AXIS_X); - enm.insert("Y", NODE_TANGENT_AXIS_Y); - enm.insert("Z", NODE_TANGENT_AXIS_Z); + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_OUT_NORMAL(tangent, "Tangent"); - return enm; + return type; } -ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init(); -ShaderEnum TangentNode::axis_enum = tangent_axis_init(); - TangentNode::TangentNode() -: ShaderNode("tangent") +: ShaderNode(node_type) { - direction_type = ustring("Radial"); - axis = ustring("X"); - attribute = ustring(""); - - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); - add_output("Tangent", SHADER_SOCKET_NORMAL); } void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes) { if(shader->has_surface) { - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) attributes->add(ATTR_STD_UV_TANGENT); else @@ -4785,7 +5417,7 @@ void TangentNode::compile(SVMCompiler& compiler) ShaderOutput *tangent_out = output("Tangent"); int attr; - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) attr = compiler.attribute(ATTR_STD_UV_TANGENT); else @@ -4797,21 +5429,21 @@ void TangentNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_TANGENT, compiler.encode_uchar4( compiler.stack_assign(tangent_out), - direction_type_enum[direction_type], - axis_enum[axis]), attr); + direction_type, + axis), attr); } void TangentNode::compile(OSLCompiler& compiler) { - if(direction_type == ustring("UV Map")) { + if(direction_type == NODE_TANGENT_UVMAP) { if(attribute == ustring("")) compiler.parameter("attr_name", ustring("geom:tangent")); else compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); } - compiler.parameter("direction_type", direction_type); - compiler.parameter("axis", axis); + compiler.parameter(this, "direction_type"); + compiler.parameter(this, "axis"); compiler.add(this, "node_tangent"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index c0f0dc29099..6c2467d9bee 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -18,6 +18,7 @@ #define __NODES_H__ #include "graph.h" +#include "node.h" #include "util_string.h" @@ -35,6 +36,7 @@ public: Transform compute_transform(); bool skip(); void compile(SVMCompiler& compiler, int offset_in, int offset_out); + int compile(SVMCompiler& compiler, ShaderInput *vector_in); void compile(OSLCompiler &compiler); int compile_begin(SVMCompiler& compiler, ShaderInput *vector_in); @@ -49,48 +51,26 @@ public: enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 }; Type type; - static ShaderEnum type_enum; enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 }; Mapping x_mapping, y_mapping, z_mapping; - static ShaderEnum mapping_enum; enum Projection { FLAT, CUBE, TUBE, SPHERE }; Projection projection; - static ShaderEnum projection_enum; - - bool equals(const TextureMapping& other) { - return translation == other.translation && - rotation == other.rotation && - scale == other.scale && - use_minmax == other.use_minmax && - min == other.min && - max == other.max && - type == other.type && - x_mapping == other.x_mapping && - y_mapping == other.y_mapping && - z_mapping == other.z_mapping && - projection == other.projection; - } }; /* Nodes */ class TextureNode : public ShaderNode { public: - explicit TextureNode(const char *name_) : ShaderNode(name_) {} + explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) {} TextureMapping tex_mapping; - - virtual bool equals(const ShaderNode *other) { - return ShaderNode::equals(other) && - tex_mapping.equals(((const TextureNode*)other)->tex_mapping); - } }; /* Any node which uses image manager's slot should be a subclass of this one. */ class ImageSlotTextureNode : public TextureNode { public: - explicit ImageSlotTextureNode(const char *name_) : TextureNode(name_) { + explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) { special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT; } int slot; @@ -107,30 +87,22 @@ public: int is_float; bool is_linear; bool use_alpha; - string filename; + ustring filename; void *builtin_data; - ustring color_space; - ustring projection; + NodeImageColorSpace color_space; + NodeImageProjection projection; InterpolationType interpolation; ExtensionType extension; float projection_blend; bool animated; + float3 vector; - static ShaderEnum color_space_enum; - static ShaderEnum projection_enum; - - virtual bool equals(const ShaderNode *other) { - const ImageTextureNode *image_node = (const ImageTextureNode*)other; + virtual bool equals(const ShaderNode& other) + { + const ImageTextureNode& image_node = (const ImageTextureNode&)other; return ImageSlotTextureNode::equals(other) && - use_alpha == image_node->use_alpha && - filename == image_node->filename && - builtin_data == image_node->builtin_data && - color_space == image_node->color_space && - projection == image_node->projection && - interpolation == image_node->interpolation && - extension == image_node->extension && - projection_blend == image_node->projection_blend && - animated == image_node->animated; + builtin_data == image_node.builtin_data && + animated == image_node.animated; } }; @@ -146,26 +118,20 @@ public: int is_float; bool is_linear; bool use_alpha; - string filename; + ustring filename; void *builtin_data; - ustring color_space; - ustring projection; + NodeImageColorSpace color_space; + NodeEnvironmentProjection projection; InterpolationType interpolation; bool animated; + float3 vector; - static ShaderEnum color_space_enum; - static ShaderEnum projection_enum; - - virtual bool equals(const ShaderNode *other) { - const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other; + virtual bool equals(const ShaderNode& other) + { + const EnvironmentTextureNode& env_node = (const EnvironmentTextureNode&)other; return ImageSlotTextureNode::equals(other) && - use_alpha == env_node->use_alpha && - filename == env_node->filename && - builtin_data == env_node->builtin_data && - color_space == env_node->color_space && - projection == env_node->projection && - interpolation == env_node->interpolation && - animated == env_node->animated; + builtin_data == env_node.builtin_data && + animated == env_node.animated; } }; @@ -175,29 +141,24 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } + NodeSkyType type; float3 sun_direction; float turbidity; float ground_albedo; - - ustring type; - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const SkyTextureNode *sky_node = (const SkyTextureNode*)other; - return TextureNode::equals(other) && - sun_direction == sky_node->sun_direction && - turbidity == sky_node->turbidity && - ground_albedo == sky_node->ground_albedo && - type == sky_node->type; - } + float3 vector; }; class OutputNode : public ShaderNode { public: SHADER_NODE_CLASS(OutputNode) + void *surface; + void *volume; + float displacement; + float3 normal; + /* Don't allow output node de-duplication. */ - virtual bool equals(const ShaderNode * /*other*/) { return false; } + virtual bool equals(const ShaderNode& /*other*/) { return false; } }; class GradientTextureNode : public TextureNode { @@ -206,19 +167,16 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const GradientTextureNode *gradient_node = (const GradientTextureNode*)other; - return TextureNode::equals(other) && - type == gradient_node->type; - } + NodeGradientType type; + float3 vector; }; class NoiseTextureNode : public TextureNode { public: SHADER_NODE_CLASS(NoiseTextureNode) + + float scale, detail, distortion; + float3 vector; }; class VoronoiTextureNode : public TextureNode { @@ -227,15 +185,9 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring coloring; - - static ShaderEnum coloring_enum; - - virtual bool equals(const ShaderNode *other) { - const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other; - return TextureNode::equals(other) && - coloring == voronoi_node->coloring; - } + NodeVoronoiColoring coloring; + float scale; + float3 vector; }; class MusgraveTextureNode : public TextureNode { @@ -244,15 +196,9 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other; - return TextureNode::equals(other) && - type == musgrave_node->type; - } + NodeMusgraveType type; + float scale, detail, dimension, lacunarity, offset, gain; + float3 vector; }; class WaveTextureNode : public TextureNode { @@ -261,17 +207,11 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } - ustring type; - ustring profile; - static ShaderEnum type_enum; - static ShaderEnum profile_enum; + NodeWaveType type; + NodeWaveProfile profile; - virtual bool equals(const ShaderNode *other) { - const WaveTextureNode *wave_node = (const WaveTextureNode*)other; - return TextureNode::equals(other) && - type == wave_node->type && - profile == wave_node->profile; - } + float scale, distortion, detail, detail_scale; + float3 vector; }; class MagicTextureNode : public TextureNode { @@ -281,18 +221,17 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } int depth; - - virtual bool equals(const ShaderNode *other) { - const MagicTextureNode *magic_node = (const MagicTextureNode*)other; - return TextureNode::equals(other) && - depth == magic_node->depth; - } + float3 vector; + float scale, distortion; }; class CheckerTextureNode : public TextureNode { public: SHADER_NODE_CLASS(CheckerTextureNode) + float3 vector, color1, color2; + float scale; + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; @@ -303,16 +242,11 @@ public: float offset, squash; int offset_frequency, squash_frequency; - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + float3 color1, color2, mortar; + float scale, mortar_size, bias, brick_width, row_height; + float3 vector; - virtual bool equals(const ShaderNode *other) { - const BrickTextureNode *brick_node = (const BrickTextureNode*)other; - return TextureNode::equals(other) && - offset == brick_node->offset && - squash == brick_node->squash && - offset_frequency == brick_node->offset_frequency && - squash_frequency == brick_node->squash_frequency; - } + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; class PointDensityTextureNode : public ShaderNode { @@ -326,25 +260,20 @@ public: bool has_spatial_varying() { return true; } bool has_object_dependency() { return true; } - ImageManager *image_manager; - int slot; - string filename; - ustring space; - void *builtin_data; + ustring filename; + NodeTexVoxelSpace space; InterpolationType interpolation; - Transform tfm; + float3 vector; - static ShaderEnum space_enum; + ImageManager *image_manager; + int slot; + void *builtin_data; - virtual bool equals(const ShaderNode *other) { - const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other; + virtual bool equals(const ShaderNode& other) { + const PointDensityTextureNode& point_dendity_node = (const PointDensityTextureNode&)other; return ShaderNode::equals(other) && - filename == point_dendity_node->filename && - space == point_dendity_node->space && - builtin_data == point_dendity_node->builtin_data && - interpolation == point_dendity_node->interpolation && - tfm == point_dendity_node->tfm; + builtin_data == point_dendity_node.builtin_data; } }; @@ -353,46 +282,60 @@ public: SHADER_NODE_CLASS(MappingNode) virtual int get_group() { return NODE_GROUP_LEVEL_2; } + float3 vector; TextureMapping tex_mapping; +}; - virtual bool equals(const ShaderNode *other) { - const MappingNode *mapping_node = (const MappingNode*)other; - return ShaderNode::equals(other) && - tex_mapping.equals(mapping_node->tex_mapping); - } +class RGBToBWNode : public ShaderNode { +public: + SHADER_NODE_CLASS(RGBToBWNode) + void constant_fold(const ConstantFolder& folder); + + float3 color; }; class ConvertNode : public ShaderNode { public: - ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false); + ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); SHADER_NODE_BASE_CLASS(ConvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); - ShaderSocketType from, to; + SocketType::Type from, to; - virtual bool equals(const ShaderNode *other) - { - const ConvertNode *convert_node = (const ConvertNode*)other; - return ShaderNode::equals(other) && - from == convert_node->from && - to == convert_node->to; - } + union { + float value_float; + int value_int; + float3 value_color; + float3 value_vector; + float3 value_point; + float3 value_normal; + }; + ustring value_string; + +private: + static const int MAX_TYPE = 12; + static bool register_types(); + static Node* create(const NodeType *type); + static const NodeType *node_types[MAX_TYPE][MAX_TYPE]; + static bool initialized; }; class BsdfNode : public ShaderNode { public: - explicit BsdfNode(bool scattering = false); + explicit BsdfNode(const NodeType *node_type); SHADER_NODE_BASE_CLASS(BsdfNode); bool has_spatial_varying() { return true; } void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL); virtual ClosureType get_closure_type() { return closure; } + float3 color; + float3 normal; + float surface_mix_weight; ClosureType closure; - bool scattering; - virtual bool equals(const ShaderNode * /*other*/) + virtual bool equals(const ShaderNode& /*other*/) { /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ return false; @@ -403,15 +346,19 @@ class AnisotropicBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(AnisotropicBsdfNode) - ustring distribution; - static ShaderEnum distribution_enum; + float3 tangent; + float roughness, anisotropy, rotation; + ClosureType distribution; + ClosureType get_closure_type() { return distribution; } void attributes(Shader *shader, AttributeRequestSet *attributes); }; class DiffuseBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(DiffuseBsdfNode) + + float roughness; }; /* Disney BRDF */ @@ -427,6 +374,12 @@ public: ShaderInput *sheen, ShaderInput *sheenTint, ShaderInput *clearcoat, ShaderInput *clearcoatGloss, ShaderInput *ior, ShaderInput *transparency, ShaderInput *refr_roughness); + float3 base_color; + float3 subsurface_color; + float metallic, subsurface, specular, roughness, specularTint, anisotropic, + sheen, sheenTint, clearcoat, clearcoatGloss, ior, transparency, refractionRoughness; + float3 normal, clearcoatNormal, tangent; + float surface_mix_weight; ClosureType closure; virtual bool equals(const ShaderNode * /*other*/) @@ -451,6 +404,8 @@ public: class VelvetBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(VelvetBsdfNode) + + float sigma; }; class GlossyBsdfNode : public BsdfNode { @@ -459,9 +414,10 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + ClosureType get_closure_type() { return distribution; } - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + float roughness; + ClosureType distribution, distribution_orig; }; class GlassBsdfNode : public BsdfNode { @@ -470,9 +426,10 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + ClosureType get_closure_type() { return distribution; } - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + float roughness, IOR; + ClosureType distribution, distribution_orig; }; class RefractionBsdfNode : public BsdfNode { @@ -481,17 +438,18 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + ClosureType get_closure_type() { return distribution; } - ustring distribution, distribution_orig; - static ShaderEnum distribution_enum; + float roughness, IOR; + ClosureType distribution, distribution_orig; }; class ToonBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(ToonBsdfNode) - ustring component; - static ShaderEnum component_enum; + float smooth, size; + ClosureType component; }; class SubsurfaceScatteringNode : public BsdfNode { @@ -499,24 +457,37 @@ public: SHADER_NODE_CLASS(SubsurfaceScatteringNode) bool has_surface_bssrdf() { return true; } bool has_bssrdf_bump(); + ClosureType get_closure_type() { return falloff; } - static ShaderEnum falloff_enum; + float scale; + float3 radius; + float sharpness; + float texture_blur; + ClosureType falloff; }; class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } + + float3 color; + float strength; + float surface_mix_weight; }; class BackgroundNode : public ShaderNode { public: SHADER_NODE_CLASS(BackgroundNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } + + float3 color; + float strength; + float surface_mix_weight; }; class HoldoutNode : public ShaderNode { @@ -524,6 +495,9 @@ public: SHADER_NODE_CLASS(HoldoutNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } virtual ClosureType get_closure_type() { return CLOSURE_HOLDOUT_ID; } + + float surface_mix_weight; + float volume_mix_weight; }; class AmbientOcclusionNode : public ShaderNode { @@ -533,11 +507,16 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; } + + float3 normal_osl; + float3 color; + float surface_mix_weight; }; class VolumeNode : public ShaderNode { public: - SHADER_NODE_CLASS(VolumeNode) + VolumeNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(VolumeNode) void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2); virtual int get_group() { return NODE_GROUP_LEVEL_1; } @@ -546,9 +525,12 @@ public: } virtual ClosureType get_closure_type() { return closure; } + float3 color; + float density; + float volume_mix_weight; ClosureType closure; - virtual bool equals(const ShaderNode * /*other*/) + virtual bool equals(const ShaderNode& /*other*/) { /* TODO(sergey): With some care Volume nodes can be de-duplicated. */ return false; @@ -563,15 +545,20 @@ public: class ScatterVolumeNode : public VolumeNode { public: SHADER_NODE_CLASS(ScatterVolumeNode) + + float anisotropy; }; class HairBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(HairBsdfNode) + ClosureType get_closure_type() { return component; } - ustring component; - static ShaderEnum component_enum; - + ClosureType component; + float offset; + float roughness_u; + float roughness_v; + float3 tangent; }; class GeometryNode : public ShaderNode { @@ -579,6 +566,8 @@ public: SHADER_NODE_CLASS(GeometryNode) void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + + float3 normal_osl; }; class TextureCoordinateNode : public ShaderNode { @@ -588,17 +577,10 @@ public: bool has_spatial_varying() { return true; } bool has_object_dependency() { return use_transform; } + float3 normal_osl; bool from_dupli; bool use_transform; Transform ob_tfm; - - virtual bool equals(const ShaderNode *other) { - const TextureCoordinateNode *texco_node = (const TextureCoordinateNode*)other; - return ShaderNode::equals(other) && - from_dupli == texco_node->from_dupli && - use_transform == texco_node->use_transform && - ob_tfm == texco_node->ob_tfm; - } }; class UVMapNode : public ShaderNode { @@ -610,13 +592,6 @@ public: ustring attribute; bool from_dupli; - - virtual bool equals(const ShaderNode *other) { - const UVMapNode *uv_map_node = (const UVMapNode*)other; - return ShaderNode::equals(other) && - attribute == uv_map_node->attribute && - from_dupli == uv_map_node->from_dupli; - } }; class LightPathNode : public ShaderNode { @@ -630,6 +605,9 @@ public: SHADER_NODE_CLASS(LightFalloffNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_2; } + + float strength; + float smooth; }; class ObjectInfoNode : public ShaderNode { @@ -661,136 +639,150 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); float value; - - virtual bool equals(const ShaderNode *other) { - const ValueNode *value_node = (const ValueNode*)other; - return ShaderNode::equals(other) && - value == value_node->value; - } }; class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); float3 value; - - virtual bool equals(const ShaderNode *other) { - const ColorNode *color_node = (const ColorNode*)other; - return ShaderNode::equals(other) && - value == color_node->value; - } }; class AddClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(AddClosureNode) + void constant_fold(const ConstantFolder& folder); }; class MixClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); + + float fac; }; class MixClosureWeightNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureWeightNode); + + float weight; + float fac; }; class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float fac; + float3 color; }; class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + NodeMix type; bool use_clamp; - - ustring type; - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const MixNode *mix_node = (const MixNode*)other; - return ShaderNode::equals(other) && - use_clamp == mix_node->use_clamp && - type == mix_node->type; - } + float3 color1; + float3 color2; + float fac; }; class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float r, g, b; }; class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float h, s, v; }; class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float x, y, z; }; class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 color; + float gamma; }; class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 color; + float bright; + float contrast; }; class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 color; }; class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 color; }; class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 vector; }; class HSVNode : public ShaderNode { public: SHADER_NODE_CLASS(HSVNode) + + float hue; + float saturation; + float value; + float fac; + float3 color; }; class AttributeNode : public ShaderNode { @@ -800,12 +792,6 @@ public: bool has_spatial_varying() { return true; } ustring attribute; - - virtual bool equals(const ShaderNode *other) { - const AttributeNode *color_node = (const AttributeNode*)other; - return ShaderNode::equals(other) && - attribute == color_node->attribute; - } }; class CameraNode : public ShaderNode { @@ -819,6 +805,9 @@ public: SHADER_NODE_CLASS(FresnelNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 normal; + float IOR; }; class LayerWeightNode : public ShaderNode { @@ -826,6 +815,9 @@ public: SHADER_NODE_CLASS(LayerWeightNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 normal; + float blend; }; class WireframeNode : public ShaderNode { @@ -834,42 +826,37 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } + float size; bool use_pixel_size; }; class WavelengthNode : public ShaderNode { public: SHADER_NODE_CLASS(WavelengthNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float wavelength; }; class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float temperature; }; class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); + float value1; + float value2; + NodeMath type; bool use_clamp; - - ustring type; - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const MathNode *math_node = (const MathNode*)other; - return ShaderNode::equals(other) && - use_clamp == math_node->use_clamp && - type == math_node->type; - } }; class NormalNode : public ShaderNode { @@ -878,30 +865,18 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } float3 direction; - - virtual bool equals(const ShaderNode *other) - { - const NormalNode *normal_node = (const NormalNode*)other; - return ShaderNode::equals(other) && - direction == normal_node->direction; - } + float3 normal; }; class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); - ustring type; - static ShaderEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const MathNode *math_node = (const MathNode*)other; - return ShaderNode::equals(other) && - type == math_node->type; - } + float3 vector1; + float3 vector2; + NodeVectorMath type; }; class VectorTransformNode : public ShaderNode { @@ -910,88 +885,97 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring type; - ustring convert_from; - ustring convert_to; - - static ShaderEnum type_enum; - static ShaderEnum convert_space_enum; - - virtual bool equals(const ShaderNode *other) { - const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other; - return ShaderNode::equals(other) && - type == vector_transform_node->type && - convert_from == vector_transform_node->convert_from && - convert_to == vector_transform_node->convert_to; - } + NodeVectorTransformType type; + NodeVectorTransformConvertSpace convert_from; + NodeVectorTransformConvertSpace convert_to; + float3 vector; }; class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value); + void constant_fold(const ConstantFolder& folder); bool has_spatial_varying() { return true; } virtual int get_feature() { return NODE_FEATURE_BUMP; } bool invert; - - virtual bool equals(const ShaderNode *other) { - const BumpNode *bump_node = (const BumpNode*)other; - return ShaderNode::equals(other) && - invert == bump_node->invert; - } + float height; + float sample_center; + float sample_x; + float sample_y; + float3 normal; + float strength; + float distance; }; -class RGBCurvesNode : public ShaderNode { +class CurvesNode : public ShaderNode { public: - SHADER_NODE_CLASS(RGBCurvesNode) + explicit CurvesNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(CurvesNode); virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } array<float3> curves; - float min_x, max_x; + float min_x, max_x, fac; + float3 value; + +protected: + void constant_fold(const ConstantFolder& folder, ShaderInput *value_in); + void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out); + void compile(OSLCompiler& compiler, const char *name); }; -class VectorCurvesNode : public ShaderNode { +class RGBCurvesNode : public CurvesNode { public: - SHADER_NODE_CLASS(VectorCurvesNode) - - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } + SHADER_NODE_CLASS(RGBCurvesNode) + void constant_fold(const ConstantFolder& folder); +}; - array<float3> curves; - float min_x, max_x; +class VectorCurvesNode : public CurvesNode { +public: + SHADER_NODE_CLASS(VectorCurvesNode) + void constant_fold(const ConstantFolder& folder); }; class RGBRampNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBRampNode) + void constant_fold(const ConstantFolder& folder); + virtual int get_group() { return NODE_GROUP_LEVEL_1; } + array<float3> ramp; array<float> ramp_alpha; + float fac; bool interpolate; - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } }; class SetNormalNode : public ShaderNode { public: SHADER_NODE_CLASS(SetNormalNode) + float3 direction; }; -class OSLScriptNode : public ShaderNode { +class OSLNode : public ShaderNode { public: - SHADER_NODE_CLASS(OSLScriptNode) + static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL); + ~OSLNode(); + + ShaderNode *clone() const; + + char* input_default_value(); + void add_input(ustring name, SocketType::Type type); + void add_output(ustring name, SocketType::Type type); + + SHADER_NODE_NO_CLONE_CLASS(OSLNode) /* ideally we could beter detect this, but we can't query this now */ bool has_spatial_varying() { return true; } + virtual bool equals(const ShaderNode& /*other*/) { return false; } string filepath; string bytecode_hash; - - virtual bool equals(const ShaderNode * /*other*/) { return false; } }; class NormalMapNode : public ShaderNode { @@ -1001,18 +985,11 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring space; - static ShaderEnum space_enum; - + NodeNormalMapSpace space; ustring attribute; - - virtual bool equals(const ShaderNode *other) - { - const NormalMapNode *normal_map_node = (const NormalMapNode*)other; - return ShaderNode::equals(other) && - space == normal_map_node->space && - attribute == normal_map_node->attribute; - } + float strength; + float3 color; + float3 normal_osl; }; class TangentNode : public ShaderNode { @@ -1022,22 +999,10 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } - ustring direction_type; - static ShaderEnum direction_type_enum; - - ustring axis; - static ShaderEnum axis_enum; - + NodeTangentDirectionType direction_type; + NodeTangentAxis axis; ustring attribute; - - virtual bool equals(const ShaderNode *other) - { - const TangentNode *tangent_node = (const TangentNode*)other; - return ShaderNode::equals(other) && - direction_type == tangent_node->direction_type && - axis == tangent_node->axis && - attribute == tangent_node->attribute; - } + float3 normal_osl; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index e2fe0bd72a1..662d87e8b6b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -33,14 +33,25 @@ CCL_NAMESPACE_BEGIN /* Object */ +NODE_DEFINE(Object) +{ + NodeType* type = NodeType::add("object", create); + + SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_UINT(visibility, "Visibility", ~0); + SOCKET_UINT(random_id, "Random ID", 0); + SOCKET_INT(pass_id, "Pass ID", 0); + SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); + SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); + + return type; +} + Object::Object() +: Node(node_type) { - name = ""; - mesh = NULL; - tfm = transform_identity(); - visibility = ~0; - random_id = 0; - pass_id = 0; particle_system = NULL; particle_index = 0; bounds = BoundBox::empty; @@ -48,9 +59,6 @@ Object::Object() motion.mid = transform_identity(); motion.post = transform_identity(); use_motion = false; - use_holdout = false; - dupli_generated = make_float3(0.0f, 0.0f, 0.0f); - dupli_uv = make_float2(0.0f, 0.0f); } Object::~Object() @@ -137,12 +145,12 @@ void Object::apply_transform(bool apply_to_motion) /* apply transform to curve keys */ for(size_t i = 0; i < mesh->curve_keys.size(); i++) { - float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i])); - float radius = mesh->curve_keys[i].w * scalar; + float3 co = transform_point(&tfm, mesh->curve_keys[i]); + float radius = mesh->curve_radius[i] * scalar; /* scale for curve radius is only correct for uniform scale */ - mesh->curve_keys[i] = float3_to_float4(co); - mesh->curve_keys[i].w = radius; + mesh->curve_keys[i] = co; + mesh->curve_radius[i] = radius; } if(apply_to_motion) { @@ -176,7 +184,7 @@ void Object::apply_transform(bool apply_to_motion) } /* tfm is not reset to identity, all code that uses it needs to check the - transform_applied boolean */ + * transform_applied boolean */ } void Object::tag_update(Scene *scene) @@ -217,6 +225,16 @@ vector<float> Object::motion_times() return times; } +bool Object::is_traceable() +{ + /* Mesh itself can be empty,can skip all such objects. */ + if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { + return false; + } + /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ + return true; +} + /* Object Manager */ ObjectManager::ObjectManager() @@ -269,7 +287,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s state->surface_area_lock.unlock(); if(it == state->surface_area_map.end()) { - foreach(Mesh::Triangle& t, mesh->triangles) { + size_t num_triangles = mesh->num_triangles(); + for(size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); float3 p1 = mesh->verts[t.v[0]]; float3 p2 = mesh->verts[t.v[1]]; float3 p3 = mesh->verts[t.v[2]]; @@ -288,7 +308,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s surface_area *= uniform_scale; } else { - foreach(Mesh::Triangle& t, mesh->triangles) { + size_t num_triangles = mesh->num_triangles(); + for(size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]); float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]); float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]); @@ -360,7 +382,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s state->object_flag[object_index] = flag; /* Have curves. */ - if(mesh->curves.size()) { + if(mesh->num_curves()) { state->have_curves = true; } } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index c2a79ca8dc4..7ab73f3c91a 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -17,6 +17,7 @@ #ifndef __OBJECT_H__ #define __OBJECT_H__ +#include "node.h" #include "scene.h" #include "util_boundbox.h" @@ -37,12 +38,13 @@ struct Transform; /* Object */ -class Object { +class Object : public Node { public: + NODE_DECLARE; + Mesh *mesh; Transform tfm; BoundBox bounds; - ustring name; uint random_id; int pass_id; vector<ParamValue> attributes; @@ -66,6 +68,11 @@ public: void apply_transform(bool apply_to_motion); vector<float> motion_times(); + + /* Check whether object is traceable and it worth adding it to + * kernel scene. + */ + bool is_traceable(); }; /* Object Manager */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 3d14965b4ca..676afad997e 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -394,16 +394,145 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str { ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str()); - /* this is a bit weak, but works */ OSLShaderInfo info; + + if(!info.query.open_bytecode(bytecode)) { + fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str()); + } + + /* this is a bit weak, but works */ info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos); info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos); info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos); + loaded_shaders[hash] = info; return loaded_shaders.find(hash)->first.c_str(); } +OSLNode *OSLShaderManager::osl_node(const std::string& filepath, + const std::string& bytecode_hash, + const std::string& bytecode) +{ + /* create query */ + const char *hash; + + if(!filepath.empty()) { + hash = shader_load_filepath(filepath); + } + else { + hash = shader_test_loaded(bytecode_hash); + if(!hash) + hash = shader_load_bytecode(bytecode_hash, bytecode); + } + + if(!hash) { + return NULL; + } + + OSLShaderInfo *info = shader_loaded_info(hash); + + /* count number of inputs */ + size_t num_inputs = 0; + + for(int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if(param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + if(!param->isoutput) + num_inputs++; + } + + /* create node */ + OSLNode *node = OSLNode::create(num_inputs); + + /* add new sockets from parameters */ + set<void*> used_sockets; + + for(int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if(param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + SocketType::Type socket_type; + + if(param->isclosure) { + socket_type = SocketType::CLOSURE; + } + else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) { + if(param->type.vecsemantics == TypeDesc::COLOR) + socket_type = SocketType::COLOR; + else if(param->type.vecsemantics == TypeDesc::POINT) + socket_type = SocketType::POINT; + else if(param->type.vecsemantics == TypeDesc::VECTOR) + socket_type = SocketType::VECTOR; + else if(param->type.vecsemantics == TypeDesc::NORMAL) + socket_type = SocketType::NORMAL; + else + continue; + + if(!param->isoutput && param->validdefault) { + float3 *default_value = (float3*)node->input_default_value(); + default_value->x = param->fdefault[0]; + default_value->y = param->fdefault[1]; + default_value->z = param->fdefault[2]; + } + } + else if(param->type.aggregate == TypeDesc::SCALAR) { + if(param->type.basetype == TypeDesc::INT) { + socket_type = SocketType::INT; + + if(!param->isoutput && param->validdefault) { + *(int*)node->input_default_value() = param->idefault[0]; + } + } + else if(param->type.basetype == TypeDesc::FLOAT) { + socket_type = SocketType::FLOAT; + + if(!param->isoutput && param->validdefault) { + *(float*)node->input_default_value() = param->fdefault[0]; + } + } + else if(param->type.basetype == TypeDesc::STRING) { + socket_type = SocketType::STRING; + + if(!param->isoutput && param->validdefault) { + *(ustring*)node->input_default_value() = param->sdefault[0]; + } + } + else + continue; + } + else + continue; + + if(param->isoutput) { + node->add_output(param->name, socket_type); + } + else { + node->add_input(param->name, socket_type); + } + } + + /* set bytcode hash or filepath */ + if(!bytecode_hash.empty()) { + node->bytecode_hash = bytecode_hash; + } + else { + node->filepath = filepath; + } + + /* Generate inputs and outputs */ + node->create_inputs_outputs(node->type); + + return node; +} + /* Graph Compiler */ OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_) @@ -427,7 +556,7 @@ string OSLCompiler::id(ShaderNode *node) string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) { - string sname(input->name); + string sname(input->name().string()); size_t i; /* strip whitespace */ @@ -436,7 +565,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) /* if output exists with the same name, add "In" suffix */ foreach(ShaderOutput *output, node->outputs) { - if(strcmp(input->name, output->name)==0) { + if(input->name() == output->name()) { sname += "In"; break; } @@ -447,7 +576,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output) { - string sname(output->name); + string sname(output->name().string()); size_t i; /* strip whitespace */ @@ -456,7 +585,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output) /* if input exists with the same name, add "Out" suffix */ foreach(ShaderInput *input, node->inputs) { - if(strcmp(input->name, output->name)==0) { + if(input->name() == output->name()) { sname += "Out"; break; } @@ -470,21 +599,21 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input) /* exception for output node, only one input is actually used * depending on the current shader type */ - if(!(input->usage & ShaderInput::USE_OSL)) + if(input->flags() & SocketType::SVM_INTERNAL) return true; if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) { - if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE) + if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) return true; - if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME) + if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) return true; - if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT) + if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) return true; - if(strcmp(input->name, "Normal") == 0) + if(input->name() == "Normal") return true; } else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) { - if(strcmp(input->name, "Height") == 0) + if(input->name() == "Height") return true; } else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP) @@ -512,34 +641,36 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) if(node_skip_input(node, input)) continue; /* already has default value assigned */ - else if(input->default_value != ShaderInput::NONE) + else if(input->flags() & SocketType::DEFAULT_LINK_MASK) continue; string param_name = compatible_name(node, input); - switch(input->type) { - case SHADER_SOCKET_COLOR: - parameter_color(param_name.c_str(), input->value); + const SocketType& socket = input->socket_type; + switch(input->type()) { + case SocketType::COLOR: + parameter_color(param_name.c_str(), node->get_float3(socket)); break; - case SHADER_SOCKET_POINT: - parameter_point(param_name.c_str(), input->value); + case SocketType::POINT: + parameter_point(param_name.c_str(), node->get_float3(socket)); break; - case SHADER_SOCKET_VECTOR: - parameter_vector(param_name.c_str(), input->value); + case SocketType::VECTOR: + parameter_vector(param_name.c_str(), node->get_float3(socket)); break; - case SHADER_SOCKET_NORMAL: - parameter_normal(param_name.c_str(), input->value); + case SocketType::NORMAL: + parameter_normal(param_name.c_str(), node->get_float3(socket)); break; - case SHADER_SOCKET_FLOAT: - parameter(param_name.c_str(), input->value.x); + case SocketType::FLOAT: + parameter(param_name.c_str(), node->get_float(socket)); break; - case SHADER_SOCKET_INT: - parameter(param_name.c_str(), (int)input->value.x); + case SocketType::INT: + parameter(param_name.c_str(), node->get_int(socket)); break; - case SHADER_SOCKET_STRING: - parameter(param_name.c_str(), input->value_string); + case SocketType::STRING: + parameter(param_name.c_str(), node->get_string(socket)); break; - case SHADER_SOCKET_CLOSURE: - case SHADER_SOCKET_UNDEFINED: + case SocketType::CLOSURE: + case SocketType::UNDEFINED: + default: break; } } @@ -605,6 +736,169 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) } } +static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength) +{ + return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype, + (TypeDesc::AGGREGATE)typedesc.aggregate, + (TypeDesc::VECSEMANTICS)typedesc.vecsemantics, + arraylength); +} + +void OSLCompiler::parameter(ShaderNode* node, const char *name) +{ + OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; + ustring uname = ustring(name); + const SocketType& socket = *(node->type->find_input(uname)); + + switch(socket.type) + { + case SocketType::BOOLEAN: + { + int value = node->get_bool(socket); + ss->Parameter(name, TypeDesc::TypeInt, &value); + break; + } + case SocketType::FLOAT: + { + float value = node->get_float(socket); + ss->Parameter(uname, TypeDesc::TypeFloat, &value); + break; + } + case SocketType::INT: + { + int value = node->get_int(socket); + ss->Parameter(uname, TypeDesc::TypeInt, &value); + break; + } + case SocketType::COLOR: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeColor, &value); + break; + } + case SocketType::VECTOR: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeVector, &value); + break; + } + case SocketType::POINT: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypePoint, &value); + break; + } + case SocketType::NORMAL: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeNormal, &value); + break; + } + case SocketType::POINT2: + { + float2 value = node->get_float2(socket); + ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value); + break; + } + case SocketType::STRING: + { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::ENUM: + { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::TRANSFORM: + { + Transform value = node->get_transform(socket); + ss->Parameter(uname, TypeDesc::TypeMatrix, &value); + break; + } + case SocketType::BOOLEAN_ARRAY: + { + // OSL does not support booleans, so convert to int + const array<bool>& value = node->get_bool_array(socket); + array<int> intvalue(value.size()); + for (size_t i = 0; i < value.size(); i++) + intvalue[i] = value[i]; + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data()); + break; + } + case SocketType::FLOAT_ARRAY: + { + const array<float>& value = node->get_float_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data()); + break; + } + case SocketType::INT_ARRAY: + { + const array<int>& value = node->get_int_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data()); + break; + } + case SocketType::COLOR_ARRAY: + case SocketType::VECTOR_ARRAY: + case SocketType::POINT_ARRAY: + case SocketType::NORMAL_ARRAY: + { + TypeDesc typedesc; + + switch(socket.type) + { + case SocketType::COLOR_ARRAY: typedesc = TypeDesc::TypeColor; break; + case SocketType::VECTOR_ARRAY: typedesc = TypeDesc::TypeVector; break; + case SocketType::POINT_ARRAY: typedesc = TypeDesc::TypePoint; break; + case SocketType::NORMAL_ARRAY: typedesc = TypeDesc::TypeNormal; break; + default: assert(0); break; + } + + // convert to tightly packed array since float3 has padding + const array<float3>& value = node->get_float3_array(socket); + array<float> fvalue(value.size() * 3); + for (size_t i = 0, j = 0; i < value.size(); i++) + { + fvalue[j++] = value[i].x; + fvalue[j++] = value[i].y; + fvalue[j++] = value[i].z; + } + + ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data()); + break; + } + case SocketType::POINT2_ARRAY: + { + const array<float2>& value = node->get_float2_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), value.data()); + break; + } + case SocketType::STRING_ARRAY: + { + const array<ustring>& value = node->get_string_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data()); + break; + } + case SocketType::TRANSFORM_ARRAY: + { + const array<Transform>& value = node->get_transform_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data()); + break; + } + case SocketType::CLOSURE: + case SocketType::NODE: + case SocketType::NODE_ARRAY: + case SocketType::UNDEFINED: + case SocketType::UINT: + { + assert(0); + break; + } + } +} + void OSLCompiler::parameter(const char *name, float f) { OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; @@ -868,6 +1162,10 @@ void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfil { } +void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/) +{ +} + void OSLCompiler::parameter(const char * /*name*/, float /*f*/) { } diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 110897ff300..b131b672b8c 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -22,6 +22,7 @@ #include "util_thread.h" #include "graph.h" +#include "nodes.h" #include "shader.h" #ifdef WITH_OSL @@ -54,6 +55,7 @@ struct OSLShaderInfo { has_surface_bssrdf(false) {} + OSL::OSLQuery query; bool has_surface_emission; bool has_surface_transparent; bool has_surface_bssrdf; @@ -83,6 +85,11 @@ public: const char *shader_load_filepath(string filepath); OSLShaderInfo *shader_loaded_info(const string& hash); + /* create OSL node using OSLQuery */ + OSLNode *osl_node(const std::string& filepath, + const std::string& bytecode_hash = "", + const std::string& bytecode = ""); + protected: void texture_system_init(); void texture_system_free(); @@ -118,6 +125,8 @@ public: void add(ShaderNode *node, const char *name, bool isfilepath = false); + void parameter(ShaderNode *node, const char *name); + void parameter(const char *name, float f); void parameter_color(const char *name, float3 f); void parameter_vector(const char *name, float3 f); diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index 50726bb4574..1a35d60fb4b 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -58,8 +58,8 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene * adds one dummy particle at the beginning to avoid invalid lookups, * in case a shader uses particle info without actual particle data. */ int num_particles = 1; - foreach(ParticleSystem *psys, scene->particle_systems) - num_particles += psys->particles.size(); + for(size_t j = 0; j < scene->particle_systems.size(); j++) + num_particles += scene->particle_systems[j]->particles.size(); float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles); @@ -71,9 +71,12 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); int i = 1; - foreach(ParticleSystem *psys, scene->particle_systems) { - foreach(Particle &pa, psys->particles) { + for(size_t j = 0; j < scene->particle_systems.size(); j++) { + ParticleSystem *psys = scene->particle_systems[j]; + + for(size_t k = 0; k < psys->particles.size(); k++) { /* pack in texture */ + Particle& pa = psys->particles[k]; int offset = i*PARTICLE_SIZE; particles[offset] = make_float4(pa.index, pa.age, pa.lifetime, pa.size); diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h index bf2b6b77015..2509e27b44b 100644 --- a/intern/cycles/render/particles.h +++ b/intern/cycles/render/particles.h @@ -47,7 +47,7 @@ public: void tag_update(Scene *scene); - vector<Particle> particles; + array<Particle> particles; }; /* ParticleSystem Manager */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b0052c30af4..b341837b7e8 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -242,9 +242,14 @@ void Scene::device_update(Device *device_, Progress& progress) } if(print_stats) { + size_t mem_used = util_guarded_get_mem_used(); + size_t mem_peak = util_guarded_get_mem_peak(); + VLOG(1) << "System memory statistics after full device sync:\n" - << " Usage: " << util_guarded_get_mem_used() << "\n" - << " Peak: " << util_guarded_get_mem_peak(); + << " Usage: " << string_human_readable_number(mem_used) + << " (" << string_human_readable_size(mem_used) << ")\n" + << " Peak: " << string_human_readable_number(mem_peak) + << " (" << string_human_readable_size(mem_peak) << ")"; } } @@ -258,6 +263,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading) return MOTION_NONE; } +float Scene::motion_shutter_time() +{ + if(need_motion() == Scene::MOTION_PASS) + return 2.0f; + else + return camera->shuttertime; +} + bool Scene::need_global_attribute(AttributeStandard std) { if(std == ATTR_STD_UV) diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 33c03d40f27..9e72f197cce 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -63,7 +63,8 @@ public: device_vector<float4> bvh_nodes; device_vector<float4> bvh_leaf_nodes; device_vector<uint> object_node; - device_vector<float4> tri_storage; + device_vector<uint> prim_tri_index; + device_vector<float4> prim_tri_verts; device_vector<uint> prim_type; device_vector<uint> prim_visibility; device_vector<uint> prim_index; @@ -72,12 +73,15 @@ public: /* mesh */ device_vector<uint> tri_shader; device_vector<float4> tri_vnormal; - device_vector<float4> tri_vindex; - device_vector<float4> tri_verts; + device_vector<uint4> tri_vindex; + device_vector<uint> tri_patch; + device_vector<float2> tri_patch_uv; device_vector<float4> curves; device_vector<float4> curve_keys; + device_vector<uint> patches; + /* objects */ device_vector<float4> objects; device_vector<float4> objects_vector; @@ -109,10 +113,12 @@ public: device_vector<uint> sobol_directions; /* cpu images */ - device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_IMAGES_CPU]; - device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_IMAGES_CPU]; - device_vector<float> tex_float_image[TEX_NUM_FLOAT_IMAGES_CPU]; - device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_IMAGES_CPU]; + device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_CPU]; + device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU]; + device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU]; + device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU]; + device_vector<half4> tex_half4_image[TEX_NUM_HALF4_CPU]; + device_vector<half> tex_half_image[TEX_NUM_HALF_CPU]; /* opencl images */ device_vector<uchar4> tex_image_byte4_packed; @@ -134,6 +140,7 @@ public: BVH_NUM_TYPES, } bvh_type; bool use_bvh_spatial_split; + bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; @@ -142,6 +149,7 @@ public: shadingsystem = SHADINGSYSTEM_SVM; bvh_type = BVH_DYNAMIC; use_bvh_spatial_split = false; + use_bvh_unaligned_nodes = true; use_qbvh = false; persistent_data = false; } @@ -150,6 +158,7 @@ public: { return !(shadingsystem == params.shadingsystem && bvh_type == params.bvh_type && use_bvh_spatial_split == params.use_bvh_spatial_split + && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_qbvh == params.use_qbvh && persistent_data == params.persistent_data); } }; @@ -208,6 +217,7 @@ public: enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; MotionType need_motion(bool advanced_shading = true); + float motion_shutter_time(); bool need_update(); bool need_reset(); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 76979e9ba3e..1cd76ff2b39 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -630,7 +630,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_camera_motion = scene->camera->use_motion; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; - if(mesh->curves.size() > 0) { + if(mesh->num_curves()) { requested_features.use_hair = true; } requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 635024d7bdf..4cdb878df45 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -449,17 +449,15 @@ void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scen void ShaderManager::add_default(Scene *scene) { - ShaderNode *closure, *out; - /* default surface */ { ShaderGraph *graph = new ShaderGraph(); - closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f); - out = graph->output(); + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = make_float3(0.8f, 0.8f, 0.8f); + graph->add(diffuse); - graph->connect(closure->output("BSDF"), out->input("Surface")); + graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface")); Shader *shader = new Shader(); shader->name = "default_surface"; @@ -472,12 +470,12 @@ void ShaderManager::add_default(Scene *scene) { ShaderGraph *graph = new ShaderGraph(); - closure = graph->add(new EmissionNode()); - closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f); - closure->input("Strength")->value.x = 0.0f; - out = graph->output(); + EmissionNode *emission = new EmissionNode(); + emission->color = make_float3(0.8f, 0.8f, 0.8f); + emission->strength = 0.0f; + graph->add(emission); - graph->connect(closure->output("Emission"), out->input("Surface")); + graph->connect(emission->output("Emission"), graph->output()->input("Surface")); Shader *shader = new Shader(); shader->name = "default_light"; diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 4c97a5ad792..1a166885e2b 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -65,20 +65,21 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); } - + foreach(Shader *shader, scene->shaders) { if(progress.get_cancel()) return; assert(shader->graph); - if(shader->use_mis && shader->has_surface_emission) - scene->light_manager->need_update = true; - SVMCompiler::Summary summary; SVMCompiler compiler(scene->shader_manager, scene->image_manager); compiler.background = (shader == scene->default_background); compiler.compile(scene, shader, svm_nodes, shader->id, &summary); + if(shader->use_mis && shader->has_surface_emission) { + scene->light_manager->need_update = true; + } + VLOG(2) << "Compilation summary:\n" << "Shader name: " << shader->name << "\n" << summary.full_report(); @@ -120,22 +121,22 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man compile_failed = false; } -int SVMCompiler::stack_size(ShaderSocketType type) +int SVMCompiler::stack_size(SocketType::Type type) { int size = 0; switch(type) { - case SHADER_SOCKET_FLOAT: - case SHADER_SOCKET_INT: + case SocketType::FLOAT: + case SocketType::INT: size = 1; break; - case SHADER_SOCKET_COLOR: - case SHADER_SOCKET_VECTOR: - case SHADER_SOCKET_NORMAL: - case SHADER_SOCKET_POINT: + case SocketType::COLOR: + case SocketType::VECTOR: + case SocketType::NORMAL: + case SocketType::POINT: size = 3; break; - case SHADER_SOCKET_CLOSURE: + case SocketType::CLOSURE: size = 0; break; default: @@ -146,7 +147,7 @@ int SVMCompiler::stack_size(ShaderSocketType type) return size; } -int SVMCompiler::stack_find_offset(ShaderSocketType type) +int SVMCompiler::stack_find_offset(SocketType::Type type) { int size = stack_size(type); int offset = -1; @@ -175,7 +176,7 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type) return 0; } -void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset) +void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset) { int size = stack_size(type); @@ -192,23 +193,25 @@ int SVMCompiler::stack_assign(ShaderInput *input) input->stack_offset = input->link->stack_offset; } else { + Node *node = input->parent; + /* not linked to output -> add nodes to load default value */ - input->stack_offset = stack_find_offset(input->type); + input->stack_offset = stack_find_offset(input->type()); - if(input->type == SHADER_SOCKET_FLOAT) { - add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset); + if(input->type() == SocketType::FLOAT) { + add_node(NODE_VALUE_F, __float_as_int(node->get_float(input->socket_type)), input->stack_offset); } - else if(input->type == SHADER_SOCKET_INT) { - add_node(NODE_VALUE_F, (int)input->value.x, input->stack_offset); + else if(input->type() == SocketType::INT) { + add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset); } - else if(input->type == SHADER_SOCKET_VECTOR || - input->type == SHADER_SOCKET_NORMAL || - input->type == SHADER_SOCKET_POINT || - input->type == SHADER_SOCKET_COLOR) + else if(input->type() == SocketType::VECTOR || + input->type() == SocketType::NORMAL || + input->type() == SocketType::POINT || + input->type() == SocketType::COLOR) { add_node(NODE_VALUE_V, input->stack_offset); - add_node(NODE_VALUE_V, input->value); + add_node(NODE_VALUE_V, node->get_float3(input->socket_type)); } else /* should not get called for closure */ assert(0); @@ -222,7 +225,7 @@ int SVMCompiler::stack_assign(ShaderOutput *output) { /* if no stack offset assigned yet, find one */ if(output->stack_offset == SVM_STACK_INVALID) - output->stack_offset = stack_find_offset(output->type); + output->stack_offset = stack_find_offset(output->type()); return output->stack_offset; } @@ -247,11 +250,11 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) { if(output->stack_offset == SVM_STACK_INVALID) { assert(input->link); - assert(stack_size(output->type) == stack_size(input->link->type)); + assert(stack_size(output->type()) == stack_size(input->link->type())); output->stack_offset = input->link->stack_offset; - int size = stack_size(output->type); + int size = stack_size(output->type()); for(int i = 0; i < size; i++) active_stack.users[output->stack_offset + i]++; @@ -279,7 +282,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done) all_done = false; if(all_done) { - stack_clear_offset(output->type, output->stack_offset); + stack_clear_offset(output->type(), output->stack_offset); output->stack_offset = SVM_STACK_INVALID; foreach(ShaderInput *in, output->links) @@ -293,7 +296,7 @@ void SVMCompiler::stack_clear_temporary(ShaderNode *node) { foreach(ShaderInput *input, node->inputs) { if(!input->link && input->stack_offset != SVM_STACK_INVALID) { - stack_clear_offset(input->type, input->stack_offset); + stack_clear_offset(input->type(), input->stack_offset); input->stack_offset = SVM_STACK_INVALID; } } @@ -446,7 +449,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; ShaderInput *weight_in = node->input(weight_name); - if(weight_in && (weight_in->link || weight_in->value.x != 1.0f)) + if(weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) mix_weight_offset = stack_assign(weight_in); else mix_weight_offset = SVM_STACK_INVALID; @@ -479,7 +482,7 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, } else { foreach(ShaderInput *in, node->inputs) { - if(in->type == SHADER_SOCKET_CLOSURE && in->link) + if(in->type() == SocketType::CLOSURE && in->link) generated_shared_closure_nodes(root_node, in->link->parent, state, diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index dbf1b1de947..e14d57d7601 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -99,8 +99,8 @@ public: int stack_assign(ShaderInput *input); int stack_assign_if_linked(ShaderInput *input); int stack_assign_if_linked(ShaderOutput *output); - int stack_find_offset(ShaderSocketType type); - void stack_clear_offset(ShaderSocketType type, int offset); + int stack_find_offset(SocketType::Type type); + void stack_clear_offset(SocketType::Type type, int offset); void stack_link(ShaderInput *input, ShaderOutput *output); void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0); @@ -172,7 +172,7 @@ protected: }; void stack_clear_temporary(ShaderNode *node); - int stack_size(ShaderSocketType type); + int stack_size(SocketType::Type type); void stack_clear_users(ShaderNode *node, ShaderNodeSet& done); bool node_skip_input(ShaderNode *node, ShaderInput *input); diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt index d1708868fd0..db497013693 100644 --- a/intern/cycles/subd/CMakeLists.txt +++ b/intern/cycles/subd/CMakeLists.txt @@ -14,14 +14,12 @@ set(INC_SYS set(SRC subd_dice.cpp - subd_mesh.cpp subd_patch.cpp subd_split.cpp ) set(SRC_HEADERS subd_dice.h - subd_mesh.h subd_patch.h subd_split.h ) diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index a5dfcd21ceb..36981a20f3c 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -41,14 +41,19 @@ EdgeDice::EdgeDice(const SubdParams& params_) } } -void EdgeDice::reserve(int num_verts, int num_tris) +void EdgeDice::reserve(int num_verts) { Mesh *mesh = params.mesh; vert_offset = mesh->verts.size(); - tri_offset = mesh->triangles.size(); + tri_offset = mesh->num_triangles(); - mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0); + /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ + if(vert_offset + num_verts > mesh->verts.capacity()) { + mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles()); + } + + mesh->resize_mesh(vert_offset + num_verts, tri_offset); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); @@ -66,25 +71,35 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) mesh_P[vert_offset] = P; mesh_N[vert_offset] = N; + params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y); if(params.ptex) { Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV); - params.mesh->attributes.reserve(); + params.mesh->attributes.resize(); float3 *ptex_uv = attr_ptex_uv->data_float3(); ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f); } + params.mesh->num_subd_verts++; + return vert_offset++; } void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) { - params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false); + Mesh *mesh = params.mesh; + + /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ + if(mesh->triangles.size() == mesh->triangles.capacity()) + mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2)); + + mesh->add_triangle(v0, v1, v2, patch->shader, true); + params.mesh->triangle_patch[params.mesh->num_triangles()-1] = patch->patch_index; if(params.ptex) { Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); - params.mesh->attributes.reserve(); + params.mesh->attributes.resize(); float *ptex_face_id = attr_ptex_face_id->data_float(); ptex_face_id[tri_offset] = (float)patch->ptex_face_id(); @@ -141,8 +156,7 @@ void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv) { /* XXX need to make this also work for edge factor 0 and 1 */ int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1); - int num_tris = 0; - EdgeDice::reserve(num_verts, num_tris); + EdgeDice::reserve(num_verts); } float2 QuadDice::map_uv(SubPatch& sub, float u, float v) @@ -335,160 +349,5 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef) assert(vert_offset == params.mesh->verts.size()); } -/* TriangleDice */ - -TriangleDice::TriangleDice(const SubdParams& params_) -: EdgeDice(params_) -{ -} - -void TriangleDice::reserve(EdgeFactors& ef, int M) -{ - int num_verts = ef.tu + ef.tv + ef.tw; - - for(int m = M-2; m > 0; m -= 2) - num_verts += 3 + (m-1)*3; - - if(!(M & 1)) - num_verts++; - - EdgeDice::reserve(num_verts, 0); -} - -float2 TriangleDice::map_uv(SubPatch& sub, float2 uv) -{ - /* map UV from subpatch to patch parametric coordinates */ - return uv.x*sub.Pu + uv.y*sub.Pv + (1.0f - uv.x - uv.y)*sub.Pw; -} - -int TriangleDice::add_vert(SubPatch& sub, float2 uv) -{ - return EdgeDice::add_vert(sub.patch, map_uv(sub, uv)); -} - -void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M) -{ - // XXX normals are flipped, why? - - /* grid is constructed starting from the outside edges, and adding - * progressively smaller inner triangles that connected to the outer - * one, until M = 1 or 2, the we fill up the last part. */ - vector<int> outer_u, outer_v, outer_w; - int m; - - /* add outer corners vertices */ - { - float2 p_u = make_float2(1.0f, 0.0f); - float2 p_v = make_float2(0.0f, 1.0f); - float2 p_w = make_float2(0.0f, 0.0f); - - int corner_u = add_vert(sub, p_u); - int corner_v = add_vert(sub, p_v); - int corner_w = add_vert(sub, p_w); - - outer_u.push_back(corner_v); - outer_v.push_back(corner_w); - outer_w.push_back(corner_u); - - for(int i = 1; i < ef.tu; i++) - outer_u.push_back(add_vert(sub, interp(p_v, p_w, i/(float)ef.tu))); - for(int i = 1; i < ef.tv; i++) - outer_v.push_back(add_vert(sub, interp(p_w, p_u, i/(float)ef.tv))); - for(int i = 1; i < ef.tw; i++) - outer_w.push_back(add_vert(sub, interp(p_u, p_v, i/(float)ef.tw))); - - outer_u.push_back(corner_w); - outer_v.push_back(corner_u); - outer_w.push_back(corner_v); - } - - for(m = M-2; m > 0; m -= 2) { - vector<int> inner_u, inner_v, inner_w; - - const float t0 = m / (float)M; - float2 center = make_float2(1.0f/3.0f, 1.0f/3.0f); - - /* 3 corner vertices */ - float2 p_u = interp(center, make_float2(1.0f, 0.0f), t0); - float2 p_v = interp(center, make_float2(0.0f, 1.0f), t0); - float2 p_w = interp(center, make_float2(0.0f, 0.0f), t0); - - int corner_u = add_vert(sub, p_u); - int corner_v = add_vert(sub, p_v); - int corner_w = add_vert(sub, p_w); - - /* construct array of vertex indices for each side */ - inner_u.push_back(corner_v); - inner_v.push_back(corner_w); - inner_w.push_back(corner_u); - - for(int i = 1; i < m; i++) { - /* add vertices between corners */ - const float t1 = i / (float)m; - - inner_u.push_back(add_vert(sub, interp(p_v, p_w, t1))); - inner_v.push_back(add_vert(sub, interp(p_w, p_u, t1))); - inner_w.push_back(add_vert(sub, interp(p_u, p_v, t1))); - } - - inner_u.push_back(corner_w); - inner_v.push_back(corner_u); - inner_w.push_back(corner_v); - - /* stitch together inner/outer with triangles */ - stitch_triangles(sub.patch, outer_u, inner_u); - stitch_triangles(sub.patch, outer_v, inner_v); - stitch_triangles(sub.patch, outer_w, inner_w); - - outer_u = inner_u; - outer_v = inner_v; - outer_w = inner_w; - } - - /* fill up last part */ - if(m == -1) { - /* single triangle */ - add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]); - } - else { - /* center vertex + up to 6 triangles */ - int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f)); - - add_triangle(sub.patch, outer_w[0], outer_w[1], center); - /* if this is false then there is only one triangle on this side */ - if(outer_w.size() > 2) - add_triangle(sub.patch, outer_w[1], outer_w[2], center); - - add_triangle(sub.patch, outer_u[0], outer_u[1], center); - if(outer_u.size() > 2) - add_triangle(sub.patch, outer_u[1], outer_u[2], center); - - add_triangle(sub.patch, outer_v[0], outer_v[1], center); - if(outer_v.size() > 2) - add_triangle(sub.patch, outer_v[1], outer_v[2], center); - } -} - -void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef) -{ - /* todo: handle 2 1 1 resolution */ - int M = max(ef.tu, max(ef.tv, ef.tw)); - - /* Due to the "slant" of the edges of a triangle compared to a quad, the internal - * triangles end up smaller, causing over-tessellation. This is to correct for this - * difference in area. Technically its only correct for equilateral triangles, but - * its better than how it was. - * - * (2*cos(radians(30))/3)**0.5 - */ - float S = 0.7598356856515927f; - M = max((int)ceil(S*M), 1); - - reserve(ef, M); - add_grid(sub, ef, M); - - assert(vert_offset == params.mesh->verts.size()); -} - CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h index 49f786e949e..3002ec780e8 100644 --- a/intern/cycles/subd/subd_dice.h +++ b/intern/cycles/subd/subd_dice.h @@ -33,8 +33,6 @@ class Patch; struct SubdParams { Mesh *mesh; - int shader; - bool smooth; bool ptex; int test_steps; @@ -44,11 +42,9 @@ struct SubdParams { Camera *camera; Transform objecttoworld; - SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false) + SubdParams(Mesh *mesh_, bool ptex_ = false) { mesh = mesh_; - shader = shader_; - smooth = smooth_; ptex = ptex_; test_steps = 3; @@ -72,7 +68,7 @@ public: explicit EdgeDice(const SubdParams& params); - void reserve(int num_verts, int num_tris); + void reserve(int num_verts); int add_vert(Patch *patch, float2 uv); void add_triangle(Patch *patch, int v0, int v1, int v2); @@ -136,46 +132,6 @@ public: void dice(SubPatch& sub, EdgeFactors& ef); }; -/* Triangle EdgeDice - * - * Edge tessellation factors and subpatch coordinates are as follows: - * - * Pw - * /\ - * tv / \ tu - * / \ - * / \ - * Pu -------- Pv - * tw - */ - -class TriangleDice : public EdgeDice { -public: - struct SubPatch { - Patch *patch; - - float2 Pu; - float2 Pv; - float2 Pw; - }; - - struct EdgeFactors { - int tu; - int tv; - int tw; - }; - - explicit TriangleDice(const SubdParams& params); - - void reserve(EdgeFactors& ef, int M); - - float2 map_uv(SubPatch& sub, float2 uv); - int add_vert(SubPatch& sub, float2 uv); - - void add_grid(SubPatch& sub, EdgeFactors& ef, int M); - void dice(SubPatch& sub, EdgeFactors& ef); -}; - CCL_NAMESPACE_END #endif /* __SUBD_DICE_H__ */ diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp deleted file mode 100644 index 56d7d2b2303..00000000000 --- a/intern/cycles/subd/subd_mesh.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> - -#include "subd_mesh.h" -#include "subd_patch.h" -#include "subd_split.h" - -#include "util_debug.h" -#include "util_foreach.h" - -#ifdef WITH_OPENSUBDIV - -#include <osd/vertex.h> -#include <osd/mesh.h> -#include <osd/cpuComputeController.h> -#include <osd/cpuVertexBuffer.h> -#include <osd/cpuEvalLimitController.h> -#include <osd/evalLimitContext.h> - -CCL_NAMESPACE_BEGIN - -/* typedefs */ -typedef OpenSubdiv::OsdVertex OsdVertex; -typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh; -typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory; -typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision; -typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace; -typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge; -typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh; -typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex; -typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext; -typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController; -typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext; -typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController; -typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer; -typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords; -typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor; - -/* OpenSubdiv Patch */ - -class OpenSubdPatch : public Patch { -public: - int face_id; - - OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base) - { - face_id = 0; - - /* create buffers for evaluation */ - vbuf_P = OsdCpuVertexBuffer::Create(3, 1); - vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1); - vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1); - - P = vbuf_P->BindCpuBuffer(); - dPdu = vbuf_dPdu->BindCpuBuffer(); - dPdv = vbuf_dPdv->BindCpuBuffer(); - - /* setup evaluation context */ - OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */ - - evalctx = OsdCpuEvalLimitContext::Create(farmesh, false); - evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv); - } - - ~OpenSubdPatch() - { - evalctx->GetVertexData().Unbind(); - - delete evalctx; - delete vbuf_P; - delete vbuf_dPdu; - delete vbuf_dPdv; - } - - void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v) - { - OsdEvalCoords coords; - coords.u = u; - coords.v = v; - coords.face = face_id; - - evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0); - - *P_ = make_float3(P[0], P[1], P[2]); - if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]); - if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]); - - /* optimize: skip evaluating derivatives when not needed */ - /* todo: swapped derivatives, different winding convention? */ - } - - BoundBox bound() - { - /* not implemented */ - BoundBox bbox = BoundBox::empty; - return bbox; - } - - int ptex_face_id() - { - return face_id; - } - -protected: - OsdCpuEvalLimitController evalctrl; - OsdCpuEvalLimitContext *evalctx; - OsdCpuVertexBuffer *vbuf_P; - OsdCpuVertexBuffer *vbuf_dPdu; - OsdCpuVertexBuffer *vbuf_dPdv; - float *P; - float *dPdu; - float *dPdv; -}; - -/* OpenSubdiv Mesh */ - -OpenSubdMesh::OpenSubdMesh() -{ - /* create osd mesh */ - static OsdHbrCatmarkSubdivision catmark; - OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark); - - /* initialize class */ - num_verts = 0; - num_ptex_faces = 0; - _hbrmesh = (void*)hbrmesh; -} - -OpenSubdMesh::~OpenSubdMesh() -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - if(hbrmesh) - delete hbrmesh; -} - -void OpenSubdMesh::add_vert(const float3& co) -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - OsdVertex v; - positions.push_back(co.x); - positions.push_back(co.y); - positions.push_back(co.z); - hbrmesh->NewVertex(num_verts++, v); -} - -void OpenSubdMesh::add_face(int v0, int v1, int v2) -{ - int index[3] = {v0, v1, v2}; - return add_face(index, 3); -} - -void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3) -{ - int index[4] = {v0, v1, v2, v3}; - add_face(index, 4); -} - -void OpenSubdMesh::add_face(int *index, int num) -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - -#ifndef NDEBUG - /* sanity checks */ - for(int j = 0; j < num; j++) { - OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]); - OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]); - OsdHbrHalfEdge *opposite = destination->GetEdge(origin); - - if(origin==NULL || destination==NULL) - assert(!"An edge was specified that connected a nonexistent vertex\n"); - - if(origin == destination) - assert(!"An edge was specified that connected a vertex to itself\n"); - - if(opposite && opposite->GetOpposite()) - assert(!"A non-manifold edge incident to more than 2 faces was found\n"); - - if(origin->GetEdge(destination)) { - assert(!"An edge connecting two vertices was specified more than once." - "It's likely that an incident face was flipped\n"); - } - } -#endif - - OsdHbrFace *face = hbrmesh->NewFace(num, index, 0); - - /* this is required for limit eval patch table? */ - face->SetPtexIndex(num_ptex_faces); - - if(num == 4) - num_ptex_faces++; - else - num_ptex_faces += num; -} - -bool OpenSubdMesh::finish() -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - /* finish hbr mesh construction */ - hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly); - hbrmesh->Finish(); - - return true; -} - -void OpenSubdMesh::tessellate(DiagSplit *split) -{ - if(num_ptex_faces == 0) - return; - - const int level = 3; - const bool requirefvar = false; - - /* convert HRB to FAR mesh */ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - OsdFarMeshFactory meshFactory(hbrmesh, level, true); - OsdFarMesh *farmesh = meshFactory.Create(requirefvar); - int num_hbr_verts = hbrmesh->GetNumVertices(); - - delete hbrmesh; - hbrmesh = NULL; - _hbrmesh = NULL; - - /* refine HBR mesh with vertex coordinates */ - OsdCpuComputeController *compute_controller = new OsdCpuComputeController(); - OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh); - - OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts); - vbuf_base->UpdateData(&positions[0], 0, num_verts); - - compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base); - compute_controller->Synchronize(); - - /* split & dice patches */ - OpenSubdPatch patch(farmesh, vbuf_base); - - for(int f = 0; f < num_ptex_faces; f++) { - patch.face_id = f; - split->split_quad(&patch); - } - - /* clean up */ - delete farmesh; - delete compute_controller; - delete compute_context; - delete vbuf_base; -} - -CCL_NAMESPACE_END - -#else /* WITH_OPENSUBDIV */ - -CCL_NAMESPACE_BEGIN - -/* Subd Vertex */ - -class SubdVert -{ -public: - int id; - float3 co; - - explicit SubdVert(int id_) - { - id = id_; - co = make_float3(0.0f, 0.0f, 0.0f); - } -}; - -/* Subd Face */ - -class SubdFace -{ -public: - int id; - int numverts; - int verts[4]; - - explicit SubdFace(int id_) - { - id = id_; - numverts = 0; - } -}; - -/* Subd Mesh */ - -SubdMesh::SubdMesh() -{ -} - -SubdMesh::~SubdMesh() -{ - foreach(SubdVert *vertex, verts) - delete vertex; - foreach(SubdFace *face, faces) - delete face; - - verts.clear(); - faces.clear(); -} - -SubdVert *SubdMesh::add_vert(const float3& co) -{ - SubdVert *v = new SubdVert(verts.size()); - v->co = co; - verts.push_back(v); - - return v; -} - -SubdFace *SubdMesh::add_face(int v0, int v1, int v2) -{ - int index[3] = {v0, v1, v2}; - return add_face(index, 3); -} - -SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3) -{ - int index[4] = {v0, v1, v2, v3}; - return add_face(index, 4); -} - -SubdFace *SubdMesh::add_face(int *index, int num) -{ - /* skip ngons */ - if(num < 3 || num > 4) - return NULL; - - SubdFace *f = new SubdFace(faces.size()); - - for(int i = 0; i < num; i++) - f->verts[i] = index[i]; - - f->numverts = num; - faces.push_back(f); - - return f; -} - -bool SubdMesh::finish() -{ - return true; -} - -void SubdMesh::tessellate(DiagSplit *split) -{ - int num_faces = faces.size(); - - for(int f = 0; f < num_faces; f++) { - SubdFace *face = faces[f]; - Patch *patch; - float3 *hull; - - if(face->numverts == 3) { - LinearTrianglePatch *lpatch = new LinearTrianglePatch(); - hull = lpatch->hull; - patch = lpatch; - } - else if(face->numverts == 4) { - LinearQuadPatch *lpatch = new LinearQuadPatch(); - hull = lpatch->hull; - patch = lpatch; - } - else { - assert(0); /* n-gons should have been split already */ - continue; - } - - for(int i = 0; i < face->numverts; i++) - hull[i] = verts[face->verts[i]]->co; - - if(face->numverts == 4) - swap(hull[2], hull[3]); - - if(patch->is_triangle()) - split->split_triangle(patch); - else - split->split_quad(patch); - - delete patch; - } -} - -CCL_NAMESPACE_END - -#endif /* WITH_OPENSUBDIV */ - diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h deleted file mode 100644 index f6aefc20318..00000000000 --- a/intern/cycles/subd/subd_mesh.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SUBD_MESH_H__ -#define __SUBD_MESH_H__ - -#include "util_map.h" -#include "util_types.h" -#include "util_vector.h" - -CCL_NAMESPACE_BEGIN - -#ifndef WITH_OPENSUBDIV -class SubdVert; -class SubdFace; -#endif - -class DiagSplit; -class Mesh; - -/* Subd Mesh with simple linear subdivision */ - -class SubdMesh -{ -public: - SubdMesh(); - ~SubdMesh(); - - SubdVert *add_vert(const float3& co); - - SubdFace *add_face(int v0, int v1, int v2); - SubdFace *add_face(int v0, int v1, int v2, int v3); - SubdFace *add_face(int *index, int num); - - bool finish(); - void tessellate(DiagSplit *split); - -protected: -#ifdef WITH_OPENSUBDIV - void *_hbrmesh; - vector<float> positions; - int num_verts, num_ptex_faces; -#else - vector<SubdVert*> verts; - vector<SubdFace*> faces; -#endif - -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_MESH_H__ */ - diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp index 60a78016054..d3319c5ccf5 100644 --- a/intern/cycles/subd/subd_patch.cpp +++ b/intern/cycles/subd/subd_patch.cpp @@ -84,32 +84,6 @@ BoundBox LinearQuadPatch::bound() return bbox; } -/* Linear Triangle Patch */ - -void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) -{ - *P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2]; - - if(dPdu && dPdv) { - *dPdu = hull[0] - hull[2]; - *dPdv = hull[1] - hull[2]; - } - - if(N) { - *N = normalize(u*normals[0] + v*normals[1] + (1.0f - u - v)*normals[2]); - } -} - -BoundBox LinearTrianglePatch::bound() -{ - BoundBox bbox = BoundBox::empty; - - for(int i = 0; i < 3; i++) - bbox.grow(hull[i]); - - return bbox; -} - /* Bicubic Patch */ void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h index bfa04412c66..360c1abf27b 100644 --- a/intern/cycles/subd/subd_patch.h +++ b/intern/cycles/subd/subd_patch.h @@ -26,9 +26,11 @@ class Patch { public: virtual ~Patch() {} virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0; - virtual bool is_triangle() { return false; } virtual BoundBox bound() = 0; virtual int ptex_face_id() { return -1; } + + int patch_index; + int shader; }; /* Linear Quad Patch */ @@ -39,19 +41,6 @@ public: float3 normals[4]; void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return false; } - BoundBox bound(); -}; - -/* Linear Triangle Patch */ - -class LinearTrianglePatch : public Patch { -public: - float3 hull[3]; - float3 normals[3]; - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return true; } BoundBox bound(); }; @@ -62,7 +51,6 @@ public: float3 hull[16]; void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return false; } BoundBox bound(); }; diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp index c4af8cc8c43..3c91ad8ab0d 100644 --- a/intern/cycles/subd/subd_split.cpp +++ b/intern/cycles/subd/subd_split.cpp @@ -40,12 +40,6 @@ void DiagSplit::dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef) edgefactors_quad.push_back(ef); } -void DiagSplit::dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef) -{ - subpatches_triangle.push_back(sub); - edgefactors_triangle.push_back(ef); -} - float3 DiagSplit::to_world(Patch *patch, float2 uv) { float3 P; @@ -112,34 +106,6 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2 } } -static float2 right_to_equilateral(float2 P) -{ - static const float2 A = make_float2(1.0f, 0.5f); - static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f)); - return make_float2(dot(P, A), dot(P, B)); -} - -static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t) -{ - float2 Pu = sub.Pu; - float2 Pv = sub.Pv; - float2 Pw = sub.Pw; - - if(sub.patch->is_triangle()) { - Pu = right_to_equilateral(Pu); - Pv = right_to_equilateral(Pv); - Pw = right_to_equilateral(Pw); - } - - int tu = int(max_t * len(Pw - Pv)); - int tv = int(max_t * len(Pw - Pu)); - int tw = int(max_t * len(Pv - Pu)); - - ef.tu = tu <= 1 ? 1 : min(ef.tu, tu); - ef.tv = tv <= 1 ? 1 : min(ef.tv, tv); - ef.tw = tw <= 1 ? 1 : min(ef.tw, tw); -} - static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t) { float2 P00 = sub.P00; @@ -147,13 +113,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact float2 P10 = sub.P10; float2 P11 = sub.P11; - if(sub.patch->is_triangle()) { - P00 = right_to_equilateral(P00); - P01 = right_to_equilateral(P01); - P10 = right_to_equilateral(P10); - P11 = right_to_equilateral(P11); - } - int tu0 = int(max_t * len(P10 - P00)); int tu1 = int(max_t * len(P11 - P01)); int tv0 = int(max_t * len(P01 - P00)); @@ -165,84 +124,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1); } -void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth) -{ - if(depth > 32) { - /* We should never get here, but just in case end recursion safely. */ - ef.tu = 1; - ef.tv = 1; - ef.tw = 1; - - dispatch(sub, ef); - return; - } - - assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw)); - assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu)); - assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv)); - - int non_uniform_count = int(ef.tu == DSPLIT_NON_UNIFORM) + - int(ef.tv == DSPLIT_NON_UNIFORM) + - int(ef.tw == DSPLIT_NON_UNIFORM); - - switch(non_uniform_count) { - case 1: { - /* TODO(mai): one edge is non-uniform, split into two triangles */ - // fallthru - } - case 2: { - /* TODO(mai): two edges are non-uniform, split into triangle and quad */ - // fallthru - } - case 3: { - /* all three edges are non-uniform, split into three quads */ - - /* partition edges */ - QuadDice::EdgeFactors ef0, ef1, ef2; - float2 Pu, Pv, Pw, Pcenter; - - partition_edge(sub.patch, &Pu, &ef1.tv0, &ef2.tu0, sub.Pw, sub.Pv, ef.tu); - partition_edge(sub.patch, &Pv, &ef0.tv0, &ef1.tu0, sub.Pu, sub.Pw, ef.tv); - partition_edge(sub.patch, &Pw, &ef2.tv0, &ef0.tu0, sub.Pv, sub.Pu, ef.tw); - Pcenter = (Pu + Pv + Pw) * (1.0f / 3.0f); - - /* split */ - int tsplit01 = T(sub.patch, Pv, Pcenter); - int tsplit12 = T(sub.patch, Pu, Pcenter); - int tsplit20 = T(sub.patch, Pw, Pcenter); - - ef0.tu1 = tsplit01; - ef0.tv1 = tsplit20; - - ef1.tu1 = tsplit12; - ef1.tv1 = tsplit01; - - ef2.tu1 = tsplit20; - ef2.tv1 = tsplit12; - - /* create subpatches */ - QuadDice::SubPatch sub0 = {sub.patch, sub.Pu, Pw, Pv, Pcenter}; - QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter}; - QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter}; - - limit_edge_factors(sub0, ef0, 1 << params.max_level); - limit_edge_factors(sub1, ef1, 1 << params.max_level); - limit_edge_factors(sub2, ef2, 1 << params.max_level); - - split(sub0, ef0, depth+1); - split(sub1, ef1, depth+1); - split(sub2, ef2, depth+1); - - break; - } - default: { - /* all edges uniform, no splitting needed */ - dispatch(sub, ef); - break; - } - } -} - void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth) { if(depth > 32) { @@ -259,6 +140,16 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM); bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM); + /* Split subpatches such that the ratio of T for opposite edges doesn't + * exceed 1.5, this reduces over tessellation for some patches + */ + bool tmp_split_v = split_v; + if(!split_u && min(ef.tu0, ef.tu1) > 8 && min(ef.tu0, ef.tu1)*1.5f < max(ef.tu0, ef.tu1)) + split_v = true; + if(!tmp_split_v && min(ef.tu0, ef.tu1) > 8 && min(ef.tv0, ef.tv1)*1.5f < max(ef.tv0, ef.tv1)) + split_u = true; + + /* alternate axis */ if(split_u && split_v) { split_u = depth % 2; } @@ -324,69 +215,21 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de } } -void DiagSplit::split_triangle(Patch *patch) -{ - TriangleDice::SubPatch sub_split; - TriangleDice::EdgeFactors ef_split; - - sub_split.patch = patch; - sub_split.Pu = make_float2(1.0f, 0.0f); - sub_split.Pv = make_float2(0.0f, 1.0f); - sub_split.Pw = make_float2(0.0f, 0.0f); - - ef_split.tu = T(patch, sub_split.Pv, sub_split.Pw); - ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu); - ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv); - - limit_edge_factors(sub_split, ef_split, 1 << params.max_level); - - split(sub_split, ef_split); - - TriangleDice dice(params); - - for(size_t i = 0; i < subpatches_triangle.size(); i++) { - TriangleDice::SubPatch& sub = subpatches_triangle[i]; - TriangleDice::EdgeFactors& ef = edgefactors_triangle[i]; - - ef.tu = max(ef.tu, 1); - ef.tv = max(ef.tv, 1); - ef.tw = max(ef.tw, 1); - - dice.dice(sub, ef); - } - - subpatches_triangle.clear(); - edgefactors_triangle.clear(); - - /* triangle might be split into quads so dice quad subpatches as well */ - QuadDice qdice(params); - - for(size_t i = 0; i < subpatches_quad.size(); i++) { - QuadDice::SubPatch& sub = subpatches_quad[i]; - QuadDice::EdgeFactors& ef = edgefactors_quad[i]; - - ef.tu0 = max(ef.tu0, 1); - ef.tu1 = max(ef.tu1, 1); - ef.tv0 = max(ef.tv0, 1); - ef.tv1 = max(ef.tv1, 1); - - qdice.dice(sub, ef); - } - - subpatches_quad.clear(); - edgefactors_quad.clear(); -} - -void DiagSplit::split_quad(Patch *patch) +void DiagSplit::split_quad(Patch *patch, QuadDice::SubPatch *subpatch) { QuadDice::SubPatch sub_split; QuadDice::EdgeFactors ef_split; - sub_split.patch = patch; - sub_split.P00 = make_float2(0.0f, 0.0f); - sub_split.P10 = make_float2(1.0f, 0.0f); - sub_split.P01 = make_float2(0.0f, 1.0f); - sub_split.P11 = make_float2(1.0f, 1.0f); + if(subpatch) { + sub_split = *subpatch; + } + else { + sub_split.patch = patch; + sub_split.P00 = make_float2(0.0f, 0.0f); + sub_split.P10 = make_float2(1.0f, 0.0f); + sub_split.P01 = make_float2(0.0f, 1.0f); + sub_split.P11 = make_float2(1.0f, 1.0f); + } ef_split.tu0 = T(patch, sub_split.P00, sub_split.P10); ef_split.tu1 = T(patch, sub_split.P01, sub_split.P11); diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h index bbe921f739c..a2f76dd2e03 100644 --- a/intern/cycles/subd/subd_split.h +++ b/intern/cycles/subd/subd_split.h @@ -38,8 +38,6 @@ class DiagSplit { public: vector<QuadDice::SubPatch> subpatches_quad; vector<QuadDice::EdgeFactors> edgefactors_quad; - vector<TriangleDice::SubPatch> subpatches_triangle; - vector<TriangleDice::EdgeFactors> edgefactors_triangle; SubdParams params; @@ -53,11 +51,7 @@ public: void dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef); void split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth=0); - void dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef); - void split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth=0); - - void split_triangle(Patch *patch); - void split_quad(Patch *patch); + void split_quad(Patch *patch, QuadDice::SubPatch *subpatch=NULL); }; CCL_NAMESPACE_END diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt index 2f3a4d0b1df..a6bcf980df2 100644 --- a/intern/cycles/test/CMakeLists.txt +++ b/intern/cycles/test/CMakeLists.txt @@ -14,9 +14,37 @@ endmacro() set(INC . .. + ../device + ../graph + ../kernel + ../render ../util ) +set(ALL_CYCLES_LIBRARIES + cycles_render + cycles_device + cycles_bvh + cycles_graph + cycles_kernel_osl + cycles_util + ${OPENIMAGEIO_LIBRARIES} +) +if(WITH_CYCLES_OSL) + list(APPEND ALL_CYCLES_LIBRARIES + ${OSL_LIBRARIES} + ${LLVM_LIBRARIES} + ) +endif() +if(WITH_IMAGE_OPENJPEG AND NOT WITH_SYSTEM_OPENJPEG) + list(APPEND ALL_CYCLES_LIBRARIES + extern_openjpeg + ) +endif() +list(APPEND ALL_CYCLES_LIBRARIES + ${BOOST_LIBRARIES} +) + include_directories(${INC}) link_directories(${BOOST_LIBPATH}) @@ -25,6 +53,7 @@ link_directories(${OPENIMAGEIO_LIBPATH}) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}") +CYCLES_TEST(render_graph_finalize "${ALL_CYCLES_LIBRARIES}") CYCLES_TEST(util_aligned_malloc "cycles_util") CYCLES_TEST(util_path "cycles_util;${BOOST_LIBRARIES};${OPENIMAGEIO_LIBRARIES}") CYCLES_TEST(util_string "cycles_util;${BOOST_LIBRARIES}") diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp new file mode 100644 index 00000000000..4566894d490 --- /dev/null +++ b/intern/cycles/test/render_graph_finalize_test.cpp @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#include "testing/testing.h" +#include "testing/mock_log.h" + +#include "render/graph.h" +#include "render/scene.h" +#include "render/nodes.h" +#include "util/util_logging.h" +#include "util/util_string.h" +#include "util/util_vector.h" + +using testing::AnyNumber; +using testing::HasSubstr; +using testing::ScopedMockLog; +using testing::_; + +CCL_NAMESPACE_BEGIN + +namespace { + +template<typename T> +class ShaderNodeBuilder { +public: + ShaderNodeBuilder(const string& name) + : name_(name) + { + node_ = new T(); + } + + const string& name() const { + return name_; + } + + ShaderNode *node() const { + return node_; + } + + template<typename V> + ShaderNodeBuilder& set(const string& input_name, V value) + { + ShaderInput *input_socket = node_->input(input_name.c_str()); + EXPECT_NE((void*)NULL, input_socket); + input_socket->set(value); + return *this; + } + +protected: + string name_; + ShaderNode *node_; +}; + +class ShaderGraphBuilder { +public: + explicit ShaderGraphBuilder(ShaderGraph *graph) + : graph_(graph) + { + } + + ShaderNode *find_node(const string& name) + { + map<string, ShaderNode *>::iterator it = node_map_.find(name); + if(it == node_map_.end()) { + return NULL; + } + return it->second; + } + + template<typename T> + ShaderGraphBuilder& add_node(const T& node) + { + EXPECT_EQ(NULL, find_node(node.name())); + graph_->add(node.node()); + node_map_[node.name()] = node.node(); + return *this; + } + + ShaderGraphBuilder& add_connection(const string& from, + const string& to) + { + vector<string> tokens_from, tokens_to; + string_split(tokens_from, from, "::"); + string_split(tokens_to, to, "::"); + EXPECT_EQ(2, tokens_from.size()); + EXPECT_EQ(2, tokens_to.size()); + ShaderNode *node_from = find_node(tokens_from[0]), + *node_to = find_node(tokens_to[0]); + EXPECT_NE((void*)NULL, node_from); + EXPECT_NE((void*)NULL, node_to); + EXPECT_NE(node_from, node_to); + ShaderOutput *socket_from = node_from->output(tokens_from[1].c_str()); + ShaderInput *socket_to = node_to->input(tokens_to[1].c_str()); + EXPECT_NE((void*)NULL, socket_from); + EXPECT_NE((void*)NULL, socket_to); + graph_->connect(socket_from, socket_to); + return *this; + } + +protected: + ShaderGraph *graph_; + map<string, ShaderNode *> node_map_; +}; + +} // namespace + +#define DEFINE_COMMON_VARIABLES(builder_name, mock_log_name) \ + util_logging_start(); \ + util_logging_verbosity_set(1); \ + ScopedMockLog mock_log_name; \ + DeviceInfo device_info; \ + SceneParams scene_params; \ + Scene scene(scene_params, device_info); \ + ShaderGraph graph; \ + ShaderGraphBuilder builder(&graph); \ + +TEST(render_graph, constant_fold_rgb_to_bw) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(log, Log(google::INFO, _, + HasSubstr("Replacing rgb_to_bw with constant 0.8."))); + + builder + .add_node(ShaderNodeBuilder<OutputNode>("OutputNode")) + .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode")) + .add_node(ShaderNodeBuilder<RGBToBWNode>("RGBToBWNodeNode") + .set("Color", make_float3(0.8f, 0.8f, 0.8f))) + .add_connection("RGBToBWNodeNode::Val", "EmissionNode::Color") + .add_connection("EmissionNode::Emission", "OutputNode::Surface"); + + graph.finalize(&scene); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index cceec8d444c..e6140b3ed09 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -19,8 +19,10 @@ set(SRC util_simd.cpp util_system.cpp util_task.cpp + util_thread.cpp util_time.cpp util_transform.cpp + util_windows.cpp ) if(NOT CYCLES_STANDALONE_REPOSITORY) diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index cef5adc0a61..599222da9c5 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -151,7 +151,7 @@ public: (isfinite(max.x) && isfinite(max.y) && isfinite(max.z)); } - BoundBox transformed(const Transform *tfm) + BoundBox transformed(const Transform *tfm) const { BoundBox result = BoundBox::empty; diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h index f4bac9888a5..ae85ab3a915 100644 --- a/intern/cycles/util/util_half.h +++ b/intern/cycles/util/util_half.h @@ -85,6 +85,27 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale) #endif } +ccl_device_inline float half_to_float(half h) +{ + float f; + + *((int*) &f) = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + + return f; +} + +ccl_device_inline float4 half4_to_float4(half4 h) +{ + float4 f; + + f.x = half_to_float(h.x); + f.y = half_to_float(h.y); + f.z = half_to_float(h.z); + f.w = half_to_float(h.w); + + return f; +} + #endif #endif diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 32924f9a8c2..016f4a6a794 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -174,6 +174,11 @@ ccl_device_inline float clamp(float a, float mn, float mx) return min(max(a, mn), mx); } +ccl_device_inline float mix(float a, float b, float t) +{ + return a + t*(b - a); +} + #endif #ifndef __KERNEL_CUDA__ @@ -219,6 +224,11 @@ ccl_device_inline float smoothstepf(float f) return (3.0f*ff - 2.0f*ff*f); } +ccl_device_inline int mod(int x, int m) +{ + return (x % m + m) % m; +} + /* Float2 Vector */ #ifndef __KERNEL_OPENCL__ @@ -545,6 +555,11 @@ ccl_device_inline float3 normalize(const float3 a) #endif +ccl_device_inline float3 saturate3(float3 a) +{ + return make_float3(saturate(a.x), saturate(a.y), saturate(a.z)); +} + ccl_device_inline float3 normalize_len(const float3 a, float *t) { *t = len(a); @@ -647,6 +662,15 @@ ccl_device_inline float3 interp(float3 a, float3 b, float t) return a + t*(b - a); } +#ifndef __KERNEL_OPENCL__ + +ccl_device_inline float3 mix(float3 a, float3 b, float t) +{ + return a + t*(b - a); +} + +#endif + ccl_device_inline bool is_zero(const float3 a) { #ifdef __KERNEL_SSE__ @@ -666,6 +690,15 @@ ccl_device_inline float average(const float3 a) return reduce_add(a)*(1.0f/3.0f); } +ccl_device_inline bool isequal_float3(const float3 a, const float3 b) +{ +#ifdef __KERNEL_OPENCL__ + return all(a == b); +#else + return a == b; +#endif +} + /* Float4 Vector */ #ifdef __KERNEL_SSE__ @@ -1329,6 +1362,15 @@ ccl_device float safe_modulo(float a, float b) return (b != 0.0f)? fmodf(a, b): 0.0f; } +ccl_device_inline float beta(float x, float y) +{ +#ifndef __KERNEL_OPENCL__ + return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y)); +#else + return expf(lgamma(x) + lgamma(y) - lgamma(x+y)); +#endif +} + /* Ray Intersection */ ccl_device bool ray_sphere_intersect( @@ -1479,21 +1521,25 @@ ccl_device bool ray_triangle_intersect_uv( return true; } -ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_t, - float3 quad_P, float3 quad_u, float3 quad_v, +ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt, + float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n, float3 *isect_P, float *isect_t) { - float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f; - float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f; - float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f; - float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f; + float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); + if(t < ray_mint || t > ray_maxt) + return false; - if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t)) - return true; - else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t)) - return true; - - return false; + float3 hit = ray_P + t*ray_D; + float3 inplane = hit - quad_P; + if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f) + return false; + if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f) + return false; + + if(isect_P) *isect_P = hit; + if(isect_t) *isect_t = t; + + return true; } /* projections */ diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h index deb2013daae..d3960deb3b4 100644 --- a/intern/cycles/util/util_math_fast.h +++ b/intern/cycles/util/util_math_fast.h @@ -547,6 +547,9 @@ ccl_device_inline float fast_erff(float x) const float a5 = 0.0002765672f; const float a6 = 0.0000430638f; const float a = fabsf(x); + if(a >= 12.3f) { + return copysignf(1.0f, x); + } const float b = 1.0f - (1.0f - a); /* Crush denormals. */ const float r = madd(madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f); const float s = r * r; /* ^2 */ diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp index 0c848beaafd..f23f2cb0168 100644 --- a/intern/cycles/util/util_path.cpp +++ b/intern/cycles/util/util_path.cpp @@ -728,6 +728,17 @@ bool path_remove(const string& path) return remove(path.c_str()) == 0; } +static string line_directive(const string& path, int line) +{ + string escaped_path = path; + string_replace(escaped_path, "\"", "\\\""); + string_replace(escaped_path, "\'", "\\\'"); + string_replace(escaped_path, "\?", "\\\?"); + string_replace(escaped_path, "\\", "\\\\"); + return string_printf("#line %d \"%s\"", line, escaped_path.c_str()); +} + + string path_source_replace_includes(const string& source, const string& path) { /* Our own little c preprocessor that replaces #includes with the file @@ -737,7 +748,7 @@ string path_source_replace_includes(const string& source, const string& path) string result = ""; vector<string> lines; - string_split(lines, source, "\n"); + string_split(lines, source, "\n", false); for(size_t i = 0; i < lines.size(); ++i) { string line = lines[i]; @@ -759,7 +770,10 @@ string path_source_replace_includes(const string& source, const string& path) text = path_source_replace_includes( text, path_dirname(filepath)); text = path_source_replace_includes(text, path); - line = token.replace(0, n_end + 1, "\n" + text + "\n"); + /* Use line directives for better error messages. */ + line = line_directive(filepath, 1) + + token.replace(0, n_end + 1, "\n" + text + "\n") + + line_directive(path, i); } } } diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index b3a8c6d7c2e..5594aa8edb6 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -74,7 +74,10 @@ bool string_iequals(const string& a, const string& b) return false; } -void string_split(vector<string>& tokens, const string& str, const string& separators) +void string_split(vector<string>& tokens, + const string& str, + const string& separators, + bool skip_empty_tokens) { size_t token_start = 0, token_length = 0; for(size_t i = 0; i < str.size(); ++i) { @@ -87,9 +90,9 @@ void string_split(vector<string>& tokens, const string& str, const string& separ } else { /* Current character is a separator, - * append current token to the list (if token is not empty). + * append current token to the list. */ - if(token_length > 0) { + if(!skip_empty_tokens || token_length > 0) { string token = str.substr(token_start, token_length); tokens.push_back(token); } @@ -239,5 +242,49 @@ string string_to_ansi(const string& str) #endif /* _WIN32 */ +string string_human_readable_size(size_t size) +{ + static const char suffixes[] = "BKMGTPEZY"; + + const char* suffix = suffixes; + size_t r = 0; + + while(size >= 1024) { + r = size % 1024; + size /= 1024; + suffix++; + } + + if(*suffix != 'B') + return string_printf("%.2f%c", double(size*1024+r)/1024.0, *suffix); + else + return string_printf("%zu", size); +} + +string string_human_readable_number(size_t num) +{ + if(num == 0) { + return "0"; + } + + /* Add thousands separators. */ + char buf[32]; + + char* p = buf+31; + *p = '\0'; + + int i = -1; + while(num) { + if(++i && i % 3 == 0) + *(--p) = ','; + + *(--p) = '0' + (num % 10); + + num /= 10; + } + + return p; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index c4b51bda432..7aeed96f00b 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -39,7 +39,10 @@ using std::istringstream; string string_printf(const char *format, ...) PRINTF_ATTRIBUTE; bool string_iequals(const string& a, const string& b); -void string_split(vector<string>& tokens, const string& str, const string& separators = "\t "); +void string_split(vector<string>& tokens, + const string& str, + const string& separators = "\t ", + bool skip_empty_tokens = true); void string_replace(string& haystack, const string& needle, const string& other); bool string_startswith(const string& s, const char *start); bool string_endswith(const string& s, const char *end); @@ -62,6 +65,11 @@ string string_from_wstring(const wstring& path); string string_to_ansi(const string& str); #endif +/* Make a string from a size in bytes in human readable form */ +string string_human_readable_size(size_t size); +/* Make a string from a unitless quantity in human readable form */ +string string_human_readable_number(size_t num); + CCL_NAMESPACE_END #endif /* __UTIL_STRING_H__ */ diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 4ff0ee91d73..d5fac9a0e34 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -15,7 +15,9 @@ */ #include "util_system.h" + #include "util_debug.h" +#include "util_logging.h" #include "util_types.h" #include "util_string.h" @@ -33,28 +35,56 @@ CCL_NAMESPACE_BEGIN -int system_cpu_thread_count() +int system_cpu_group_count() { - static uint count = 0; - - if(count > 0) - return count; +#ifdef _WIN32 + util_windows_init_numa_groups(); + return GetActiveProcessorGroupCount(); +#else + /* TODO(sergey): Need to adopt for other platforms. */ + return 1; +#endif +} +int system_cpu_group_thread_count(int group) +{ + /* TODO(sergey): Need make other platforms aware of groups. */ #ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - count = (uint)info.dwNumberOfProcessors; + util_windows_init_numa_groups(); + return GetActiveProcessorCount(group); #elif defined(__APPLE__) + (void)group; + int count; size_t len = sizeof(count); int mib[2] = { CTL_HW, HW_NCPU }; - sysctl(mib, 2, &count, &len, NULL, 0); + return count; #else - count = (uint)sysconf(_SC_NPROCESSORS_ONLN); + (void)group; + return sysconf(_SC_NPROCESSORS_ONLN); #endif +} + +int system_cpu_thread_count() +{ + static uint count = 0; - if(count < 1) + if(count > 0) { + return count; + } + + int max_group = system_cpu_group_count(); + VLOG(1) << "Detected " << max_group << " CPU groups."; + for(int group = 0; group < max_group; ++group) { + int num_threads = system_cpu_group_thread_count(group); + VLOG(1) << "Group " << group + << " has " << num_threads << " threads."; + count += num_threads; + } + + if(count < 1) { count = 1; + } return count; } diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h index 4e7e00f85fd..557aab6cbae 100644 --- a/intern/cycles/util/util_system.h +++ b/intern/cycles/util/util_system.h @@ -21,7 +21,15 @@ CCL_NAMESPACE_BEGIN +/* Get number of available CPU groups. */ +int system_cpu_group_count(); + +/* Get number of threads/processors in the specified group. */ +int system_cpu_group_thread_count(int group); + +/* Get total number of threads in all groups. */ int system_cpu_thread_count(); + string system_cpu_brand_string(); int system_cpu_bits(); bool system_cpu_support_sse2(); diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index d86aa8a4a46..352ba81c95a 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -16,6 +16,7 @@ #include "util_debug.h" #include "util_foreach.h" +#include "util_logging.h" #include "util_system.h" #include "util_task.h" #include "util_time.h" @@ -198,12 +199,30 @@ void TaskScheduler::init(int num_threads) /* automatic number of threads */ num_threads = system_cpu_thread_count(); } + VLOG(1) << "Creating pool of " << num_threads << " threads."; /* launch threads that will be waiting for work */ threads.resize(num_threads); - for(size_t i = 0; i < threads.size(); i++) - threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1)); + int num_groups = system_cpu_group_count(); + int thread_index = 0; + for(int group = 0; group < num_groups; ++group) { + /* NOTE: That's not really efficient from threading point of view, + * but it is simple to read and it doesn't make sense to use more + * user-specified threads than logical threads anyway. + */ + int num_group_threads = (group == num_groups - 1) + ? (threads.size() - thread_index) + : system_cpu_group_thread_count(group); + for(int group_thread = 0; + group_thread < num_group_threads && thread_index < threads.size(); + ++group_thread, ++thread_index) + { + threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, + thread_index + 1), + group); + } + } } users++; diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index 6da47858133..2ef47283029 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -19,43 +19,63 @@ CCL_NAMESPACE_BEGIN -/* Texture limits on various devices. */ +/* Texture limits on devices. */ /* CPU */ -#define TEX_NUM_BYTE4_IMAGES_CPU 1024 -#define TEX_NUM_FLOAT4_IMAGES_CPU 1024 -#define TEX_NUM_FLOAT_IMAGES_CPU 1024 -#define TEX_NUM_BYTE_IMAGES_CPU 1024 -#define TEX_IMAGE_BYTE4_START_CPU TEX_NUM_FLOAT4_IMAGES_CPU -#define TEX_IMAGE_FLOAT_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU) -#define TEX_IMAGE_BYTE_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU + TEX_NUM_BYTE_IMAGES_CPU) +#define TEX_NUM_FLOAT4_CPU 1024 +#define TEX_NUM_BYTE4_CPU 1024 +#define TEX_NUM_FLOAT_CPU 1024 +#define TEX_NUM_BYTE_CPU 1024 +#define TEX_NUM_HALF4_CPU 1024 +#define TEX_NUM_HALF_CPU 1024 +#define TEX_START_FLOAT4_CPU 0 +#define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU +#define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU) +#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU) +#define TEX_START_HALF4_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU) +#define TEX_START_HALF_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU + TEX_NUM_HALF4_CPU) -/* CUDA (Fermi) */ -#define TEX_NUM_BYTE4_IMAGES_CUDA 88 -#define TEX_NUM_FLOAT4_IMAGES_CUDA 5 -#define TEX_NUM_FLOAT_IMAGES_CUDA 0 -#define TEX_NUM_BYTE_IMAGES_CUDA 0 -#define TEX_IMAGE_BYTE4_START_CUDA TEX_NUM_FLOAT4_IMAGES_CUDA -#define TEX_IMAGE_FLOAT_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA) -#define TEX_IMAGE_BYTE_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA + TEX_NUM_BYTE_IMAGES_CUDA) +/* CUDA (Geforce 4xx and 5xx) */ +#define TEX_NUM_FLOAT4_CUDA 5 +#define TEX_NUM_BYTE4_CUDA 88 +#define TEX_NUM_FLOAT_CUDA 0 +#define TEX_NUM_BYTE_CUDA 0 +#define TEX_NUM_HALF4_CUDA 0 +#define TEX_NUM_HALF_CUDA 0 +#define TEX_START_FLOAT4_CUDA 0 +#define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA +#define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA) +#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA) +#define TEX_START_HALF4_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA) +#define TEX_START_HALF_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA + TEX_NUM_HALF4_CUDA) -/* CUDA (KEPLER and above) */ -#define TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER 1024 -#define TEX_NUM_BYTE_IMAGES_CUDA_KEPLER 1024 -#define TEX_IMAGE_BYTE4_START_CUDA_KEPLER TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER -#define TEX_IMAGE_FLOAT_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER) -#define TEX_IMAGE_BYTE_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE_IMAGES_CUDA_KEPLER) +/* CUDA (Kepler, Geforce 6xx and above) */ +#define TEX_NUM_FLOAT4_CUDA_KEPLER 1024 +#define TEX_NUM_BYTE4_CUDA_KEPLER 1024 +#define TEX_NUM_FLOAT_CUDA_KEPLER 1024 +#define TEX_NUM_BYTE_CUDA_KEPLER 1024 +#define TEX_NUM_HALF4_CUDA_KEPLER 0 +#define TEX_NUM_HALF_CUDA_KEPLER 0 +#define TEX_START_FLOAT4_CUDA_KEPLER 0 +#define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER +#define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER) +#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER) +#define TEX_START_HALF4_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) +#define TEX_START_HALF_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER) /* OpenCL */ -#define TEX_NUM_BYTE4_IMAGES_OPENCL 1024 -#define TEX_NUM_FLOAT4_IMAGES_OPENCL 1024 -#define TEX_NUM_FLOAT_IMAGES_OPENCL 0 -#define TEX_NUM_BYTE_IMAGES_OPENCL 0 -#define TEX_IMAGE_BYTE4_START_OPENCL TEX_NUM_FLOAT4_IMAGES_OPENCL -#define TEX_IMAGE_FLOAT_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL) -#define TEX_IMAGE_BYTE_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL + TEX_NUM_BYTE_IMAGES_OPENCL) +#define TEX_NUM_FLOAT4_OPENCL 1024 +#define TEX_NUM_BYTE4_OPENCL 1024 +#define TEX_NUM_FLOAT_OPENCL 0 +#define TEX_NUM_BYTE_OPENCL 0 +#define TEX_NUM_HALF4_OPENCL 0 +#define TEX_NUM_HALF_OPENCL 0 +#define TEX_START_FLOAT4_OPENCL 0 +#define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL +#define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL) +#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL) +#define TEX_START_HALF4_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL) +#define TEX_START_HALF_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL + TEX_NUM_HALF4_OPENCL) /* Color to use when textures are not found. */ diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp new file mode 100644 index 00000000000..3db8b4bd197 --- /dev/null +++ b/intern/cycles/util/util_thread.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include "util_thread.h" + +#include "util_system.h" +#include "util_windows.h" + +CCL_NAMESPACE_BEGIN + +thread::thread(function<void(void)> run_cb, int group) + : run_cb_(run_cb), + joined_(false), + group_(group) +{ + pthread_create(&pthread_id_, NULL, run, (void*)this); +} + +thread::~thread() +{ + if(!joined_) { + join(); + } +} + +void *thread::run(void *arg) +{ + thread *self = (thread*)(arg); + if(self->group_ != -1) { +#ifdef _WIN32 + HANDLE thread_handle = GetCurrentThread(); + GROUP_AFFINITY group_affinity = { 0 }; + int num_threads = system_cpu_group_thread_count(self->group_); + group_affinity.Group = self->group_; + group_affinity.Mask = (num_threads == 64) + ? -1 + : (1ull << num_threads) - 1; + if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) { + fprintf(stderr, "Error setting thread affinity.\n"); + } +#endif + } + self->run_cb_(); + return NULL; +} + +bool thread::join() +{ + joined_ = true; + return pthread_join(pthread_id_, NULL) == 0; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 59575f31c13..427c633d2ce 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -52,37 +52,17 @@ typedef boost::condition_variable thread_condition_variable; class thread { public: - thread(function<void(void)> run_cb_) + thread(function<void(void)> run_cb, int group = -1); + ~thread(); - { - joined = false; - run_cb = run_cb_; - - pthread_create(&pthread_id, NULL, run, (void*)this); - } - - ~thread() - { - if(!joined) - join(); - } - - static void *run(void *arg) - { - ((thread*)arg)->run_cb(); - return NULL; - } - - bool join() - { - joined = true; - return pthread_join(pthread_id, NULL) == 0; - } + static void *run(void *arg); + bool join(); protected: - function<void(void)> run_cb; - pthread_t pthread_id; - bool joined; + function<void(void)> run_cb_; + pthread_t pthread_id_; + bool joined_; + int group_; }; /* Own wrapper around pthread's spin lock to make it's use easier. */ diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index f01db64a79b..6fed18a3db8 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -127,6 +127,19 @@ ccl_device_inline Transform make_transform(float a, float b, float c, float d, return t; } +/* Constructs a coordinate frame from a normalized normal. */ +ccl_device_inline Transform make_transform_frame(float3 N) +{ + const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N); + const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N); + const float3 dx = normalize((dot(dx0,dx0) > dot(dx1,dx1))? dx0: dx1); + const float3 dy = normalize(cross(N, dx)); + return make_transform(dx.x, dx.y, dx.z, 0.0f, + dy.x, dy.y, dy.z, 0.0f, + N.x , N.y, N.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + #ifndef __KERNEL_GPU__ ccl_device_inline Transform operator*(const Transform a, const Transform b) diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index 972befa185b..257c6ad7491 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -37,6 +37,7 @@ #define ccl_device_noinline static #define ccl_global #define ccl_constant +#define ccl_restrict __restrict #define __KERNEL_WITH_SSE_ALIGN__ #if defined(_WIN32) && !defined(FREE_WINDOWS) diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp new file mode 100644 index 00000000000..ee5b3fd73c0 --- /dev/null +++ b/intern/cycles/util/util_windows.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include "util_windows.h" + +#ifdef _WIN32 + +CCL_NAMESPACE_BEGIN + +#ifdef _M_X64 +# include <VersionHelpers.h> +#endif + +#if _WIN32_WINNT < 0x0601 +tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; +tGetActiveProcessorCount *GetActiveProcessorCount; +tSetThreadGroupAffinity *SetThreadGroupAffinity; +#endif + +static WORD GetActiveProcessorGroupCount_stub() +{ + return 1; +} + +static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/) +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; +} + +static BOOL SetThreadGroupAffinity_stub( + HANDLE /*hThread*/, + const GROUP_AFFINITY * /*GroupAffinity*/, + PGROUP_AFFINITY /*PreviousGroupAffinity*/) +{ + return TRUE; +} + +static bool supports_numa() +{ +#ifndef _M_X64 + return false; +#else + return IsWindows7OrGreater(); +#endif +} + +void util_windows_init_numa_groups() +{ + static bool initialized = false; + if(initialized) { + return; + } + initialized = true; +#if _WIN32_WINNT < 0x0601 + if(!supports_numa()) { + /* Use stubs on platforms which doesn't have rean NUMA/Groups. */ + GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub; + GetActiveProcessorCount = GetActiveProcessorCount_stub; + SetThreadGroupAffinity = SetThreadGroupAffinity_stub; + return; + } + HMODULE kernel = GetModuleHandleA("kernel32.dll"); +# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym) + READ_SYMBOL(GetActiveProcessorGroupCount); + READ_SYMBOL(GetActiveProcessorCount); + READ_SYMBOL(SetThreadGroupAffinity); +# undef READ_SUMBOL +#endif +} + +CCL_NAMESPACE_END + +#endif /* _WIN32 */ diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h index f67e34d0f31..ac61d5348c3 100644 --- a/intern/cycles/util/util_windows.h +++ b/intern/cycles/util/util_windows.h @@ -31,6 +31,25 @@ #include <windows.h> +CCL_NAMESPACE_BEGIN + +#if _WIN32_WINNT < 0x0601 +typedef WORD tGetActiveProcessorGroupCount(); +typedef DWORD tGetActiveProcessorCount(WORD GroupNumber); +typedef BOOL tSetThreadGroupAffinity(HANDLE hThread, + const GROUP_AFFINITY *GroupAffinity, + PGROUP_AFFINITY PreviousGroupAffinity); + +extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; +extern tGetActiveProcessorCount *GetActiveProcessorCount; +extern tSetThreadGroupAffinity *SetThreadGroupAffinity; +#endif + +/* Make sure NUMA and processor groups API is initialized. */ +void util_windows_init_numa_groups(); + +CCL_NAMESPACE_END + #endif /* WIN32 */ #endif /* __UTIL_WINDOWS_H__ */ diff --git a/intern/decklink/CMakeLists.txt b/intern/decklink/CMakeLists.txt new file mode 100644 index 00000000000..fbef65cdba4 --- /dev/null +++ b/intern/decklink/CMakeLists.txt @@ -0,0 +1,58 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2015, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Foundation. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC +) + +set(INC_SYS +) + +set(SRC + DeckLinkAPI.cpp + DeckLinkAPI.h +) + +if (WIN32) + list(APPEND SRC + win/DeckLinkAPI_h.h + win/DeckLinkAPI_i.c + ) +endif() + +if (UNIX AND NOT APPLE) + list(APPEND SRC + linux/DeckLinkAPI.h + linux/DeckLinkAPIConfiguration.h + linux/DeckLinkAPIDeckControl.h + linux/DeckLinkAPIDiscovery.h + linux/DeckLinkAPIDispatch.cpp + linux/DeckLinkAPIModes.h + linux/DeckLinkAPIVersion.h + linux/DeckLinkAPITypes.h + linux/LinuxCOM.h + ) +endif() + +blender_add_lib(bf_intern_decklink "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/decklink/DeckLinkAPI.cpp b/intern/decklink/DeckLinkAPI.cpp new file mode 100644 index 00000000000..aff25af70eb --- /dev/null +++ b/intern/decklink/DeckLinkAPI.cpp @@ -0,0 +1,50 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file decklink/DeckLinkAPI.cpp + * \ingroup decklink + */ + +#include "DeckLinkAPI.h" + +#ifdef WIN32 +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void) +{ + HRESULT result; + IDeckLinkIterator* pDLIterator = NULL; + + result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pDLIterator); + if (FAILED(result)) + return NULL; + return pDLIterator; +} +#else +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void) +{ + return CreateDeckLinkIteratorInstance(); +} +#endif // WIN32 diff --git a/intern/decklink/DeckLinkAPI.h b/intern/decklink/DeckLinkAPI.h new file mode 100644 index 00000000000..2a429c18c3c --- /dev/null +++ b/intern/decklink/DeckLinkAPI.h @@ -0,0 +1,56 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file decklink/DeckLinkAPI.h + * \ingroup decklink + */ + +#ifndef __DECKLINKAPI_H__ +#define __DECKLINKAPI_H__ + +/* Include the OS specific Declink headers */ + +#ifdef WIN32 +# include <windows.h> +# include <objbase.h> +# include <comutil.h> +# include "win/DeckLinkAPI_h.h" + typedef unsigned int dl_size_t; +#elif defined(__APPLE__) +# error "Decklink not supported in OSX" +#else +# include "linux/DeckLinkAPI.h" + /* Windows COM API uses BOOL, linux uses bool */ +# define BOOL bool + typedef uint32_t dl_size_t; +#endif + + +/* OS independent function to get the device iterator */ +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void); + +#endif /* __DECKLINKAPI_H__ */ diff --git a/intern/decklink/linux/DeckLinkAPI.h b/intern/decklink/linux/DeckLinkAPI.h new file mode 100644 index 00000000000..08bfba39994 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPI.h @@ -0,0 +1,767 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_H +#define BMD_DECKLINKAPI_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +/* DeckLink API */ + +#include <stdint.h> +#include "LinuxCOM.h" + +#include "DeckLinkAPITypes.h" +#include "DeckLinkAPIModes.h" +#include "DeckLinkAPIDiscovery.h" +#include "DeckLinkAPIConfiguration.h" +#include "DeckLinkAPIDeckControl.h" + +#define BLACKMAGIC_DECKLINK_API_MAGIC 1 + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ {0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE}; +BMD_CONST REFIID IID_IDeckLinkInputCallback = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ {0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A}; +BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ {0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8}; +BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ {0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6}; +BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ {0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA}; +BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ {0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4}; +BMD_CONST REFIID IID_IDeckLinkOutput = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; +BMD_CONST REFIID IID_IDeckLinkInput = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; +BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ {0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17}; +BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ {0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90}; +BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ {0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7}; +BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ {0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44}; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ {0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04}; +BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ {0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}; +BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ {0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38}; +BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ {0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F}; +BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ {0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D}; +BMD_CONST REFIID IID_IDeckLinkNotification = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; +BMD_CONST REFIID IID_IDeckLinkAttributes = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; +BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ {0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3}; +BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ {0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A}; +BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ {0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F}; +BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ {0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01}; + +/* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ + +typedef uint32_t BMDVideoOutputFlags; +enum _BMDVideoOutputFlags { + bmdVideoOutputFlagDefault = 0, + bmdVideoOutputVANC = 1 << 0, + bmdVideoOutputVITC = 1 << 1, + bmdVideoOutputRP188 = 1 << 2, + bmdVideoOutputDualStream3D = 1 << 4 +}; + +/* Enum BMDFrameFlags - Frame flags */ + +typedef uint32_t BMDFrameFlags; +enum _BMDFrameFlags { + bmdFrameFlagDefault = 0, + bmdFrameFlagFlipVertical = 1 << 0, + + /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ + + bmdFrameHasNoInputSource = 1 << 31 +}; + +/* Enum BMDVideoInputFlags - Flags applicable to video input */ + +typedef uint32_t BMDVideoInputFlags; +enum _BMDVideoInputFlags { + bmdVideoInputFlagDefault = 0, + bmdVideoInputEnableFormatDetection = 1 << 0, + bmdVideoInputDualStream3D = 1 << 1 +}; + +/* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ + +typedef uint32_t BMDVideoInputFormatChangedEvents; +enum _BMDVideoInputFormatChangedEvents { + bmdVideoInputDisplayModeChanged = 1 << 0, + bmdVideoInputFieldDominanceChanged = 1 << 1, + bmdVideoInputColorspaceChanged = 1 << 2 +}; + +/* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */ + +typedef uint32_t BMDDetectedVideoInputFormatFlags; +enum _BMDDetectedVideoInputFormatFlags { + bmdDetectedVideoInputYCbCr422 = 1 << 0, + bmdDetectedVideoInputRGB444 = 1 << 1, + bmdDetectedVideoInputDualStream3D = 1 << 2 +}; + +/* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */ + +typedef uint32_t BMDDeckLinkCapturePassthroughMode; +enum _BMDDeckLinkCapturePassthroughMode { + bmdDeckLinkCapturePassthroughModeDirect = /* 'pdir' */ 0x70646972, + bmdDeckLinkCapturePassthroughModeCleanSwitch = /* 'pcln' */ 0x70636C6E +}; + +/* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ + +typedef uint32_t BMDOutputFrameCompletionResult; +enum _BMDOutputFrameCompletionResult { + bmdOutputFrameCompleted, + bmdOutputFrameDisplayedLate, + bmdOutputFrameDropped, + bmdOutputFrameFlushed +}; + +/* Enum BMDReferenceStatus - GenLock input status */ + +typedef uint32_t BMDReferenceStatus; +enum _BMDReferenceStatus { + bmdReferenceNotSupportedByHardware = 1 << 0, + bmdReferenceLocked = 1 << 1 +}; + +/* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ + +typedef uint32_t BMDAudioSampleRate; +enum _BMDAudioSampleRate { + bmdAudioSampleRate48kHz = 48000 +}; + +/* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */ + +typedef uint32_t BMDAudioSampleType; +enum _BMDAudioSampleType { + bmdAudioSampleType16bitInteger = 16, + bmdAudioSampleType32bitInteger = 32 +}; + +/* Enum BMDAudioOutputStreamType - Audio output stream type */ + +typedef uint32_t BMDAudioOutputStreamType; +enum _BMDAudioOutputStreamType { + bmdAudioOutputStreamContinuous, + bmdAudioOutputStreamContinuousDontResample, + bmdAudioOutputStreamTimestamped +}; + +/* Enum BMDDisplayModeSupport - Output mode supported flags */ + +typedef uint32_t BMDDisplayModeSupport; +enum _BMDDisplayModeSupport { + bmdDisplayModeNotSupported = 0, + bmdDisplayModeSupported, + bmdDisplayModeSupportedWithConversion +}; + +/* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ + +typedef uint32_t BMDTimecodeFormat; +enum _BMDTimecodeFormat { + bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9) + bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) + bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10) + bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1 + bmdTimecodeVITC = /* 'vitc' */ 0x76697463, + bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432, + bmdTimecodeSerial = /* 'seri' */ 0x73657269 +}; + +/* Enum BMDAnalogVideoFlags - Analog video display flags */ + +typedef uint32_t BMDAnalogVideoFlags; +enum _BMDAnalogVideoFlags { + bmdAnalogVideoFlagCompositeSetup75 = 1 << 0, + bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1 +}; + +/* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */ + +typedef uint32_t BMDAudioOutputAnalogAESSwitch; +enum _BMDAudioOutputAnalogAESSwitch { + bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320, + bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67 +}; + +/* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ + +typedef uint32_t BMDVideoOutputConversionMode; +enum _BMDVideoOutputConversionMode { + bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278, + bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068, + bmdVideoOutputHD720toHD1080Conversion = /* '720c' */ 0x37323063, + bmdVideoOutputHardwareLetterboxDownconversion = /* 'HWlb' */ 0x48576C62, + bmdVideoOutputHardwareAnamorphicDownconversion = /* 'HWam' */ 0x4857616D, + bmdVideoOutputHardwareCenterCutDownconversion = /* 'HWcc' */ 0x48576363, + bmdVideoOutputHardware720p1080pCrossconversion = /* 'xcap' */ 0x78636170, + bmdVideoOutputHardwareAnamorphic720pUpconversion = /* 'ua7p' */ 0x75613770, + bmdVideoOutputHardwareAnamorphic1080iUpconversion = /* 'ua1i' */ 0x75613169, + bmdVideoOutputHardwareAnamorphic149To720pUpconversion = /* 'u47p' */ 0x75343770, + bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = /* 'u41i' */ 0x75343169, + bmdVideoOutputHardwarePillarbox720pUpconversion = /* 'up7p' */ 0x75703770, + bmdVideoOutputHardwarePillarbox1080iUpconversion = /* 'up1i' */ 0x75703169 +}; + +/* Enum BMDVideoInputConversionMode - Video input conversion mode */ + +typedef uint32_t BMDVideoInputConversionMode; +enum _BMDVideoInputConversionMode { + bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62, + bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D, + bmdVideoInputLetterboxDownconversionFromHD720 = /* '72lb' */ 0x37326C62, + bmdVideoInputAnamorphicDownconversionFromHD720 = /* '72am' */ 0x3732616D, + bmdVideoInputLetterboxUpconversion = /* 'lbup' */ 0x6C627570, + bmdVideoInputAnamorphicUpconversion = /* 'amup' */ 0x616D7570 +}; + +/* Enum BMDVideo3DPackingFormat - Video 3D packing format */ + +typedef uint32_t BMDVideo3DPackingFormat; +enum _BMDVideo3DPackingFormat { + bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368, + bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C, + bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F, + bmdVideo3DPackingFramePacking = /* 'frpk' */ 0x6672706B, + bmdVideo3DPackingLeftOnly = /* 'left' */ 0x6C656674, + bmdVideo3DPackingRightOnly = /* 'righ' */ 0x72696768 +}; + +/* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */ + +typedef uint32_t BMDIdleVideoOutputOperation; +enum _BMDIdleVideoOutputOperation { + bmdIdleVideoOutputBlack = /* 'blac' */ 0x626C6163, + bmdIdleVideoOutputLastFrame = /* 'lafa' */ 0x6C616661, + bmdIdleVideoOutputDesktop = /* 'desk' */ 0x6465736B +}; + +/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ + +typedef uint32_t BMDDeckLinkAttributeID; +enum _BMDDeckLinkAttributeID { + + /* Flags */ + + BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, + BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, + BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968, + BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, + BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, + BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, + BMDDeckLinkHasAnalogVideoOutputGain = /* 'avog' */ 0x61766F67, + BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = /* 'ovog' */ 0x6F766F67, + BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C, + BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073, + BMDDeckLinkSupportsDesktopDisplay = /* 'extd' */ 0x65787464, + BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164, + BMDDeckLinkSupportsFullDuplex = /* 'fdup' */ 0x66647570, + BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E, + BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61, + BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73, + BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75, + + /* Integers */ + + BMDDeckLinkMaximumAudioChannels = /* 'mach' */ 0x6D616368, + BMDDeckLinkMaximumAnalogAudioChannels = /* 'aach' */ 0x61616368, + BMDDeckLinkNumberOfSubDevices = /* 'nsbd' */ 0x6E736264, + BMDDeckLinkSubDeviceIndex = /* 'subi' */ 0x73756269, + BMDDeckLinkPersistentID = /* 'peid' */ 0x70656964, + BMDDeckLinkTopologicalID = /* 'toid' */ 0x746F6964, + BMDDeckLinkVideoOutputConnections = /* 'vocn' */ 0x766F636E, + BMDDeckLinkVideoInputConnections = /* 'vicn' */ 0x7669636E, + BMDDeckLinkAudioOutputConnections = /* 'aocn' */ 0x616F636E, + BMDDeckLinkAudioInputConnections = /* 'aicn' */ 0x6169636E, + BMDDeckLinkDeviceBusyState = /* 'dbst' */ 0x64627374, + BMDDeckLinkVideoIOSupport = /* 'vios' */ 0x76696F73, // Returns a BMDVideoIOSupport bit field + + /* Floats */ + + BMDDeckLinkVideoInputGainMinimum = /* 'vigm' */ 0x7669676D, + BMDDeckLinkVideoInputGainMaximum = /* 'vigx' */ 0x76696778, + BMDDeckLinkVideoOutputGainMinimum = /* 'vogm' */ 0x766F676D, + BMDDeckLinkVideoOutputGainMaximum = /* 'vogx' */ 0x766F6778, + + /* Strings */ + + BMDDeckLinkSerialPortDeviceName = /* 'slpn' */ 0x736C706E +}; + +/* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ + +typedef uint32_t BMDDeckLinkAPIInformationID; +enum _BMDDeckLinkAPIInformationID { + BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 +}; + +/* Enum BMDDeviceBusyState - Current device busy state */ + +typedef uint32_t BMDDeviceBusyState; +enum _BMDDeviceBusyState { + bmdDeviceCaptureBusy = 1 << 0, + bmdDevicePlaybackBusy = 1 << 1, + bmdDeviceSerialPortBusy = 1 << 2 +}; + +/* Enum BMDVideoIOSupport - Device video input/output support */ + +typedef uint32_t BMDVideoIOSupport; +enum _BMDVideoIOSupport { + bmdDeviceSupportsCapture = 1 << 0, + bmdDeviceSupportsPlayback = 1 << 1 +}; + +/* Enum BMD3DPreviewFormat - Linked Frame preview format */ + +typedef uint32_t BMD3DPreviewFormat; +enum _BMD3DPreviewFormat { + bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661, + bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674, + bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768, + bmd3DPreviewFormatSideBySide = /* 'side' */ 0x73696465, + bmd3DPreviewFormatTopBottom = /* 'topb' */ 0x746F7062 +}; + +/* Enum BMDNotifications - Events that can be subscribed through IDeckLinkNotification */ + +typedef uint32_t BMDNotifications; +enum _BMDNotifications { + bmdPreferencesChanged = /* 'pref' */ 0x70726566 +}; + +#if defined(__cplusplus) + +// Forward Declarations + +class IDeckLinkVideoOutputCallback; +class IDeckLinkInputCallback; +class IDeckLinkMemoryAllocator; +class IDeckLinkAudioOutputCallback; +class IDeckLinkIterator; +class IDeckLinkAPIInformation; +class IDeckLinkOutput; +class IDeckLinkInput; +class IDeckLinkVideoFrame; +class IDeckLinkMutableVideoFrame; +class IDeckLinkVideoFrame3DExtensions; +class IDeckLinkVideoInputFrame; +class IDeckLinkVideoFrameAncillary; +class IDeckLinkAudioInputPacket; +class IDeckLinkScreenPreviewCallback; +class IDeckLinkGLScreenPreviewHelper; +class IDeckLinkNotificationCallback; +class IDeckLinkNotification; +class IDeckLinkAttributes; +class IDeckLinkKeyer; +class IDeckLinkVideoConversion; +class IDeckLinkDeviceNotificationCallback; +class IDeckLinkDiscovery; + +/* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */ + +class IDeckLinkVideoOutputCallback : public IUnknown +{ +public: + virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; + virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; + +protected: + virtual ~IDeckLinkVideoOutputCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInputCallback - Frame arrival callback. */ + +class IDeckLinkInputCallback : public IUnknown +{ +public: + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; + +protected: + virtual ~IDeckLinkInputCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */ + +class IDeckLinkMemoryAllocator : public IUnknown +{ +public: + virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; + virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; + + virtual HRESULT Commit (void) = 0; + virtual HRESULT Decommit (void) = 0; +}; + +/* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */ + +class IDeckLinkAudioOutputCallback : public IUnknown +{ +public: + virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; +}; + +/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ + +class IDeckLinkIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; +}; + +/* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ + +class IDeckLinkAPIInformation : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkAPIInformation () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkOutput : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + + virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkInput : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */ + +class IDeckLinkVideoFrame : public IUnknown +{ +public: + virtual long GetWidth (void) = 0; + virtual long GetHeight (void) = 0; + virtual long GetRowBytes (void) = 0; + virtual BMDPixelFormat GetPixelFormat (void) = 0; + virtual BMDFrameFlags GetFlags (void) = 0; + virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; + virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + +protected: + virtual ~IDeckLinkVideoFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */ + +class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame +{ +public: + virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; + + virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; + virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; + virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; + +protected: + virtual ~IDeckLinkMutableVideoFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */ + +class IDeckLinkVideoFrame3DExtensions : public IUnknown +{ +public: + virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; + virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; + +protected: + virtual ~IDeckLinkVideoFrame3DExtensions () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */ + +class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame +{ +public: + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; + +protected: + virtual ~IDeckLinkVideoInputFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ + +class IDeckLinkVideoFrameAncillary : public IUnknown +{ +public: + + virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; + virtual BMDPixelFormat GetPixelFormat (void) = 0; + virtual BMDDisplayMode GetDisplayMode (void) = 0; + +protected: + virtual ~IDeckLinkVideoFrameAncillary () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */ + +class IDeckLinkAudioInputPacket : public IUnknown +{ +public: + virtual long GetSampleFrameCount (void) = 0; + virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; + +protected: + virtual ~IDeckLinkAudioInputPacket () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */ + +class IDeckLinkScreenPreviewCallback : public IUnknown +{ +public: + virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + +protected: + virtual ~IDeckLinkScreenPreviewCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ + +class IDeckLinkGLScreenPreviewHelper : public IUnknown +{ +public: + + /* Methods must be called with OpenGL context set */ + + virtual HRESULT InitializeGL (void) = 0; + virtual HRESULT PaintGL (void) = 0; + virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; + +protected: + virtual ~IDeckLinkGLScreenPreviewHelper () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkNotificationCallback - DeckLink Notification Callback Interface */ + +class IDeckLinkNotificationCallback : public IUnknown +{ +public: + virtual HRESULT Notify (/* in */ BMDNotifications topic, /* in */ uint64_t param1, /* in */ uint64_t param2) = 0; +}; + +/* Interface IDeckLinkNotification - DeckLink Notification interface */ + +class IDeckLinkNotification : public IUnknown +{ +public: + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; +}; + +/* Interface IDeckLinkAttributes - DeckLink Attribute interface */ + +class IDeckLinkAttributes : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkAttributes () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkKeyer - DeckLink Keyer interface */ + +class IDeckLinkKeyer : public IUnknown +{ +public: + virtual HRESULT Enable (/* in */ bool isExternal) = 0; + virtual HRESULT SetLevel (/* in */ uint8_t level) = 0; + virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0; + virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0; + virtual HRESULT Disable (void) = 0; + +protected: + virtual ~IDeckLinkKeyer () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ + +class IDeckLinkVideoConversion : public IUnknown +{ +public: + virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0; + +protected: + virtual ~IDeckLinkVideoConversion () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDeviceNotificationCallback - DeckLink device arrival/removal notification callbacks */ + +class IDeckLinkDeviceNotificationCallback : public IUnknown +{ +public: + virtual HRESULT DeckLinkDeviceArrived (/* in */ IDeckLink* deckLinkDevice) = 0; + virtual HRESULT DeckLinkDeviceRemoved (/* in */ IDeckLink* deckLinkDevice) = 0; + +protected: + virtual ~IDeckLinkDeviceNotificationCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDiscovery - DeckLink device discovery */ + +class IDeckLinkDiscovery : public IUnknown +{ +public: + virtual HRESULT InstallDeviceNotifications (/* in */ IDeckLinkDeviceNotificationCallback* deviceNotificationCallback) = 0; + virtual HRESULT UninstallDeviceNotifications (void) = 0; + +protected: + virtual ~IDeckLinkDiscovery () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + IDeckLinkIterator* CreateDeckLinkIteratorInstance (void); + IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void); + IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void); + IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void); + IDeckLinkVideoConversion* CreateVideoConversionInstance (void); + bool IsDeckLinkAPIPresent (void); +} + + +#endif // defined(__cplusplus) +#endif /* defined(BMD_DECKLINKAPI_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIConfiguration.h b/intern/decklink/linux/DeckLinkAPIConfiguration.h new file mode 100644 index 00000000000..9d5bc9a9e1b --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIConfiguration.h @@ -0,0 +1,192 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPICONFIGURATION_H +#define BMD_DECKLINKAPICONFIGURATION_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 1E69FCF6-4203-4936-8076-2A9F4CFD50CB */ {0x1E,0x69,0xFC,0xF6,0x42,0x03,0x49,0x36,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB}; + +/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ + +typedef uint32_t BMDDeckLinkConfigurationID; +enum _BMDDeckLinkConfigurationID { + + /* Serial port Flags */ + + bmdDeckLinkConfigSwapSerialRxTx = /* 'ssrt' */ 0x73737274, + + /* Video Input/Output Flags */ + + bmdDeckLinkConfigUse1080pNotPsF = /* 'fpro' */ 0x6670726F, + + /* Video Input/Output Integers */ + + bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, + bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073, + bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164, + + /* Audio Input/Output Flags */ + + bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, + + /* Video output flags */ + + bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, + bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, + bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F, + bmdDeckLinkConfigSingleLinkVideoOutput = /* 'sglo' */ 0x73676C6F, + bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63, + bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F, + bmdDeckLinkConfigDownConversionOnAllAnalogOutput = /* 'caao' */ 0x6361616F, + bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461, + + /* Video Output Integers */ + + bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E, + bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D, + bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66, + bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74, + bmdDeckLinkConfigVideoOutputIdleOperation = /* 'voio' */ 0x766F696F, + bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D, + bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66, + + /* Video Output Floats */ + + bmdDeckLinkConfigVideoOutputComponentLumaGain = /* 'oclg' */ 0x6F636C67, + bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = /* 'occb' */ 0x6F636362, + bmdDeckLinkConfigVideoOutputComponentChromaRedGain = /* 'occr' */ 0x6F636372, + bmdDeckLinkConfigVideoOutputCompositeLumaGain = /* 'oilg' */ 0x6F696C67, + bmdDeckLinkConfigVideoOutputCompositeChromaGain = /* 'oicg' */ 0x6F696367, + bmdDeckLinkConfigVideoOutputSVideoLumaGain = /* 'oslg' */ 0x6F736C67, + bmdDeckLinkConfigVideoOutputSVideoChromaGain = /* 'oscg' */ 0x6F736367, + + /* Video Input Flags */ + + bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only + bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream + + /* Video Input Integers */ + + bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E, + bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966, + bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D, + bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966, + bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31, + bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, + bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, + bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D, + + /* Video Input Floats */ + + bmdDeckLinkConfigVideoInputComponentLumaGain = /* 'iclg' */ 0x69636C67, + bmdDeckLinkConfigVideoInputComponentChromaBlueGain = /* 'iccb' */ 0x69636362, + bmdDeckLinkConfigVideoInputComponentChromaRedGain = /* 'iccr' */ 0x69636372, + bmdDeckLinkConfigVideoInputCompositeLumaGain = /* 'iilg' */ 0x69696C67, + bmdDeckLinkConfigVideoInputCompositeChromaGain = /* 'iicg' */ 0x69696367, + bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67, + bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367, + + /* Audio Input Integers */ + + bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E, + + /* Audio Input Floats */ + + bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331, + bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332, + bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333, + bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334, + bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973, + + /* Audio Output Integers */ + + bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161, + + /* Audio Output Floats */ + + bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334, + bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73, + + /* Device Information Strings */ + + bmdDeckLinkConfigDeviceInformationLabel = /* 'dila' */ 0x64696C61, + bmdDeckLinkConfigDeviceInformationSerialNumber = /* 'disn' */ 0x6469736E, + bmdDeckLinkConfigDeviceInformationCompany = /* 'dico' */ 0x6469636F, + bmdDeckLinkConfigDeviceInformationPhone = /* 'diph' */ 0x64697068, + bmdDeckLinkConfigDeviceInformationEmail = /* 'diem' */ 0x6469656D, + bmdDeckLinkConfigDeviceInformationDate = /* 'dida' */ 0x64696461 +}; + +// Forward Declarations + +class IDeckLinkConfiguration; + +/* Interface IDeckLinkConfiguration - DeckLink Configuration interface */ + +class IDeckLinkConfiguration : public IUnknown +{ +public: + virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0; + virtual HRESULT WriteConfigurationToPreferences (void) = 0; + +protected: + virtual ~IDeckLinkConfiguration () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDeckControl.h b/intern/decklink/linux/DeckLinkAPIDeckControl.h new file mode 100644 index 00000000000..b83d013129e --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDeckControl.h @@ -0,0 +1,215 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIDECKCONTROL_H +#define BMD_DECKLINKAPIDECKCONTROL_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ {0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF}; +BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ {0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE}; + +/* Enum BMDDeckControlMode - DeckControl mode */ + +typedef uint32_t BMDDeckControlMode; +enum _BMDDeckControlMode { + bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70, + bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263, + bmdDeckControlExportMode = /* 'expm' */ 0x6578706D, + bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D +}; + +/* Enum BMDDeckControlEvent - DeckControl event */ + +typedef uint32_t BMDDeckControlEvent; +enum _BMDDeckControlEvent { + bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted. + + /* Export-To-Tape events */ + + bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. + bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. + + /* Capture events */ + + bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. + bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. +}; + +/* Enum BMDDeckControlVTRControlState - VTR Control state */ + +typedef uint32_t BMDDeckControlVTRControlState; +enum _BMDDeckControlVTRControlState { + bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D, + bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270, + bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272, + bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261, + bmdDeckControlVTRControlShuttleForward = /* 'vtsf' */ 0x76747366, + bmdDeckControlVTRControlShuttleReverse = /* 'vtsr' */ 0x76747372, + bmdDeckControlVTRControlJogForward = /* 'vtjf' */ 0x76746A66, + bmdDeckControlVTRControlJogReverse = /* 'vtjr' */ 0x76746A72, + bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F +}; + +/* Enum BMDDeckControlStatusFlags - Deck Control status flags */ + +typedef uint32_t BMDDeckControlStatusFlags; +enum _BMDDeckControlStatusFlags { + bmdDeckControlStatusDeckConnected = 1 << 0, + bmdDeckControlStatusRemoteMode = 1 << 1, + bmdDeckControlStatusRecordInhibited = 1 << 2, + bmdDeckControlStatusCassetteOut = 1 << 3 +}; + +/* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */ + +typedef uint32_t BMDDeckControlExportModeOpsFlags; +enum _BMDDeckControlExportModeOpsFlags { + bmdDeckControlExportModeInsertVideo = 1 << 0, + bmdDeckControlExportModeInsertAudio1 = 1 << 1, + bmdDeckControlExportModeInsertAudio2 = 1 << 2, + bmdDeckControlExportModeInsertAudio3 = 1 << 3, + bmdDeckControlExportModeInsertAudio4 = 1 << 4, + bmdDeckControlExportModeInsertAudio5 = 1 << 5, + bmdDeckControlExportModeInsertAudio6 = 1 << 6, + bmdDeckControlExportModeInsertAudio7 = 1 << 7, + bmdDeckControlExportModeInsertAudio8 = 1 << 8, + bmdDeckControlExportModeInsertAudio9 = 1 << 9, + bmdDeckControlExportModeInsertAudio10 = 1 << 10, + bmdDeckControlExportModeInsertAudio11 = 1 << 11, + bmdDeckControlExportModeInsertAudio12 = 1 << 12, + bmdDeckControlExportModeInsertTimeCode = 1 << 13, + bmdDeckControlExportModeInsertAssemble = 1 << 14, + bmdDeckControlExportModeInsertPreview = 1 << 15, + bmdDeckControlUseManualExport = 1 << 16 +}; + +/* Enum BMDDeckControlError - Deck Control error */ + +typedef uint32_t BMDDeckControlError; +enum _BMDDeckControlError { + bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572, + bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572, + bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572, + bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572, + bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572, + bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F, + bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572, + bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572, + bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572, + bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572, + bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572, + bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663, + bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D, + bmdDeckControlBufferTooSmallError = /* 'btsm' */ 0x6274736D, + bmdDeckControlBadChecksumError = /* 'chks' */ 0x63686B73, + bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572 +}; + +// Forward Declarations + +class IDeckLinkDeckControlStatusCallback; +class IDeckLinkDeckControl; + +/* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */ + +class IDeckLinkDeckControlStatusCallback : public IUnknown +{ +public: + virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0; + virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0; + virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0; + virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0; + +protected: + virtual ~IDeckLinkDeckControlStatusCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDeckControl - Deck Control main interface */ + +class IDeckLinkDeckControl : public IUnknown +{ +public: + virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Close (/* in */ bool standbyOn) = 0; + virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; + virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; + virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecodeString (/* out */ const char **currentTimeCode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; + virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; + virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; + virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; + virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; + virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; + virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; + virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Abort (void) = 0; + virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; + +protected: + virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDiscovery.h b/intern/decklink/linux/DeckLinkAPIDiscovery.h new file mode 100644 index 00000000000..424d9d54b39 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDiscovery.h @@ -0,0 +1,71 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIDISCOVERY_H +#define BMD_DECKLINKAPIDISCOVERY_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ {0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91}; + +// Forward Declarations + +class IDeckLink; + +/* Interface IDeckLink - represents a DeckLink device */ + +class IDeckLink : public IUnknown +{ +public: + virtual HRESULT GetModelName (/* out */ const char **modelName) = 0; + virtual HRESULT GetDisplayName (/* out */ const char **displayName) = 0; + +protected: + virtual ~IDeckLink () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDispatch.cpp b/intern/decklink/linux/DeckLinkAPIDispatch.cpp new file mode 100644 index 00000000000..3cf53f109ac --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDispatch.cpp @@ -0,0 +1,148 @@ +/* -LICENSE-START- +** Copyright (c) 2009 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +**/ + +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <dlfcn.h> +#include <ctype.h> + +#include "DeckLinkAPI.h" + +#define kDeckLinkAPI_Name "libDeckLinkAPI.so" +#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so" + +typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); +typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void); +typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); +typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); +typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void); + +static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; +static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT; + +static bool gLoadedDeckLinkAPI = false; + +static CreateIteratorFunc gCreateIteratorFunc = NULL; +static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL; +static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; +static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; +static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL; + +static void InitDeckLinkAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + + gLoadedDeckLinkAPI = true; + + gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0002"); + if (!gCreateIteratorFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001"); + if (!gCreateAPIInformationFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001"); + if (!gCreateVideoConversionFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0001"); + if (!gCreateDeckLinkDiscoveryFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +static void InitDeckLinkPreviewAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001"); + if (!gCreateOpenGLPreviewFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +bool IsDeckLinkAPIPresent (void) +{ + // If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller + return gLoadedDeckLinkAPI; +} + +IDeckLinkIterator* CreateDeckLinkIteratorInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateIteratorFunc == NULL) + return NULL; + return gCreateIteratorFunc(); +} + +IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateAPIInformationFunc == NULL) + return NULL; + return gCreateAPIInformationFunc(); +} + +IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI); + + if (gCreateOpenGLPreviewFunc == NULL) + return NULL; + return gCreateOpenGLPreviewFunc(); +} + +IDeckLinkVideoConversion* CreateVideoConversionInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoConversionFunc == NULL) + return NULL; + return gCreateVideoConversionFunc(); +} + +IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateDeckLinkDiscoveryFunc == NULL) + return NULL; + return gCreateDeckLinkDiscoveryFunc(); +} diff --git a/intern/decklink/linux/DeckLinkAPIModes.h b/intern/decklink/linux/DeckLinkAPIModes.h new file mode 100644 index 00000000000..394d68c3078 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIModes.h @@ -0,0 +1,191 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIMODES_H +#define BMD_DECKLINKAPIMODES_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ {0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35}; +BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ {0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78}; + +/* Enum BMDDisplayMode - Video display modes */ + +typedef uint32_t BMDDisplayMode; +enum _BMDDisplayMode { + + /* SD Modes */ + + bmdModeNTSC = /* 'ntsc' */ 0x6E747363, + bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown + bmdModePAL = /* 'pal ' */ 0x70616C20, + bmdModeNTSCp = /* 'ntsp' */ 0x6E747370, + bmdModePALp = /* 'palp' */ 0x70616C70, + + /* HD 1080 Modes */ + + bmdModeHD1080p2398 = /* '23ps' */ 0x32337073, + bmdModeHD1080p24 = /* '24ps' */ 0x32347073, + bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, + bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, + bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, + bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, + bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, + bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, + bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, + bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. + + /* HD 720 Modes */ + + bmdModeHD720p50 = /* 'hp50' */ 0x68703530, + bmdModeHD720p5994 = /* 'hp59' */ 0x68703539, + bmdModeHD720p60 = /* 'hp60' */ 0x68703630, + + /* 2k Modes */ + + bmdMode2k2398 = /* '2k23' */ 0x326B3233, + bmdMode2k24 = /* '2k24' */ 0x326B3234, + bmdMode2k25 = /* '2k25' */ 0x326B3235, + + /* DCI Modes (output only) */ + + bmdMode2kDCI2398 = /* '2d23' */ 0x32643233, + bmdMode2kDCI24 = /* '2d24' */ 0x32643234, + bmdMode2kDCI25 = /* '2d25' */ 0x32643235, + + /* 4k Modes */ + + bmdMode4K2160p2398 = /* '4k23' */ 0x346B3233, + bmdMode4K2160p24 = /* '4k24' */ 0x346B3234, + bmdMode4K2160p25 = /* '4k25' */ 0x346B3235, + bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239, + bmdMode4K2160p30 = /* '4k30' */ 0x346B3330, + bmdMode4K2160p50 = /* '4k50' */ 0x346B3530, + bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539, + bmdMode4K2160p60 = /* '4k60' */ 0x346B3630, + + /* DCI Modes (output only) */ + + bmdMode4kDCI2398 = /* '4d23' */ 0x34643233, + bmdMode4kDCI24 = /* '4d24' */ 0x34643234, + bmdMode4kDCI25 = /* '4d25' */ 0x34643235, + + /* Special Modes */ + + bmdModeUnknown = /* 'iunk' */ 0x69756E6B +}; + +/* Enum BMDFieldDominance - Video field dominance */ + +typedef uint32_t BMDFieldDominance; +enum _BMDFieldDominance { + bmdUnknownFieldDominance = 0, + bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772, + bmdUpperFieldFirst = /* 'uppr' */ 0x75707072, + bmdProgressiveFrame = /* 'prog' */ 0x70726F67, + bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620 +}; + +/* Enum BMDPixelFormat - Video pixel formats supported for output/input */ + +typedef uint32_t BMDPixelFormat; +enum _BMDPixelFormat { + bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, + bmdFormat10BitYUV = /* 'v210' */ 0x76323130, + bmdFormat8BitARGB = 32, + bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241, + bmdFormat10BitRGB = /* 'r210' */ 0x72323130, // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 + bmdFormat12BitRGB = /* 'R12B' */ 0x52313242, // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat12BitRGBLE = /* 'R12L' */ 0x5231324C, // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat10BitRGBXLE = /* 'R10l' */ 0x5231306C, // Little-endian 10-bit RGB with SMPTE video levels (64-940) + bmdFormat10BitRGBX = /* 'R10b' */ 0x52313062 // Big-endian 10-bit RGB with SMPTE video levels (64-940) +}; + +/* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ + +typedef uint32_t BMDDisplayModeFlags; +enum _BMDDisplayModeFlags { + bmdDisplayModeSupports3D = 1 << 0, + bmdDisplayModeColorspaceRec601 = 1 << 1, + bmdDisplayModeColorspaceRec709 = 1 << 2 +}; + +// Forward Declarations + +class IDeckLinkDisplayModeIterator; +class IDeckLinkDisplayMode; + +/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ + +class IDeckLinkDisplayModeIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + +protected: + virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDisplayMode - represents a display mode */ + +class IDeckLinkDisplayMode : public IUnknown +{ +public: + virtual HRESULT GetName (/* out */ const char **name) = 0; + virtual BMDDisplayMode GetDisplayMode (void) = 0; + virtual long GetWidth (void) = 0; + virtual long GetHeight (void) = 0; + virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; + virtual BMDFieldDominance GetFieldDominance (void) = 0; + virtual BMDDisplayModeFlags GetFlags (void) = 0; + +protected: + virtual ~IDeckLinkDisplayMode () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIMODES_H) */ diff --git a/intern/decklink/linux/DeckLinkAPITypes.h b/intern/decklink/linux/DeckLinkAPITypes.h new file mode 100644 index 00000000000..55e015f2a3c --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPITypes.h @@ -0,0 +1,110 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPITYPES_H +#define BMD_DECKLINKAPITYPES_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + +typedef int64_t BMDTimeValue; +typedef int64_t BMDTimeScale; +typedef uint32_t BMDTimecodeBCD; +typedef uint32_t BMDTimecodeUserBits; + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ {0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40}; + +/* Enum BMDTimecodeFlags - Timecode flags */ + +typedef uint32_t BMDTimecodeFlags; +enum _BMDTimecodeFlags { + bmdTimecodeFlagDefault = 0, + bmdTimecodeIsDropFrame = 1 << 0, + bmdTimecodeFieldMark = 1 << 1 +}; + +/* Enum BMDVideoConnection - Video connection types */ + +typedef uint32_t BMDVideoConnection; +enum _BMDVideoConnection { + bmdVideoConnectionSDI = 1 << 0, + bmdVideoConnectionHDMI = 1 << 1, + bmdVideoConnectionOpticalSDI = 1 << 2, + bmdVideoConnectionComponent = 1 << 3, + bmdVideoConnectionComposite = 1 << 4, + bmdVideoConnectionSVideo = 1 << 5 +}; + +/* Enum BMDAudioConnection - Audio connection types */ + +typedef uint32_t BMDAudioConnection; +enum _BMDAudioConnection { + bmdAudioConnectionEmbedded = 1 << 0, + bmdAudioConnectionAESEBU = 1 << 1, + bmdAudioConnectionAnalog = 1 << 2, + bmdAudioConnectionAnalogXLR = 1 << 3, + bmdAudioConnectionAnalogRCA = 1 << 4 +}; + +// Forward Declarations + +class IDeckLinkTimecode; + +/* Interface IDeckLinkTimecode - Used for video frame timecode representation. */ + +class IDeckLinkTimecode : public IUnknown +{ +public: + virtual BMDTimecodeBCD GetBCD (void) = 0; + virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; + virtual HRESULT GetString (/* out */ const char **timecode) = 0; + virtual BMDTimecodeFlags GetFlags (void) = 0; + virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; + +protected: + virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPITYPES_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIVersion.h b/intern/decklink/linux/DeckLinkAPIVersion.h new file mode 100644 index 00000000000..cfcc701c427 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIVersion.h @@ -0,0 +1,37 @@ +/* -LICENSE-START- + * ** Copyright (c) 2014 Blackmagic Design + * ** + * ** Permission is hereby granted, free of charge, to any person or organization + * ** obtaining a copy of the software and accompanying documentation covered by + * ** this license (the "Software") to use, reproduce, display, distribute, + * ** execute, and transmit the Software, and to prepare derivative works of the + * ** Software, and to permit third-parties to whom the Software is furnished to + * ** do so, all subject to the following: + * ** + * ** The copyright notices in the Software and this entire statement, including + * ** the above license grant, this restriction and the following disclaimer, + * ** must be included in all copies of the Software, in whole or in part, and + * ** all derivative works of the Software, unless such copies or derivative + * ** works are solely in the form of machine-executable object code generated by + * ** a source language processor. + * ** + * ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * ** DEALINGS IN THE SOFTWARE. + * ** -LICENSE-END- + * */ + +/* DeckLinkAPIVersion.h */ + +#ifndef __DeckLink_API_Version_h__ +#define __DeckLink_API_Version_h__ + +#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a040000 +#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.4" + +#endif // __DeckLink_API_Version_h__ + diff --git a/intern/decklink/linux/LinuxCOM.h b/intern/decklink/linux/LinuxCOM.h new file mode 100644 index 00000000000..ee783bbd58f --- /dev/null +++ b/intern/decklink/linux/LinuxCOM.h @@ -0,0 +1,100 @@ +/* -LICENSE-START- +** Copyright (c) 2009 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef __LINUX_COM_H_ +#define __LINUX_COM_H_ + +struct REFIID +{ + unsigned char byte0; + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; + unsigned char byte5; + unsigned char byte6; + unsigned char byte7; + unsigned char byte8; + unsigned char byte9; + unsigned char byte10; + unsigned char byte11; + unsigned char byte12; + unsigned char byte13; + unsigned char byte14; + unsigned char byte15; +}; + +typedef REFIID CFUUIDBytes; +#define CFUUIDGetUUIDBytes(x) x + +#define _HRESULT_DEFINED +typedef int HRESULT; +typedef unsigned long ULONG; +typedef void *LPVOID; + +#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) +#define FAILED(Status) ((HRESULT)(Status)<0) + +#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR) +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 + +#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_UNEXPECTED ((HRESULT)0x8000FFFFL) +#define E_NOTIMPL ((HRESULT)0x80000001L) +#define E_OUTOFMEMORY ((HRESULT)0x80000002L) +#define E_INVALIDARG ((HRESULT)0x80000003L) +#define E_NOINTERFACE ((HRESULT)0x80000004L) +#define E_POINTER ((HRESULT)0x80000005L) +#define E_HANDLE ((HRESULT)0x80000006L) +#define E_ABORT ((HRESULT)0x80000007L) +#define E_FAIL ((HRESULT)0x80000008L) +#define E_ACCESSDENIED ((HRESULT)0x80000009L) + +#define STDMETHODCALLTYPE + +#define IID_IUnknown (REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} +#define IUnknownUUID IID_IUnknown + +#ifdef __cplusplus +class IUnknown +{ + public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; +}; +#endif + +#endif + diff --git a/intern/decklink/win/DeckLinkAPI_h.h b/intern/decklink/win/DeckLinkAPI_h.h new file mode 100644 index 00000000000..1bd80b6dc95 --- /dev/null +++ b/intern/decklink/win/DeckLinkAPI_h.h @@ -0,0 +1,13323 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Mon Apr 13 20:57:05 2015 + */ +/* Compiler settings for ..\..\include\DeckLinkAPI.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the <rpcndr.h> version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of <rpcndr.h> +#endif // __RPCNDR_H_VERSION__ + + +#ifndef __DeckLinkAPI_h_h__ +#define __DeckLinkAPI_h_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IDeckLinkTimecode_FWD_DEFINED__ +#define __IDeckLinkTimecode_FWD_DEFINED__ +typedef interface IDeckLinkTimecode IDeckLinkTimecode; + +#endif /* __IDeckLinkTimecode_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator IDeckLinkDisplayModeIterator; + +#endif /* __IDeckLinkDisplayModeIterator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode IDeckLinkDisplayMode; + +#endif /* __IDeckLinkDisplayMode_FWD_DEFINED__ */ + + +#ifndef __IDeckLink_FWD_DEFINED__ +#define __IDeckLink_FWD_DEFINED__ +typedef interface IDeckLink IDeckLink; + +#endif /* __IDeckLink_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_FWD_DEFINED__ +#define __IDeckLinkConfiguration_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration IDeckLinkConfiguration; + +#endif /* __IDeckLinkConfiguration_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ +typedef interface IDeckLinkDeckControlStatusCallback IDeckLinkDeckControlStatusCallback; + +#endif /* __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_FWD_DEFINED__ +#define __IDeckLinkDeckControl_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl IDeckLinkDeckControl; + +#endif /* __IDeckLinkDeckControl_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ +#define __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ +typedef interface IBMDStreamingDeviceNotificationCallback IBMDStreamingDeviceNotificationCallback; + +#endif /* __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264InputCallback_FWD_DEFINED__ +#define __IBMDStreamingH264InputCallback_FWD_DEFINED__ +typedef interface IBMDStreamingH264InputCallback IBMDStreamingH264InputCallback; + +#endif /* __IBMDStreamingH264InputCallback_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDiscovery_FWD_DEFINED__ +#define __IBMDStreamingDiscovery_FWD_DEFINED__ +typedef interface IBMDStreamingDiscovery IBMDStreamingDiscovery; + +#endif /* __IBMDStreamingDiscovery_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ +#define __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ +typedef interface IBMDStreamingVideoEncodingMode IBMDStreamingVideoEncodingMode; + +#endif /* __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ +#define __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ +typedef interface IBMDStreamingMutableVideoEncodingMode IBMDStreamingMutableVideoEncodingMode; + +#endif /* __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ +#define __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ +typedef interface IBMDStreamingVideoEncodingModePresetIterator IBMDStreamingVideoEncodingModePresetIterator; + +#endif /* __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceInput_FWD_DEFINED__ +#define __IBMDStreamingDeviceInput_FWD_DEFINED__ +typedef interface IBMDStreamingDeviceInput IBMDStreamingDeviceInput; + +#endif /* __IBMDStreamingDeviceInput_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALPacket_FWD_DEFINED__ +#define __IBMDStreamingH264NALPacket_FWD_DEFINED__ +typedef interface IBMDStreamingH264NALPacket IBMDStreamingH264NALPacket; + +#endif /* __IBMDStreamingH264NALPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingAudioPacket_FWD_DEFINED__ +#define __IBMDStreamingAudioPacket_FWD_DEFINED__ +typedef interface IBMDStreamingAudioPacket IBMDStreamingAudioPacket; + +#endif /* __IBMDStreamingAudioPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ +#define __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ +typedef interface IBMDStreamingMPEG2TSPacket IBMDStreamingMPEG2TSPacket; + +#endif /* __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALParser_FWD_DEFINED__ +#define __IBMDStreamingH264NALParser_FWD_DEFINED__ +typedef interface IBMDStreamingH264NALParser IBMDStreamingH264NALParser; + +#endif /* __IBMDStreamingH264NALParser_FWD_DEFINED__ */ + + +#ifndef __CBMDStreamingDiscovery_FWD_DEFINED__ +#define __CBMDStreamingDiscovery_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CBMDStreamingDiscovery CBMDStreamingDiscovery; +#else +typedef struct CBMDStreamingDiscovery CBMDStreamingDiscovery; +#endif /* __cplusplus */ + +#endif /* __CBMDStreamingDiscovery_FWD_DEFINED__ */ + + +#ifndef __CBMDStreamingH264NALParser_FWD_DEFINED__ +#define __CBMDStreamingH264NALParser_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CBMDStreamingH264NALParser CBMDStreamingH264NALParser; +#else +typedef struct CBMDStreamingH264NALParser CBMDStreamingH264NALParser; +#endif /* __cplusplus */ + +#endif /* __CBMDStreamingH264NALParser_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback IDeckLinkVideoOutputCallback; + +#endif /* __IDeckLinkVideoOutputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_FWD_DEFINED__ +#define __IDeckLinkInputCallback_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback IDeckLinkInputCallback; + +#endif /* __IDeckLinkInputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMemoryAllocator_FWD_DEFINED__ +#define __IDeckLinkMemoryAllocator_FWD_DEFINED__ +typedef interface IDeckLinkMemoryAllocator IDeckLinkMemoryAllocator; + +#endif /* __IDeckLinkMemoryAllocator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioOutputCallback_FWD_DEFINED__ +#define __IDeckLinkAudioOutputCallback_FWD_DEFINED__ +typedef interface IDeckLinkAudioOutputCallback IDeckLinkAudioOutputCallback; + +#endif /* __IDeckLinkAudioOutputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_FWD_DEFINED__ +#define __IDeckLinkIterator_FWD_DEFINED__ +typedef interface IDeckLinkIterator IDeckLinkIterator; + +#endif /* __IDeckLinkIterator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAPIInformation_FWD_DEFINED__ +#define __IDeckLinkAPIInformation_FWD_DEFINED__ +typedef interface IDeckLinkAPIInformation IDeckLinkAPIInformation; + +#endif /* __IDeckLinkAPIInformation_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_FWD_DEFINED__ +#define __IDeckLinkOutput_FWD_DEFINED__ +typedef interface IDeckLinkOutput IDeckLinkOutput; + +#endif /* __IDeckLinkOutput_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_FWD_DEFINED__ +#define __IDeckLinkInput_FWD_DEFINED__ +typedef interface IDeckLinkInput IDeckLinkInput; + +#endif /* __IDeckLinkInput_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame IDeckLinkVideoFrame; + +#endif /* __IDeckLinkVideoFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_FWD_DEFINED__ +#define __IDeckLinkMutableVideoFrame_FWD_DEFINED__ +typedef interface IDeckLinkMutableVideoFrame IDeckLinkMutableVideoFrame; + +#endif /* __IDeckLinkMutableVideoFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ +#define __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame3DExtensions IDeckLinkVideoFrame3DExtensions; + +#endif /* __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame IDeckLinkVideoInputFrame; + +#endif /* __IDeckLinkVideoInputFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ +#define __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrameAncillary IDeckLinkVideoFrameAncillary; + +#endif /* __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_FWD_DEFINED__ +#define __IDeckLinkAudioInputPacket_FWD_DEFINED__ +typedef interface IDeckLinkAudioInputPacket IDeckLinkAudioInputPacket; + +#endif /* __IDeckLinkAudioInputPacket_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ +typedef interface IDeckLinkScreenPreviewCallback IDeckLinkScreenPreviewCallback; + +#endif /* __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +typedef interface IDeckLinkGLScreenPreviewHelper IDeckLinkGLScreenPreviewHelper; + +#endif /* __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +#define __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +typedef interface IDeckLinkDX9ScreenPreviewHelper IDeckLinkDX9ScreenPreviewHelper; + +#endif /* __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkNotificationCallback_FWD_DEFINED__ +#define __IDeckLinkNotificationCallback_FWD_DEFINED__ +typedef interface IDeckLinkNotificationCallback IDeckLinkNotificationCallback; + +#endif /* __IDeckLinkNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkNotification_FWD_DEFINED__ +#define __IDeckLinkNotification_FWD_DEFINED__ +typedef interface IDeckLinkNotification IDeckLinkNotification; + +#endif /* __IDeckLinkNotification_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAttributes_FWD_DEFINED__ +#define __IDeckLinkAttributes_FWD_DEFINED__ +typedef interface IDeckLinkAttributes IDeckLinkAttributes; + +#endif /* __IDeckLinkAttributes_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkKeyer_FWD_DEFINED__ +#define __IDeckLinkKeyer_FWD_DEFINED__ +typedef interface IDeckLinkKeyer IDeckLinkKeyer; + +#endif /* __IDeckLinkKeyer_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_FWD_DEFINED__ +#define __IDeckLinkVideoConversion_FWD_DEFINED__ +typedef interface IDeckLinkVideoConversion IDeckLinkVideoConversion; + +#endif /* __IDeckLinkVideoConversion_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ +#define __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ +typedef interface IDeckLinkDeviceNotificationCallback IDeckLinkDeviceNotificationCallback; + +#endif /* __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDiscovery_FWD_DEFINED__ +#define __IDeckLinkDiscovery_FWD_DEFINED__ +typedef interface IDeckLinkDiscovery IDeckLinkDiscovery; + +#endif /* __IDeckLinkDiscovery_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkIterator_FWD_DEFINED__ +#define __CDeckLinkIterator_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkIterator CDeckLinkIterator; +#else +typedef struct CDeckLinkIterator CDeckLinkIterator; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkIterator_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkAPIInformation_FWD_DEFINED__ +#define __CDeckLinkAPIInformation_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkAPIInformation CDeckLinkAPIInformation; +#else +typedef struct CDeckLinkAPIInformation CDeckLinkAPIInformation; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkAPIInformation_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +#define __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; +#else +typedef struct CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +#define __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper; +#else +typedef struct CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkVideoConversion_FWD_DEFINED__ +#define __CDeckLinkVideoConversion_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkVideoConversion CDeckLinkVideoConversion; +#else +typedef struct CDeckLinkVideoConversion CDeckLinkVideoConversion; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkVideoConversion_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkDiscovery_FWD_DEFINED__ +#define __CDeckLinkDiscovery_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkDiscovery CDeckLinkDiscovery; +#else +typedef struct CDeckLinkDiscovery CDeckLinkDiscovery; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkDiscovery_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ +#define __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration_v10_2 IDeckLinkConfiguration_v10_2; + +#endif /* __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v9_9_FWD_DEFINED__ +#define __IDeckLinkOutput_v9_9_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v9_9 IDeckLinkOutput_v9_9; + +#endif /* __IDeckLinkOutput_v9_9_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v9_2_FWD_DEFINED__ +#define __IDeckLinkInput_v9_2_FWD_DEFINED__ +typedef interface IDeckLinkInput_v9_2 IDeckLinkInput_v9_2; + +#endif /* __IDeckLinkInput_v9_2_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ +typedef interface IDeckLinkDeckControlStatusCallback_v8_1 IDeckLinkDeckControlStatusCallback_v8_1; + +#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ +#define __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl_v8_1 IDeckLinkDeckControl_v8_1; + +#endif /* __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLink_v8_0_FWD_DEFINED__ +#define __IDeckLink_v8_0_FWD_DEFINED__ +typedef interface IDeckLink_v8_0 IDeckLink_v8_0; + +#endif /* __IDeckLink_v8_0_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_v8_0_FWD_DEFINED__ +#define __IDeckLinkIterator_v8_0_FWD_DEFINED__ +typedef interface IDeckLinkIterator_v8_0 IDeckLinkIterator_v8_0; + +#endif /* __IDeckLinkIterator_v8_0_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkIterator_v8_0_FWD_DEFINED__ +#define __CDeckLinkIterator_v8_0_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0; +#else +typedef struct CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkIterator_v8_0_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ +#define __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl_v7_9 IDeckLinkDeckControl_v7_9; + +#endif /* __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator_v7_6 IDeckLinkDisplayModeIterator_v7_6; + +#endif /* __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode_v7_6 IDeckLinkDisplayMode_v7_6; + +#endif /* __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_6_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_6 IDeckLinkOutput_v7_6; + +#endif /* __IDeckLinkOutput_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_6_FWD_DEFINED__ +#define __IDeckLinkInput_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_6 IDeckLinkInput_v7_6; + +#endif /* __IDeckLinkInput_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkTimecode_v7_6_FWD_DEFINED__ +#define __IDeckLinkTimecode_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkTimecode_v7_6 IDeckLinkTimecode_v7_6; + +#endif /* __IDeckLinkTimecode_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame_v7_6 IDeckLinkVideoFrame_v7_6; + +#endif /* __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkMutableVideoFrame_v7_6 IDeckLinkMutableVideoFrame_v7_6; + +#endif /* __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_6 IDeckLinkVideoInputFrame_v7_6; + +#endif /* __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkScreenPreviewCallback_v7_6 IDeckLinkScreenPreviewCallback_v7_6; + +#endif /* __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkGLScreenPreviewHelper_v7_6 IDeckLinkGLScreenPreviewHelper_v7_6; + +#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoConversion_v7_6 IDeckLinkVideoConversion_v7_6; + +#endif /* __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ +#define __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration_v7_6 IDeckLinkConfiguration_v7_6; + +#endif /* __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback_v7_6 IDeckLinkVideoOutputCallback_v7_6; + +#endif /* __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_6 IDeckLinkInputCallback_v7_6; + +#endif /* __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +#define __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; +#else +typedef struct CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +#define __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; +#else +typedef struct CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_3 IDeckLinkInputCallback_v7_3; + +#endif /* __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_3_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_3 IDeckLinkOutput_v7_3; + +#endif /* __IDeckLinkOutput_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_3_FWD_DEFINED__ +#define __IDeckLinkInput_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_3 IDeckLinkInput_v7_3; + +#endif /* __IDeckLinkInput_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_3 IDeckLinkVideoInputFrame_v7_3; + +#endif /* __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator_v7_1 IDeckLinkDisplayModeIterator_v7_1; + +#endif /* __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode_v7_1 IDeckLinkDisplayMode_v7_1; + +#endif /* __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame_v7_1 IDeckLinkVideoFrame_v7_1; + +#endif /* __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_1 IDeckLinkVideoInputFrame_v7_1; + +#endif /* __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ +#define __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkAudioInputPacket_v7_1 IDeckLinkAudioInputPacket_v7_1; + +#endif /* __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback_v7_1 IDeckLinkVideoOutputCallback_v7_1; + +#endif /* __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_1 IDeckLinkInputCallback_v7_1; + +#endif /* __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_1_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_1 IDeckLinkOutput_v7_1; + +#endif /* __IDeckLinkOutput_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_1_FWD_DEFINED__ +#define __IDeckLinkInput_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_1 IDeckLinkInput_v7_1; + +#endif /* __IDeckLinkInput_v7_1_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + + +#ifndef __DeckLinkAPI_LIBRARY_DEFINED__ +#define __DeckLinkAPI_LIBRARY_DEFINED__ + +/* library DeckLinkAPI */ +/* [helpstring][version][uuid] */ + +typedef LONGLONG BMDTimeValue; + +typedef LONGLONG BMDTimeScale; + +typedef unsigned int BMDTimecodeBCD; + +typedef unsigned int BMDTimecodeUserBits; + +typedef unsigned int BMDTimecodeFlags; +#if 0 +typedef enum _BMDTimecodeFlags BMDTimecodeFlags; + +#endif +/* [v1_enum] */ +enum _BMDTimecodeFlags + { + bmdTimecodeFlagDefault = 0, + bmdTimecodeIsDropFrame = ( 1 << 0 ) , + bmdTimecodeFieldMark = ( 1 << 1 ) + } ; +typedef /* [v1_enum] */ +enum _BMDVideoConnection + { + bmdVideoConnectionSDI = ( 1 << 0 ) , + bmdVideoConnectionHDMI = ( 1 << 1 ) , + bmdVideoConnectionOpticalSDI = ( 1 << 2 ) , + bmdVideoConnectionComponent = ( 1 << 3 ) , + bmdVideoConnectionComposite = ( 1 << 4 ) , + bmdVideoConnectionSVideo = ( 1 << 5 ) + } BMDVideoConnection; + +typedef /* [v1_enum] */ +enum _BMDAudioConnection + { + bmdAudioConnectionEmbedded = ( 1 << 0 ) , + bmdAudioConnectionAESEBU = ( 1 << 1 ) , + bmdAudioConnectionAnalog = ( 1 << 2 ) , + bmdAudioConnectionAnalogXLR = ( 1 << 3 ) , + bmdAudioConnectionAnalogRCA = ( 1 << 4 ) + } BMDAudioConnection; + + +typedef unsigned int BMDDisplayModeFlags; +#if 0 +typedef enum _BMDDisplayModeFlags BMDDisplayModeFlags; + +#endif +typedef /* [v1_enum] */ +enum _BMDDisplayMode + { + bmdModeNTSC = 0x6e747363, + bmdModeNTSC2398 = 0x6e743233, + bmdModePAL = 0x70616c20, + bmdModeNTSCp = 0x6e747370, + bmdModePALp = 0x70616c70, + bmdModeHD1080p2398 = 0x32337073, + bmdModeHD1080p24 = 0x32347073, + bmdModeHD1080p25 = 0x48703235, + bmdModeHD1080p2997 = 0x48703239, + bmdModeHD1080p30 = 0x48703330, + bmdModeHD1080i50 = 0x48693530, + bmdModeHD1080i5994 = 0x48693539, + bmdModeHD1080i6000 = 0x48693630, + bmdModeHD1080p50 = 0x48703530, + bmdModeHD1080p5994 = 0x48703539, + bmdModeHD1080p6000 = 0x48703630, + bmdModeHD720p50 = 0x68703530, + bmdModeHD720p5994 = 0x68703539, + bmdModeHD720p60 = 0x68703630, + bmdMode2k2398 = 0x326b3233, + bmdMode2k24 = 0x326b3234, + bmdMode2k25 = 0x326b3235, + bmdMode2kDCI2398 = 0x32643233, + bmdMode2kDCI24 = 0x32643234, + bmdMode2kDCI25 = 0x32643235, + bmdMode4K2160p2398 = 0x346b3233, + bmdMode4K2160p24 = 0x346b3234, + bmdMode4K2160p25 = 0x346b3235, + bmdMode4K2160p2997 = 0x346b3239, + bmdMode4K2160p30 = 0x346b3330, + bmdMode4K2160p50 = 0x346b3530, + bmdMode4K2160p5994 = 0x346b3539, + bmdMode4K2160p60 = 0x346b3630, + bmdMode4kDCI2398 = 0x34643233, + bmdMode4kDCI24 = 0x34643234, + bmdMode4kDCI25 = 0x34643235, + bmdModeUnknown = 0x69756e6b + } BMDDisplayMode; + +typedef /* [v1_enum] */ +enum _BMDFieldDominance + { + bmdUnknownFieldDominance = 0, + bmdLowerFieldFirst = 0x6c6f7772, + bmdUpperFieldFirst = 0x75707072, + bmdProgressiveFrame = 0x70726f67, + bmdProgressiveSegmentedFrame = 0x70736620 + } BMDFieldDominance; + +typedef /* [v1_enum] */ +enum _BMDPixelFormat + { + bmdFormat8BitYUV = 0x32767579, + bmdFormat10BitYUV = 0x76323130, + bmdFormat8BitARGB = 32, + bmdFormat8BitBGRA = 0x42475241, + bmdFormat10BitRGB = 0x72323130, + bmdFormat12BitRGB = 0x52313242, + bmdFormat12BitRGBLE = 0x5231324c, + bmdFormat10BitRGBXLE = 0x5231306c, + bmdFormat10BitRGBX = 0x52313062 + } BMDPixelFormat; + +/* [v1_enum] */ +enum _BMDDisplayModeFlags + { + bmdDisplayModeSupports3D = ( 1 << 0 ) , + bmdDisplayModeColorspaceRec601 = ( 1 << 1 ) , + bmdDisplayModeColorspaceRec709 = ( 1 << 2 ) + } ; + + +#if 0 +#endif + +#if 0 +#endif +typedef /* [v1_enum] */ +enum _BMDDeckLinkConfigurationID + { + bmdDeckLinkConfigSwapSerialRxTx = 0x73737274, + bmdDeckLinkConfigUse1080pNotPsF = 0x6670726f, + bmdDeckLinkConfigHDMI3DPackingFormat = 0x33647066, + bmdDeckLinkConfigBypass = 0x62797073, + bmdDeckLinkConfigClockTimingAdjustment = 0x63746164, + bmdDeckLinkConfigAnalogAudioConsumerLevels = 0x6161636c, + bmdDeckLinkConfigFieldFlickerRemoval = 0x66646672, + bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 0x746f3539, + bmdDeckLinkConfig444SDIVideoOutput = 0x3434346f, + bmdDeckLinkConfigSingleLinkVideoOutput = 0x73676c6f, + bmdDeckLinkConfigBlackVideoOutputDuringCapture = 0x62766f63, + bmdDeckLinkConfigLowLatencyVideoOutput = 0x6c6c766f, + bmdDeckLinkConfigDownConversionOnAllAnalogOutput = 0x6361616f, + bmdDeckLinkConfigSMPTELevelAOutput = 0x736d7461, + bmdDeckLinkConfigVideoOutputConnection = 0x766f636e, + bmdDeckLinkConfigVideoOutputConversionMode = 0x766f636d, + bmdDeckLinkConfigAnalogVideoOutputFlags = 0x61766f66, + bmdDeckLinkConfigReferenceInputTimingOffset = 0x676c6f74, + bmdDeckLinkConfigVideoOutputIdleOperation = 0x766f696f, + bmdDeckLinkConfigDefaultVideoOutputMode = 0x64766f6d, + bmdDeckLinkConfigDefaultVideoOutputModeFlags = 0x64766f66, + bmdDeckLinkConfigVideoOutputComponentLumaGain = 0x6f636c67, + bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = 0x6f636362, + bmdDeckLinkConfigVideoOutputComponentChromaRedGain = 0x6f636372, + bmdDeckLinkConfigVideoOutputCompositeLumaGain = 0x6f696c67, + bmdDeckLinkConfigVideoOutputCompositeChromaGain = 0x6f696367, + bmdDeckLinkConfigVideoOutputSVideoLumaGain = 0x6f736c67, + bmdDeckLinkConfigVideoOutputSVideoChromaGain = 0x6f736367, + bmdDeckLinkConfigVideoInputScanning = 0x76697363, + bmdDeckLinkConfigUseDedicatedLTCInput = 0x646c7463, + bmdDeckLinkConfigVideoInputConnection = 0x7669636e, + bmdDeckLinkConfigAnalogVideoInputFlags = 0x61766966, + bmdDeckLinkConfigVideoInputConversionMode = 0x7669636d, + bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 0x70646966, + bmdDeckLinkConfigVANCSourceLine1Mapping = 0x76736c31, + bmdDeckLinkConfigVANCSourceLine2Mapping = 0x76736c32, + bmdDeckLinkConfigVANCSourceLine3Mapping = 0x76736c33, + bmdDeckLinkConfigCapturePassThroughMode = 0x6370746d, + bmdDeckLinkConfigVideoInputComponentLumaGain = 0x69636c67, + bmdDeckLinkConfigVideoInputComponentChromaBlueGain = 0x69636362, + bmdDeckLinkConfigVideoInputComponentChromaRedGain = 0x69636372, + bmdDeckLinkConfigVideoInputCompositeLumaGain = 0x69696c67, + bmdDeckLinkConfigVideoInputCompositeChromaGain = 0x69696367, + bmdDeckLinkConfigVideoInputSVideoLumaGain = 0x69736c67, + bmdDeckLinkConfigVideoInputSVideoChromaGain = 0x69736367, + bmdDeckLinkConfigAudioInputConnection = 0x6169636e, + bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 0x61697331, + bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 0x61697332, + bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 0x61697333, + bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 0x61697334, + bmdDeckLinkConfigDigitalAudioInputScale = 0x64616973, + bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 0x616f6161, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 0x616f7331, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 0x616f7332, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 0x616f7333, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 0x616f7334, + bmdDeckLinkConfigDigitalAudioOutputScale = 0x64616f73, + bmdDeckLinkConfigDeviceInformationLabel = 0x64696c61, + bmdDeckLinkConfigDeviceInformationSerialNumber = 0x6469736e, + bmdDeckLinkConfigDeviceInformationCompany = 0x6469636f, + bmdDeckLinkConfigDeviceInformationPhone = 0x64697068, + bmdDeckLinkConfigDeviceInformationEmail = 0x6469656d, + bmdDeckLinkConfigDeviceInformationDate = 0x64696461 + } BMDDeckLinkConfigurationID; + + +typedef unsigned int BMDDeckControlStatusFlags; +typedef unsigned int BMDDeckControlExportModeOpsFlags; +#if 0 +typedef enum _BMDDeckControlStatusFlags BMDDeckControlStatusFlags; + +typedef enum _BMDDeckControlExportModeOpsFlags BMDDeckControlExportModeOpsFlags; + +#endif +typedef /* [v1_enum] */ +enum _BMDDeckControlMode + { + bmdDeckControlNotOpened = 0x6e746f70, + bmdDeckControlVTRControlMode = 0x76747263, + bmdDeckControlExportMode = 0x6578706d, + bmdDeckControlCaptureMode = 0x6361706d + } BMDDeckControlMode; + +typedef /* [v1_enum] */ +enum _BMDDeckControlEvent + { + bmdDeckControlAbortedEvent = 0x61627465, + bmdDeckControlPrepareForExportEvent = 0x70666565, + bmdDeckControlExportCompleteEvent = 0x65786365, + bmdDeckControlPrepareForCaptureEvent = 0x70666365, + bmdDeckControlCaptureCompleteEvent = 0x63636576 + } BMDDeckControlEvent; + +typedef /* [v1_enum] */ +enum _BMDDeckControlVTRControlState + { + bmdDeckControlNotInVTRControlMode = 0x6e76636d, + bmdDeckControlVTRControlPlaying = 0x76747270, + bmdDeckControlVTRControlRecording = 0x76747272, + bmdDeckControlVTRControlStill = 0x76747261, + bmdDeckControlVTRControlShuttleForward = 0x76747366, + bmdDeckControlVTRControlShuttleReverse = 0x76747372, + bmdDeckControlVTRControlJogForward = 0x76746a66, + bmdDeckControlVTRControlJogReverse = 0x76746a72, + bmdDeckControlVTRControlStopped = 0x7674726f + } BMDDeckControlVTRControlState; + +/* [v1_enum] */ +enum _BMDDeckControlStatusFlags + { + bmdDeckControlStatusDeckConnected = ( 1 << 0 ) , + bmdDeckControlStatusRemoteMode = ( 1 << 1 ) , + bmdDeckControlStatusRecordInhibited = ( 1 << 2 ) , + bmdDeckControlStatusCassetteOut = ( 1 << 3 ) + } ; +/* [v1_enum] */ +enum _BMDDeckControlExportModeOpsFlags + { + bmdDeckControlExportModeInsertVideo = ( 1 << 0 ) , + bmdDeckControlExportModeInsertAudio1 = ( 1 << 1 ) , + bmdDeckControlExportModeInsertAudio2 = ( 1 << 2 ) , + bmdDeckControlExportModeInsertAudio3 = ( 1 << 3 ) , + bmdDeckControlExportModeInsertAudio4 = ( 1 << 4 ) , + bmdDeckControlExportModeInsertAudio5 = ( 1 << 5 ) , + bmdDeckControlExportModeInsertAudio6 = ( 1 << 6 ) , + bmdDeckControlExportModeInsertAudio7 = ( 1 << 7 ) , + bmdDeckControlExportModeInsertAudio8 = ( 1 << 8 ) , + bmdDeckControlExportModeInsertAudio9 = ( 1 << 9 ) , + bmdDeckControlExportModeInsertAudio10 = ( 1 << 10 ) , + bmdDeckControlExportModeInsertAudio11 = ( 1 << 11 ) , + bmdDeckControlExportModeInsertAudio12 = ( 1 << 12 ) , + bmdDeckControlExportModeInsertTimeCode = ( 1 << 13 ) , + bmdDeckControlExportModeInsertAssemble = ( 1 << 14 ) , + bmdDeckControlExportModeInsertPreview = ( 1 << 15 ) , + bmdDeckControlUseManualExport = ( 1 << 16 ) + } ; +typedef /* [v1_enum] */ +enum _BMDDeckControlError + { + bmdDeckControlNoError = 0x6e6f6572, + bmdDeckControlModeError = 0x6d6f6572, + bmdDeckControlMissedInPointError = 0x6d696572, + bmdDeckControlDeckTimeoutError = 0x64746572, + bmdDeckControlCommandFailedError = 0x63666572, + bmdDeckControlDeviceAlreadyOpenedError = 0x64616c6f, + bmdDeckControlFailedToOpenDeviceError = 0x66646572, + bmdDeckControlInLocalModeError = 0x6c6d6572, + bmdDeckControlEndOfTapeError = 0x65746572, + bmdDeckControlUserAbortError = 0x75616572, + bmdDeckControlNoTapeInDeckError = 0x6e746572, + bmdDeckControlNoVideoFromCardError = 0x6e766663, + bmdDeckControlNoCommunicationError = 0x6e636f6d, + bmdDeckControlBufferTooSmallError = 0x6274736d, + bmdDeckControlBadChecksumError = 0x63686b73, + bmdDeckControlUnknownError = 0x756e6572 + } BMDDeckControlError; + + + +#if 0 +#endif +typedef /* [v1_enum] */ +enum _BMDStreamingDeviceMode + { + bmdStreamingDeviceIdle = 0x69646c65, + bmdStreamingDeviceEncoding = 0x656e636f, + bmdStreamingDeviceStopping = 0x73746f70, + bmdStreamingDeviceUnknown = 0x6d756e6b + } BMDStreamingDeviceMode; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingFrameRate + { + bmdStreamingEncodedFrameRate50i = 0x65353069, + bmdStreamingEncodedFrameRate5994i = 0x65353969, + bmdStreamingEncodedFrameRate60i = 0x65363069, + bmdStreamingEncodedFrameRate2398p = 0x65323370, + bmdStreamingEncodedFrameRate24p = 0x65323470, + bmdStreamingEncodedFrameRate25p = 0x65323570, + bmdStreamingEncodedFrameRate2997p = 0x65323970, + bmdStreamingEncodedFrameRate30p = 0x65333070, + bmdStreamingEncodedFrameRate50p = 0x65353070, + bmdStreamingEncodedFrameRate5994p = 0x65353970, + bmdStreamingEncodedFrameRate60p = 0x65363070 + } BMDStreamingEncodingFrameRate; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingSupport + { + bmdStreamingEncodingModeNotSupported = 0, + bmdStreamingEncodingModeSupported = ( bmdStreamingEncodingModeNotSupported + 1 ) , + bmdStreamingEncodingModeSupportedWithChanges = ( bmdStreamingEncodingModeSupported + 1 ) + } BMDStreamingEncodingSupport; + +typedef /* [v1_enum] */ +enum _BMDStreamingVideoCodec + { + bmdStreamingVideoCodecH264 = 0x48323634 + } BMDStreamingVideoCodec; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264Profile + { + bmdStreamingH264ProfileHigh = 0x68696768, + bmdStreamingH264ProfileMain = 0x6d61696e, + bmdStreamingH264ProfileBaseline = 0x62617365 + } BMDStreamingH264Profile; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264Level + { + bmdStreamingH264Level12 = 0x6c763132, + bmdStreamingH264Level13 = 0x6c763133, + bmdStreamingH264Level2 = 0x6c763220, + bmdStreamingH264Level21 = 0x6c763231, + bmdStreamingH264Level22 = 0x6c763232, + bmdStreamingH264Level3 = 0x6c763320, + bmdStreamingH264Level31 = 0x6c763331, + bmdStreamingH264Level32 = 0x6c763332, + bmdStreamingH264Level4 = 0x6c763420, + bmdStreamingH264Level41 = 0x6c763431, + bmdStreamingH264Level42 = 0x6c763432 + } BMDStreamingH264Level; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264EntropyCoding + { + bmdStreamingH264EntropyCodingCAVLC = 0x45564c43, + bmdStreamingH264EntropyCodingCABAC = 0x45424143 + } BMDStreamingH264EntropyCoding; + +typedef /* [v1_enum] */ +enum _BMDStreamingAudioCodec + { + bmdStreamingAudioCodecAAC = 0x41414320 + } BMDStreamingAudioCodec; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingModePropertyID + { + bmdStreamingEncodingPropertyVideoFrameRate = 0x76667274, + bmdStreamingEncodingPropertyVideoBitRateKbps = 0x76627274, + bmdStreamingEncodingPropertyH264Profile = 0x68707266, + bmdStreamingEncodingPropertyH264Level = 0x686c766c, + bmdStreamingEncodingPropertyH264EntropyCoding = 0x68656e74, + bmdStreamingEncodingPropertyH264HasBFrames = 0x68426672, + bmdStreamingEncodingPropertyAudioCodec = 0x61636463, + bmdStreamingEncodingPropertyAudioSampleRate = 0x61737274, + bmdStreamingEncodingPropertyAudioChannelCount = 0x61636863, + bmdStreamingEncodingPropertyAudioBitRateKbps = 0x61627274 + } BMDStreamingEncodingModePropertyID; + + + + + + + + + + + + +typedef unsigned int BMDFrameFlags; +typedef unsigned int BMDVideoInputFlags; +typedef unsigned int BMDVideoInputFormatChangedEvents; +typedef unsigned int BMDDetectedVideoInputFormatFlags; +typedef unsigned int BMDDeckLinkCapturePassthroughMode; +typedef unsigned int BMDAnalogVideoFlags; +typedef unsigned int BMDDeviceBusyState; +#if 0 +typedef enum _BMDFrameFlags BMDFrameFlags; + +typedef enum _BMDVideoInputFlags BMDVideoInputFlags; + +typedef enum _BMDVideoInputFormatChangedEvents BMDVideoInputFormatChangedEvents; + +typedef enum _BMDDetectedVideoInputFormatFlags BMDDetectedVideoInputFormatFlags; + +typedef enum _BMDDeckLinkCapturePassthroughMode BMDDeckLinkCapturePassthroughMode; + +typedef enum _BMDAnalogVideoFlags BMDAnalogVideoFlags; + +typedef enum _BMDDeviceBusyState BMDDeviceBusyState; + +#endif +typedef /* [v1_enum] */ +enum _BMDVideoOutputFlags + { + bmdVideoOutputFlagDefault = 0, + bmdVideoOutputVANC = ( 1 << 0 ) , + bmdVideoOutputVITC = ( 1 << 1 ) , + bmdVideoOutputRP188 = ( 1 << 2 ) , + bmdVideoOutputDualStream3D = ( 1 << 4 ) + } BMDVideoOutputFlags; + +/* [v1_enum] */ +enum _BMDFrameFlags + { + bmdFrameFlagDefault = 0, + bmdFrameFlagFlipVertical = ( 1 << 0 ) , + bmdFrameHasNoInputSource = ( 1 << 31 ) + } ; +/* [v1_enum] */ +enum _BMDVideoInputFlags + { + bmdVideoInputFlagDefault = 0, + bmdVideoInputEnableFormatDetection = ( 1 << 0 ) , + bmdVideoInputDualStream3D = ( 1 << 1 ) + } ; +/* [v1_enum] */ +enum _BMDVideoInputFormatChangedEvents + { + bmdVideoInputDisplayModeChanged = ( 1 << 0 ) , + bmdVideoInputFieldDominanceChanged = ( 1 << 1 ) , + bmdVideoInputColorspaceChanged = ( 1 << 2 ) + } ; +/* [v1_enum] */ +enum _BMDDetectedVideoInputFormatFlags + { + bmdDetectedVideoInputYCbCr422 = ( 1 << 0 ) , + bmdDetectedVideoInputRGB444 = ( 1 << 1 ) , + bmdDetectedVideoInputDualStream3D = ( 1 << 2 ) + } ; +/* [v1_enum] */ +enum _BMDDeckLinkCapturePassthroughMode + { + bmdDeckLinkCapturePassthroughModeDirect = 0x70646972, + bmdDeckLinkCapturePassthroughModeCleanSwitch = 0x70636c6e + } ; +typedef /* [v1_enum] */ +enum _BMDOutputFrameCompletionResult + { + bmdOutputFrameCompleted = 0, + bmdOutputFrameDisplayedLate = ( bmdOutputFrameCompleted + 1 ) , + bmdOutputFrameDropped = ( bmdOutputFrameDisplayedLate + 1 ) , + bmdOutputFrameFlushed = ( bmdOutputFrameDropped + 1 ) + } BMDOutputFrameCompletionResult; + +typedef /* [v1_enum] */ +enum _BMDReferenceStatus + { + bmdReferenceNotSupportedByHardware = ( 1 << 0 ) , + bmdReferenceLocked = ( 1 << 1 ) + } BMDReferenceStatus; + +typedef /* [v1_enum] */ +enum _BMDAudioSampleRate + { + bmdAudioSampleRate48kHz = 48000 + } BMDAudioSampleRate; + +typedef /* [v1_enum] */ +enum _BMDAudioSampleType + { + bmdAudioSampleType16bitInteger = 16, + bmdAudioSampleType32bitInteger = 32 + } BMDAudioSampleType; + +typedef /* [v1_enum] */ +enum _BMDAudioOutputStreamType + { + bmdAudioOutputStreamContinuous = 0, + bmdAudioOutputStreamContinuousDontResample = ( bmdAudioOutputStreamContinuous + 1 ) , + bmdAudioOutputStreamTimestamped = ( bmdAudioOutputStreamContinuousDontResample + 1 ) + } BMDAudioOutputStreamType; + +typedef /* [v1_enum] */ +enum _BMDDisplayModeSupport + { + bmdDisplayModeNotSupported = 0, + bmdDisplayModeSupported = ( bmdDisplayModeNotSupported + 1 ) , + bmdDisplayModeSupportedWithConversion = ( bmdDisplayModeSupported + 1 ) + } BMDDisplayModeSupport; + +typedef /* [v1_enum] */ +enum _BMDTimecodeFormat + { + bmdTimecodeRP188VITC1 = 0x72707631, + bmdTimecodeRP188VITC2 = 0x72703132, + bmdTimecodeRP188LTC = 0x72706c74, + bmdTimecodeRP188Any = 0x72703138, + bmdTimecodeVITC = 0x76697463, + bmdTimecodeVITCField2 = 0x76697432, + bmdTimecodeSerial = 0x73657269 + } BMDTimecodeFormat; + +/* [v1_enum] */ +enum _BMDAnalogVideoFlags + { + bmdAnalogVideoFlagCompositeSetup75 = ( 1 << 0 ) , + bmdAnalogVideoFlagComponentBetacamLevels = ( 1 << 1 ) + } ; +typedef /* [v1_enum] */ +enum _BMDAudioOutputAnalogAESSwitch + { + bmdAudioOutputSwitchAESEBU = 0x61657320, + bmdAudioOutputSwitchAnalog = 0x616e6c67 + } BMDAudioOutputAnalogAESSwitch; + +typedef /* [v1_enum] */ +enum _BMDVideoOutputConversionMode + { + bmdNoVideoOutputConversion = 0x6e6f6e65, + bmdVideoOutputLetterboxDownconversion = 0x6c746278, + bmdVideoOutputAnamorphicDownconversion = 0x616d7068, + bmdVideoOutputHD720toHD1080Conversion = 0x37323063, + bmdVideoOutputHardwareLetterboxDownconversion = 0x48576c62, + bmdVideoOutputHardwareAnamorphicDownconversion = 0x4857616d, + bmdVideoOutputHardwareCenterCutDownconversion = 0x48576363, + bmdVideoOutputHardware720p1080pCrossconversion = 0x78636170, + bmdVideoOutputHardwareAnamorphic720pUpconversion = 0x75613770, + bmdVideoOutputHardwareAnamorphic1080iUpconversion = 0x75613169, + bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 0x75343770, + bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 0x75343169, + bmdVideoOutputHardwarePillarbox720pUpconversion = 0x75703770, + bmdVideoOutputHardwarePillarbox1080iUpconversion = 0x75703169 + } BMDVideoOutputConversionMode; + +typedef /* [v1_enum] */ +enum _BMDVideoInputConversionMode + { + bmdNoVideoInputConversion = 0x6e6f6e65, + bmdVideoInputLetterboxDownconversionFromHD1080 = 0x31306c62, + bmdVideoInputAnamorphicDownconversionFromHD1080 = 0x3130616d, + bmdVideoInputLetterboxDownconversionFromHD720 = 0x37326c62, + bmdVideoInputAnamorphicDownconversionFromHD720 = 0x3732616d, + bmdVideoInputLetterboxUpconversion = 0x6c627570, + bmdVideoInputAnamorphicUpconversion = 0x616d7570 + } BMDVideoInputConversionMode; + +typedef /* [v1_enum] */ +enum _BMDVideo3DPackingFormat + { + bmdVideo3DPackingSidebySideHalf = 0x73627368, + bmdVideo3DPackingLinebyLine = 0x6c62796c, + bmdVideo3DPackingTopAndBottom = 0x7461626f, + bmdVideo3DPackingFramePacking = 0x6672706b, + bmdVideo3DPackingLeftOnly = 0x6c656674, + bmdVideo3DPackingRightOnly = 0x72696768 + } BMDVideo3DPackingFormat; + +typedef /* [v1_enum] */ +enum _BMDIdleVideoOutputOperation + { + bmdIdleVideoOutputBlack = 0x626c6163, + bmdIdleVideoOutputLastFrame = 0x6c616661, + bmdIdleVideoOutputDesktop = 0x6465736b + } BMDIdleVideoOutputOperation; + +typedef /* [v1_enum] */ +enum _BMDDeckLinkAttributeID + { + BMDDeckLinkSupportsInternalKeying = 0x6b657969, + BMDDeckLinkSupportsExternalKeying = 0x6b657965, + BMDDeckLinkSupportsHDKeying = 0x6b657968, + BMDDeckLinkSupportsInputFormatDetection = 0x696e6664, + BMDDeckLinkHasReferenceInput = 0x6872696e, + BMDDeckLinkHasSerialPort = 0x68737074, + BMDDeckLinkHasAnalogVideoOutputGain = 0x61766f67, + BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = 0x6f766f67, + BMDDeckLinkHasVideoInputAntiAliasingFilter = 0x6161666c, + BMDDeckLinkHasBypass = 0x62797073, + BMDDeckLinkSupportsDesktopDisplay = 0x65787464, + BMDDeckLinkSupportsClockTimingAdjustment = 0x63746164, + BMDDeckLinkSupportsFullDuplex = 0x66647570, + BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = 0x6672696e, + BMDDeckLinkSupportsSMPTELevelAOutput = 0x6c766c61, + BMDDeckLinkSupportsDualLinkSDI = 0x73646c73, + BMDDeckLinkSupportsIdleOutput = 0x69646f75, + BMDDeckLinkMaximumAudioChannels = 0x6d616368, + BMDDeckLinkMaximumAnalogAudioChannels = 0x61616368, + BMDDeckLinkNumberOfSubDevices = 0x6e736264, + BMDDeckLinkSubDeviceIndex = 0x73756269, + BMDDeckLinkPersistentID = 0x70656964, + BMDDeckLinkTopologicalID = 0x746f6964, + BMDDeckLinkVideoOutputConnections = 0x766f636e, + BMDDeckLinkVideoInputConnections = 0x7669636e, + BMDDeckLinkAudioOutputConnections = 0x616f636e, + BMDDeckLinkAudioInputConnections = 0x6169636e, + BMDDeckLinkDeviceBusyState = 0x64627374, + BMDDeckLinkVideoIOSupport = 0x76696f73, + BMDDeckLinkVideoInputGainMinimum = 0x7669676d, + BMDDeckLinkVideoInputGainMaximum = 0x76696778, + BMDDeckLinkVideoOutputGainMinimum = 0x766f676d, + BMDDeckLinkVideoOutputGainMaximum = 0x766f6778, + BMDDeckLinkSerialPortDeviceName = 0x736c706e + } BMDDeckLinkAttributeID; + +typedef /* [v1_enum] */ +enum _BMDDeckLinkAPIInformationID + { + BMDDeckLinkAPIVersion = 0x76657273 + } BMDDeckLinkAPIInformationID; + +/* [v1_enum] */ +enum _BMDDeviceBusyState + { + bmdDeviceCaptureBusy = ( 1 << 0 ) , + bmdDevicePlaybackBusy = ( 1 << 1 ) , + bmdDeviceSerialPortBusy = ( 1 << 2 ) + } ; +typedef /* [v1_enum] */ +enum _BMDVideoIOSupport + { + bmdDeviceSupportsCapture = ( 1 << 0 ) , + bmdDeviceSupportsPlayback = ( 1 << 1 ) + } BMDVideoIOSupport; + +typedef /* [v1_enum] */ +enum _BMD3DPreviewFormat + { + bmd3DPreviewFormatDefault = 0x64656661, + bmd3DPreviewFormatLeftOnly = 0x6c656674, + bmd3DPreviewFormatRightOnly = 0x72696768, + bmd3DPreviewFormatSideBySide = 0x73696465, + bmd3DPreviewFormatTopBottom = 0x746f7062 + } BMD3DPreviewFormat; + +typedef /* [v1_enum] */ +enum _BMDNotifications + { + bmdPreferencesChanged = 0x70726566 + } BMDNotifications; + + + + + + + + + + + + + + + + + + + + + + + + + +typedef /* [v1_enum] */ +enum _BMDDeckLinkConfigurationID_v10_2 + { + bmdDeckLinkConfig3GBpsVideoOutput_v10_2 = 0x33676273 + } BMDDeckLinkConfigurationID_v10_2; + +typedef /* [v1_enum] */ +enum _BMDAudioConnection_v10_2 + { + bmdAudioConnectionEmbedded_v10_2 = 0x656d6264, + bmdAudioConnectionAESEBU_v10_2 = 0x61657320, + bmdAudioConnectionAnalog_v10_2 = 0x616e6c67, + bmdAudioConnectionAnalogXLR_v10_2 = 0x61786c72, + bmdAudioConnectionAnalogRCA_v10_2 = 0x61726361 + } BMDAudioConnection_v10_2; + + +typedef /* [v1_enum] */ +enum _BMDDeckControlVTRControlState_v8_1 + { + bmdDeckControlNotInVTRControlMode_v8_1 = 0x6e76636d, + bmdDeckControlVTRControlPlaying_v8_1 = 0x76747270, + bmdDeckControlVTRControlRecording_v8_1 = 0x76747272, + bmdDeckControlVTRControlStill_v8_1 = 0x76747261, + bmdDeckControlVTRControlSeeking_v8_1 = 0x76747273, + bmdDeckControlVTRControlStopped_v8_1 = 0x7674726f + } BMDDeckControlVTRControlState_v8_1; + + + +typedef /* [v1_enum] */ +enum _BMDVideoConnection_v7_6 + { + bmdVideoConnectionSDI_v7_6 = 0x73646920, + bmdVideoConnectionHDMI_v7_6 = 0x68646d69, + bmdVideoConnectionOpticalSDI_v7_6 = 0x6f707469, + bmdVideoConnectionComponent_v7_6 = 0x63706e74, + bmdVideoConnectionComposite_v7_6 = 0x636d7374, + bmdVideoConnectionSVideo_v7_6 = 0x73766964 + } BMDVideoConnection_v7_6; + + + + + + + + + + + + + + + + + + + + + + + +EXTERN_C const IID LIBID_DeckLinkAPI; + +#ifndef __IDeckLinkTimecode_INTERFACE_DEFINED__ +#define __IDeckLinkTimecode_INTERFACE_DEFINED__ + +/* interface IDeckLinkTimecode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkTimecode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BC6CFBD3-8317-4325-AC1C-1216391E9340") + IDeckLinkTimecode : public IUnknown + { + public: + virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetComponents( + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [out] */ BSTR *timecode) = 0; + + virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits( + /* [out] */ BMDTimecodeUserBits *userBits) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkTimecodeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkTimecode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkTimecode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkTimecode * This); + + BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( + IDeckLinkTimecode * This); + + HRESULT ( STDMETHODCALLTYPE *GetComponents )( + IDeckLinkTimecode * This, + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkTimecode * This, + /* [out] */ BSTR *timecode); + + BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkTimecode * This); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeUserBits )( + IDeckLinkTimecode * This, + /* [out] */ BMDTimecodeUserBits *userBits); + + END_INTERFACE + } IDeckLinkTimecodeVtbl; + + interface IDeckLinkTimecode + { + CONST_VTBL struct IDeckLinkTimecodeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkTimecode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkTimecode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkTimecode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkTimecode_GetBCD(This) \ + ( (This)->lpVtbl -> GetBCD(This) ) + +#define IDeckLinkTimecode_GetComponents(This,hours,minutes,seconds,frames) \ + ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) + +#define IDeckLinkTimecode_GetString(This,timecode) \ + ( (This)->lpVtbl -> GetString(This,timecode) ) + +#define IDeckLinkTimecode_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkTimecode_GetTimecodeUserBits(This,userBits) \ + ( (This)->lpVtbl -> GetTimecodeUserBits(This,userBits) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkTimecode_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9C88499F-F601-4021-B80B-032E4EB41C35") + IDeckLinkDisplayModeIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator * This, + /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIteratorVtbl; + + interface IDeckLinkDisplayModeIterator + { + CONST_VTBL struct IDeckLinkDisplayModeIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78") + IDeckLinkDisplayMode : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; + + virtual BMDDisplayModeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( + IDeckLinkDisplayMode * This); + + BMDDisplayModeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkDisplayMode * This); + + END_INTERFACE + } IDeckLinkDisplayModeVtbl; + + interface IDeckLinkDisplayMode + { + CONST_VTBL struct IDeckLinkDisplayModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#define IDeckLinkDisplayMode_GetFieldDominance(This) \ + ( (This)->lpVtbl -> GetFieldDominance(This) ) + +#define IDeckLinkDisplayMode_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLink_INTERFACE_DEFINED__ +#define __IDeckLink_INTERFACE_DEFINED__ + +/* interface IDeckLink */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLink; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C418FBDD-0587-48ED-8FE5-640F0A14AF91") + IDeckLink : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetModelName( + /* [out] */ BSTR *modelName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayName( + /* [out] */ BSTR *displayName) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLink * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLink * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLink * This); + + HRESULT ( STDMETHODCALLTYPE *GetModelName )( + IDeckLink * This, + /* [out] */ BSTR *modelName); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayName )( + IDeckLink * This, + /* [out] */ BSTR *displayName); + + END_INTERFACE + } IDeckLinkVtbl; + + interface IDeckLink + { + CONST_VTBL struct IDeckLinkVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLink_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLink_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLink_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLink_GetModelName(This,modelName) \ + ( (This)->lpVtbl -> GetModelName(This,modelName) ) + +#define IDeckLink_GetDisplayName(This,displayName) \ + ( (This)->lpVtbl -> GetDisplayName(This,displayName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLink_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1E69FCF6-4203-4936-8076-2A9F4CFD50CB") + IDeckLinkConfiguration : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfigurationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration * This); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration * This); + + END_INTERFACE + } IDeckLinkConfigurationVtbl; + + interface IDeckLinkConfiguration + { + CONST_VTBL struct IDeckLinkConfigurationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControlStatusCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("53436FFB-B434-4906-BADC-AE3060FFE8EF") + IDeckLinkDeckControlStatusCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate( + /* [in] */ BMDTimecodeBCD currentTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged( + /* [in] */ BMDDeckControlVTRControlState newState, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived( + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged( + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlStatusCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControlStatusCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControlStatusCallback * This); + + HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDTimecodeBCD currentTimecode); + + HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlVTRControlState newState, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask); + + END_INTERFACE + } IDeckLinkDeckControlStatusCallbackVtbl; + + interface IDeckLinkDeckControlStatusCallback + { + CONST_VTBL struct IDeckLinkDeckControlStatusCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControlStatusCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControlStatusCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControlStatusCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControlStatusCallback_TimecodeUpdate(This,currentTimecode) \ + ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) ) + +#define IDeckLinkDeckControlStatusCallback_VTRControlStateChanged(This,newState,error) \ + ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) ) + +#define IDeckLinkDeckControlStatusCallback_DeckControlEventReceived(This,event,error) \ + ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) ) + +#define IDeckLinkDeckControlStatusCallback_DeckControlStatusChanged(This,flags,mask) \ + ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8E1C3ACE-19C7-4E00-8B92-D80431D958BE") + IDeckLinkDeckControl : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendCommand( + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *SendCommand )( + IDeckLinkDeckControl * This, + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl * This, + /* [in] */ IDeckLinkDeckControlStatusCallback *callback); + + END_INTERFACE + } IDeckLinkDeckControlVtbl; + + interface IDeckLinkDeckControl + { + CONST_VTBL struct IDeckLinkDeckControlVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \ + ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) ) + +#define IDeckLinkDeckControl_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ +#define __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDeviceNotificationCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDeviceNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("F9531D64-3305-4B29-A387-7F74BB0D0E84") + IBMDStreamingDeviceNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceArrived( + /* [in] */ IDeckLink *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceRemoved( + /* [in] */ IDeckLink *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceModeChanged( + /* [in] */ IDeckLink *device, + /* [in] */ BMDStreamingDeviceMode mode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDeviceNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDeviceNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDeviceNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceArrived )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceRemoved )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceModeChanged )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device, + /* [in] */ BMDStreamingDeviceMode mode); + + END_INTERFACE + } IBMDStreamingDeviceNotificationCallbackVtbl; + + interface IBMDStreamingDeviceNotificationCallback + { + CONST_VTBL struct IBMDStreamingDeviceNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDeviceNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDeviceNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceArrived(This,device) \ + ( (This)->lpVtbl -> StreamingDeviceArrived(This,device) ) + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceRemoved(This,device) \ + ( (This)->lpVtbl -> StreamingDeviceRemoved(This,device) ) + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceModeChanged(This,device,mode) \ + ( (This)->lpVtbl -> StreamingDeviceModeChanged(This,device,mode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ +#define __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264InputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264InputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("823C475F-55AE-46F9-890C-537CC5CEDCCA") + IBMDStreamingH264InputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE H264NALPacketArrived( + /* [in] */ IBMDStreamingH264NALPacket *nalPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264AudioPacketArrived( + /* [in] */ IBMDStreamingAudioPacket *audioPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE MPEG2TSPacketArrived( + /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorScanningChanged( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorChanged( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputModeChanged( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264InputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264InputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264InputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264NALPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingH264NALPacket *nalPacket); + + HRESULT ( STDMETHODCALLTYPE *H264AudioPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingAudioPacket *audioPacket); + + HRESULT ( STDMETHODCALLTYPE *MPEG2TSPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorScanningChanged )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorChanged )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputModeChanged )( + IBMDStreamingH264InputCallback * This); + + END_INTERFACE + } IBMDStreamingH264InputCallbackVtbl; + + interface IBMDStreamingH264InputCallback + { + CONST_VTBL struct IBMDStreamingH264InputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264InputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264InputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264InputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264InputCallback_H264NALPacketArrived(This,nalPacket) \ + ( (This)->lpVtbl -> H264NALPacketArrived(This,nalPacket) ) + +#define IBMDStreamingH264InputCallback_H264AudioPacketArrived(This,audioPacket) \ + ( (This)->lpVtbl -> H264AudioPacketArrived(This,audioPacket) ) + +#define IBMDStreamingH264InputCallback_MPEG2TSPacketArrived(This,tsPacket) \ + ( (This)->lpVtbl -> MPEG2TSPacketArrived(This,tsPacket) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputConnectorScanningChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputConnectorScanningChanged(This) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputConnectorChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputConnectorChanged(This) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputModeChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputModeChanged(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDiscovery_INTERFACE_DEFINED__ +#define __IBMDStreamingDiscovery_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDiscovery */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDiscovery; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2C837444-F989-4D87-901A-47C8A36D096D") + IBMDStreamingDiscovery : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications( + /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDiscoveryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDiscovery * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDiscovery * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDiscovery * This); + + HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )( + IBMDStreamingDiscovery * This, + /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )( + IBMDStreamingDiscovery * This); + + END_INTERFACE + } IBMDStreamingDiscoveryVtbl; + + interface IBMDStreamingDiscovery + { + CONST_VTBL struct IBMDStreamingDiscoveryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDiscovery_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDiscovery_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDiscovery_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDiscovery_InstallDeviceNotifications(This,theCallback) \ + ( (This)->lpVtbl -> InstallDeviceNotifications(This,theCallback) ) + +#define IBMDStreamingDiscovery_UninstallDeviceNotifications(This) \ + ( (This)->lpVtbl -> UninstallDeviceNotifications(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDiscovery_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ +#define __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ + +/* interface IBMDStreamingVideoEncodingMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingVideoEncodingMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1AB8035B-CD13-458D-B6DF-5E8F7C2141D9") + IBMDStreamingVideoEncodingMode : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetPresetID( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourcePositionX( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourcePositionY( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourceWidth( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourceHeight( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetDestWidth( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetDestHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateMutableVideoEncodingMode( + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingVideoEncodingModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingVideoEncodingMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IBMDStreamingVideoEncodingMode * This, + /* [out] */ BSTR *name); + + unsigned int ( STDMETHODCALLTYPE *GetPresetID )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestWidth )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestHeight )( + IBMDStreamingVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )( + IBMDStreamingVideoEncodingMode * This, + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode); + + END_INTERFACE + } IBMDStreamingVideoEncodingModeVtbl; + + interface IBMDStreamingVideoEncodingMode + { + CONST_VTBL struct IBMDStreamingVideoEncodingModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingVideoEncodingMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingVideoEncodingMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingVideoEncodingMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingVideoEncodingMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IBMDStreamingVideoEncodingMode_GetPresetID(This) \ + ( (This)->lpVtbl -> GetPresetID(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourcePositionX(This) \ + ( (This)->lpVtbl -> GetSourcePositionX(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourcePositionY(This) \ + ( (This)->lpVtbl -> GetSourcePositionY(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourceWidth(This) \ + ( (This)->lpVtbl -> GetSourceWidth(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourceHeight(This) \ + ( (This)->lpVtbl -> GetSourceHeight(This) ) + +#define IBMDStreamingVideoEncodingMode_GetDestWidth(This) \ + ( (This)->lpVtbl -> GetDestWidth(This) ) + +#define IBMDStreamingVideoEncodingMode_GetDestHeight(This) \ + ( (This)->lpVtbl -> GetDestHeight(This) ) + +#define IBMDStreamingVideoEncodingMode_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \ + ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ +#define __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ + +/* interface IBMDStreamingMutableVideoEncodingMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingMutableVideoEncodingMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("19BF7D90-1E0A-400D-B2C6-FFC4E78AD49D") + IBMDStreamingMutableVideoEncodingMode : public IBMDStreamingVideoEncodingMode + { + public: + virtual HRESULT STDMETHODCALLTYPE SetSourceRect( + /* [in] */ unsigned int posX, + /* [in] */ unsigned int posY, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetDestSize( + /* [in] */ unsigned int width, + /* [in] */ unsigned int height) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BSTR value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingMutableVideoEncodingModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingMutableVideoEncodingMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingMutableVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [out] */ BSTR *name); + + unsigned int ( STDMETHODCALLTYPE *GetPresetID )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestWidth )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestHeight )( + IBMDStreamingMutableVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode); + + HRESULT ( STDMETHODCALLTYPE *SetSourceRect )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ unsigned int posX, + /* [in] */ unsigned int posY, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height); + + HRESULT ( STDMETHODCALLTYPE *SetDestSize )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BSTR value); + + END_INTERFACE + } IBMDStreamingMutableVideoEncodingModeVtbl; + + interface IBMDStreamingMutableVideoEncodingMode + { + CONST_VTBL struct IBMDStreamingMutableVideoEncodingModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingMutableVideoEncodingMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingMutableVideoEncodingMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingMutableVideoEncodingMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetPresetID(This) \ + ( (This)->lpVtbl -> GetPresetID(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionX(This) \ + ( (This)->lpVtbl -> GetSourcePositionX(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionY(This) \ + ( (This)->lpVtbl -> GetSourcePositionY(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourceWidth(This) \ + ( (This)->lpVtbl -> GetSourceWidth(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourceHeight(This) \ + ( (This)->lpVtbl -> GetSourceHeight(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetDestWidth(This) \ + ( (This)->lpVtbl -> GetDestWidth(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetDestHeight(This) \ + ( (This)->lpVtbl -> GetDestHeight(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \ + ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) ) + + +#define IBMDStreamingMutableVideoEncodingMode_SetSourceRect(This,posX,posY,width,height) \ + ( (This)->lpVtbl -> SetSourceRect(This,posX,posY,width,height) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetDestSize(This,width,height) \ + ( (This)->lpVtbl -> SetDestSize(This,width,height) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ +#define __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ + +/* interface IBMDStreamingVideoEncodingModePresetIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingVideoEncodingModePresetIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7AC731A3-C950-4AD0-804A-8377AA51C6C4") + IBMDStreamingVideoEncodingModePresetIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingVideoEncodingModePresetIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingVideoEncodingModePresetIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingVideoEncodingModePresetIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingVideoEncodingModePresetIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IBMDStreamingVideoEncodingModePresetIterator * This, + /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode); + + END_INTERFACE + } IBMDStreamingVideoEncodingModePresetIteratorVtbl; + + interface IBMDStreamingVideoEncodingModePresetIterator + { + CONST_VTBL struct IBMDStreamingVideoEncodingModePresetIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingVideoEncodingModePresetIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingVideoEncodingModePresetIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingVideoEncodingModePresetIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingVideoEncodingModePresetIterator_Next(This,videoEncodingMode) \ + ( (This)->lpVtbl -> Next(This,videoEncodingMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ +#define __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDeviceInput */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDeviceInput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("24B6B6EC-1727-44BB-9818-34FF086ACF98") + IBMDStreamingDeviceInput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoInputMode( + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ BOOL *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputMode( + /* [in] */ BMDDisplayMode inputMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentDetectedVideoInputMode( + /* [out] */ BMDDisplayMode *detectedMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingMode( + /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingModePresetIterator( + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoEncodingMode( + /* [in] */ BMDDisplayMode inputMode, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode, + /* [out] */ BMDStreamingEncodingSupport *result, + /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoEncodingMode( + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopCapture( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IUnknown *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDeviceInputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDeviceInput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDeviceInput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ BOOL *result); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputModeIterator )( + IBMDStreamingDeviceInput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentDetectedVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [out] */ BMDDisplayMode *detectedMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingModePresetIterator )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode, + /* [out] */ BMDStreamingEncodingSupport *result, + /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode); + + HRESULT ( STDMETHODCALLTYPE *SetVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *StopCapture )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IBMDStreamingDeviceInput * This, + /* [in] */ IUnknown *theCallback); + + END_INTERFACE + } IBMDStreamingDeviceInputVtbl; + + interface IBMDStreamingDeviceInput + { + CONST_VTBL struct IBMDStreamingDeviceInputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDeviceInput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDeviceInput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDeviceInput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDeviceInput_DoesSupportVideoInputMode(This,inputMode,result) \ + ( (This)->lpVtbl -> DoesSupportVideoInputMode(This,inputMode,result) ) + +#define IBMDStreamingDeviceInput_GetVideoInputModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetVideoInputModeIterator(This,iterator) ) + +#define IBMDStreamingDeviceInput_SetVideoInputMode(This,inputMode) \ + ( (This)->lpVtbl -> SetVideoInputMode(This,inputMode) ) + +#define IBMDStreamingDeviceInput_GetCurrentDetectedVideoInputMode(This,detectedMode) \ + ( (This)->lpVtbl -> GetCurrentDetectedVideoInputMode(This,detectedMode) ) + +#define IBMDStreamingDeviceInput_GetVideoEncodingMode(This,encodingMode) \ + ( (This)->lpVtbl -> GetVideoEncodingMode(This,encodingMode) ) + +#define IBMDStreamingDeviceInput_GetVideoEncodingModePresetIterator(This,inputMode,iterator) \ + ( (This)->lpVtbl -> GetVideoEncodingModePresetIterator(This,inputMode,iterator) ) + +#define IBMDStreamingDeviceInput_DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) \ + ( (This)->lpVtbl -> DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) ) + +#define IBMDStreamingDeviceInput_SetVideoEncodingMode(This,encodingMode) \ + ( (This)->lpVtbl -> SetVideoEncodingMode(This,encodingMode) ) + +#define IBMDStreamingDeviceInput_StartCapture(This) \ + ( (This)->lpVtbl -> StartCapture(This) ) + +#define IBMDStreamingDeviceInput_StopCapture(This) \ + ( (This)->lpVtbl -> StopCapture(This) ) + +#define IBMDStreamingDeviceInput_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264NALPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264NALPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E260E955-14BE-4395-9775-9F02CC0A9D89") + IBMDStreamingH264NALPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytesWithSizePrefix( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayTime( + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *displayTime) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketIndex( + /* [out] */ unsigned int *packetIndex) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264NALPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264NALPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264NALPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264NALPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingH264NALPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingH264NALPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetBytesWithSizePrefix )( + IBMDStreamingH264NALPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayTime )( + IBMDStreamingH264NALPacket * This, + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *displayTime); + + HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )( + IBMDStreamingH264NALPacket * This, + /* [out] */ unsigned int *packetIndex); + + END_INTERFACE + } IBMDStreamingH264NALPacketVtbl; + + interface IBMDStreamingH264NALPacket + { + CONST_VTBL struct IBMDStreamingH264NALPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264NALPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264NALPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264NALPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264NALPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingH264NALPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IBMDStreamingH264NALPacket_GetBytesWithSizePrefix(This,buffer) \ + ( (This)->lpVtbl -> GetBytesWithSizePrefix(This,buffer) ) + +#define IBMDStreamingH264NALPacket_GetDisplayTime(This,requestedTimeScale,displayTime) \ + ( (This)->lpVtbl -> GetDisplayTime(This,requestedTimeScale,displayTime) ) + +#define IBMDStreamingH264NALPacket_GetPacketIndex(This,packetIndex) \ + ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingAudioPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingAudioPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("D9EB5902-1AD2-43F4-9E2C-3CFA50B5EE19") + IBMDStreamingAudioPacket : public IUnknown + { + public: + virtual BMDStreamingAudioCodec STDMETHODCALLTYPE GetCodec( void) = 0; + + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPlayTime( + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *playTime) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketIndex( + /* [out] */ unsigned int *packetIndex) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingAudioPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingAudioPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingAudioPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingAudioPacket * This); + + BMDStreamingAudioCodec ( STDMETHODCALLTYPE *GetCodec )( + IBMDStreamingAudioPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingAudioPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingAudioPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetPlayTime )( + IBMDStreamingAudioPacket * This, + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *playTime); + + HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )( + IBMDStreamingAudioPacket * This, + /* [out] */ unsigned int *packetIndex); + + END_INTERFACE + } IBMDStreamingAudioPacketVtbl; + + interface IBMDStreamingAudioPacket + { + CONST_VTBL struct IBMDStreamingAudioPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingAudioPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingAudioPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingAudioPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingAudioPacket_GetCodec(This) \ + ( (This)->lpVtbl -> GetCodec(This) ) + +#define IBMDStreamingAudioPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingAudioPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IBMDStreamingAudioPacket_GetPlayTime(This,requestedTimeScale,playTime) \ + ( (This)->lpVtbl -> GetPlayTime(This,requestedTimeScale,playTime) ) + +#define IBMDStreamingAudioPacket_GetPacketIndex(This,packetIndex) \ + ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingMPEG2TSPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingMPEG2TSPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("91810D1C-4FB3-4AAA-AE56-FA301D3DFA4C") + IBMDStreamingMPEG2TSPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingMPEG2TSPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingMPEG2TSPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingMPEG2TSPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingMPEG2TSPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingMPEG2TSPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingMPEG2TSPacket * This, + /* [out] */ void **buffer); + + END_INTERFACE + } IBMDStreamingMPEG2TSPacketVtbl; + + interface IBMDStreamingMPEG2TSPacket + { + CONST_VTBL struct IBMDStreamingMPEG2TSPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingMPEG2TSPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingMPEG2TSPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingMPEG2TSPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingMPEG2TSPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingMPEG2TSPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ +#define __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264NALParser */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264NALParser; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5867F18C-5BFA-4CCC-B2A7-9DFD140417D2") + IBMDStreamingH264NALParser : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE IsNALSequenceParameterSet( + /* [in] */ IBMDStreamingH264NALPacket *nal) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsNALPictureParameterSet( + /* [in] */ IBMDStreamingH264NALPacket *nal) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetProfileAndLevelFromSPS( + /* [in] */ IBMDStreamingH264NALPacket *nal, + /* [out] */ unsigned int *profileIdc, + /* [out] */ unsigned int *profileCompatability, + /* [out] */ unsigned int *levelIdc) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264NALParserVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264NALParser * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264NALParser * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264NALParser * This); + + HRESULT ( STDMETHODCALLTYPE *IsNALSequenceParameterSet )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal); + + HRESULT ( STDMETHODCALLTYPE *IsNALPictureParameterSet )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal); + + HRESULT ( STDMETHODCALLTYPE *GetProfileAndLevelFromSPS )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal, + /* [out] */ unsigned int *profileIdc, + /* [out] */ unsigned int *profileCompatability, + /* [out] */ unsigned int *levelIdc); + + END_INTERFACE + } IBMDStreamingH264NALParserVtbl; + + interface IBMDStreamingH264NALParser + { + CONST_VTBL struct IBMDStreamingH264NALParserVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264NALParser_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264NALParser_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264NALParser_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264NALParser_IsNALSequenceParameterSet(This,nal) \ + ( (This)->lpVtbl -> IsNALSequenceParameterSet(This,nal) ) + +#define IBMDStreamingH264NALParser_IsNALPictureParameterSet(This,nal) \ + ( (This)->lpVtbl -> IsNALPictureParameterSet(This,nal) ) + +#define IBMDStreamingH264NALParser_GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) \ + ( (This)->lpVtbl -> GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CBMDStreamingDiscovery; + +#ifdef __cplusplus + +class DECLSPEC_UUID("0CAA31F6-8A26-40B0-86A4-BF58DCCA710C") +CBMDStreamingDiscovery; +#endif + +EXTERN_C const CLSID CLSID_CBMDStreamingH264NALParser; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7753EFBD-951C-407C-97A5-23C737B73B52") +CBMDStreamingH264NALParser; +#endif + +#ifndef __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("20AA5225-1958-47CB-820B-80A8D521A6EE") + IDeckLinkVideoOutputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback * This, + /* [in] */ IDeckLinkVideoFrame *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( + IDeckLinkVideoOutputCallback * This); + + END_INTERFACE + } IDeckLinkVideoOutputCallbackVtbl; + + interface IDeckLinkVideoOutputCallback + { + CONST_VTBL struct IDeckLinkVideoOutputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#define IDeckLinkVideoOutputCallback_ScheduledPlaybackHasStopped(This) \ + ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DD04E5EC-7415-42AB-AE4A-E80C4DFC044A") + IDeckLinkInputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback * This, + /* [in] */ IDeckLinkVideoInputFrame *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallbackVtbl; + + interface IDeckLinkInputCallback + { + CONST_VTBL struct IDeckLinkInputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ +#define __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ + +/* interface IDeckLinkMemoryAllocator */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMemoryAllocator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B36EB6E7-9D29-4AA8-92EF-843B87A289E8") + IDeckLinkMemoryAllocator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( + /* [in] */ unsigned int bufferSize, + /* [out] */ void **allocatedBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer( + /* [in] */ void *buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Decommit( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMemoryAllocatorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMemoryAllocator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMemoryAllocator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMemoryAllocator * This); + + HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( + IDeckLinkMemoryAllocator * This, + /* [in] */ unsigned int bufferSize, + /* [out] */ void **allocatedBuffer); + + HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )( + IDeckLinkMemoryAllocator * This, + /* [in] */ void *buffer); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IDeckLinkMemoryAllocator * This); + + HRESULT ( STDMETHODCALLTYPE *Decommit )( + IDeckLinkMemoryAllocator * This); + + END_INTERFACE + } IDeckLinkMemoryAllocatorVtbl; + + interface IDeckLinkMemoryAllocator + { + CONST_VTBL struct IDeckLinkMemoryAllocatorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMemoryAllocator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMemoryAllocator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMemoryAllocator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMemoryAllocator_AllocateBuffer(This,bufferSize,allocatedBuffer) \ + ( (This)->lpVtbl -> AllocateBuffer(This,bufferSize,allocatedBuffer) ) + +#define IDeckLinkMemoryAllocator_ReleaseBuffer(This,buffer) \ + ( (This)->lpVtbl -> ReleaseBuffer(This,buffer) ) + +#define IDeckLinkMemoryAllocator_Commit(This) \ + ( (This)->lpVtbl -> Commit(This) ) + +#define IDeckLinkMemoryAllocator_Decommit(This) \ + ( (This)->lpVtbl -> Decommit(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioOutputCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioOutputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("403C681B-7F46-4A12-B993-2BB127084EE6") + IDeckLinkAudioOutputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( + /* [in] */ BOOL preroll) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioOutputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioOutputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioOutputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioOutputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *RenderAudioSamples )( + IDeckLinkAudioOutputCallback * This, + /* [in] */ BOOL preroll); + + END_INTERFACE + } IDeckLinkAudioOutputCallbackVtbl; + + interface IDeckLinkAudioOutputCallback + { + CONST_VTBL struct IDeckLinkAudioOutputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioOutputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioOutputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioOutputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioOutputCallback_RenderAudioSamples(This,preroll) \ + ( (This)->lpVtbl -> RenderAudioSamples(This,preroll) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_INTERFACE_DEFINED__ +#define __IDeckLinkIterator_INTERFACE_DEFINED__ + +/* interface IDeckLinkIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("50FB36CD-3063-4B73-BDBB-958087F2D8BA") + IDeckLinkIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLink **deckLinkInstance) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkIterator * This, + /* [out] */ IDeckLink **deckLinkInstance); + + END_INTERFACE + } IDeckLinkIteratorVtbl; + + interface IDeckLinkIterator + { + CONST_VTBL struct IDeckLinkIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkIterator_Next(This,deckLinkInstance) \ + ( (This)->lpVtbl -> Next(This,deckLinkInstance) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAPIInformation_INTERFACE_DEFINED__ +#define __IDeckLinkAPIInformation_INTERFACE_DEFINED__ + +/* interface IDeckLinkAPIInformation */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAPIInformation; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7BEA3C68-730D-4322-AF34-8A7152B532A4") + IDeckLinkAPIInformation : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BSTR *value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAPIInformationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAPIInformation * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAPIInformation * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAPIInformation * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BSTR *value); + + END_INTERFACE + } IDeckLinkAPIInformationVtbl; + + interface IDeckLinkAPIInformation + { + CONST_VTBL struct IDeckLinkAPIInformationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAPIInformation_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAPIInformation_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAPIInformation_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAPIInformation_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAPIInformation_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564") + IDeckLinkOutput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus( + /* [out] */ BMDReferenceStatus *referenceStatus) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameCompletionReferenceTimestamp( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *frameCompletionTimestamp) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput * This, + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput * This, + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )( + IDeckLinkOutput * This, + /* [out] */ BMDReferenceStatus *referenceStatus); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + HRESULT ( STDMETHODCALLTYPE *GetFrameCompletionReferenceTimestamp )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *frameCompletionTimestamp); + + END_INTERFACE + } IDeckLinkOutputVtbl; + + interface IDeckLinkOutput + { + CONST_VTBL struct IDeckLinkOutputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkOutput_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_GetReferenceStatus(This,referenceStatus) \ + ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) ) + +#define IDeckLinkOutput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#define IDeckLinkOutput_GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) \ + ( (This)->lpVtbl -> GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_INTERFACE_DEFINED__ +#define __IDeckLinkInput_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AF22762B-DFAC-4846-AA79-FA8883560995") + IDeckLinkInput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputFrameMemoryAllocator )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkInputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInputVtbl; + + interface IDeckLinkInput + { + CONST_VTBL struct IDeckLinkInputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkInput_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_SetVideoInputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoInputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkInput_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3F716FE0-F023-4111-BE5D-EF4414C05B17") + IDeckLinkVideoFrame : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + END_INTERFACE + } IDeckLinkVideoFrameVtbl; + + interface IDeckLinkVideoFrame + { + CONST_VTBL struct IDeckLinkVideoFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ +#define __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkMutableVideoFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMutableVideoFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("69E2639F-40DA-4E19-B6F2-20ACE815C390") + IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlags( + /* [in] */ BMDFrameFlags newFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecode( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode *timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ unsigned char hours, + /* [in] */ unsigned char minutes, + /* [in] */ unsigned char seconds, + /* [in] */ unsigned char frames, + /* [in] */ BMDTimecodeFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeUserBits( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ BMDTimecodeUserBits userBits) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMutableVideoFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMutableVideoFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkMutableVideoFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkMutableVideoFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkMutableVideoFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkMutableVideoFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkMutableVideoFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetFlags )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDFrameFlags newFlags); + + HRESULT ( STDMETHODCALLTYPE *SetTimecode )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode *timecode); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ unsigned char hours, + /* [in] */ unsigned char minutes, + /* [in] */ unsigned char seconds, + /* [in] */ unsigned char frames, + /* [in] */ BMDTimecodeFlags flags); + + HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeUserBits )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ BMDTimecodeUserBits userBits); + + END_INTERFACE + } IDeckLinkMutableVideoFrameVtbl; + + interface IDeckLinkMutableVideoFrame + { + CONST_VTBL struct IDeckLinkMutableVideoFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMutableVideoFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMutableVideoFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMutableVideoFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMutableVideoFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkMutableVideoFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkMutableVideoFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkMutableVideoFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkMutableVideoFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkMutableVideoFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkMutableVideoFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkMutableVideoFrame_SetFlags(This,newFlags) \ + ( (This)->lpVtbl -> SetFlags(This,newFlags) ) + +#define IDeckLinkMutableVideoFrame_SetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ + ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) + +#define IDeckLinkMutableVideoFrame_SetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) + +#define IDeckLinkMutableVideoFrame_SetTimecodeUserBits(This,format,userBits) \ + ( (This)->lpVtbl -> SetTimecodeUserBits(This,format,userBits) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame3DExtensions */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame3DExtensions; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7") + IDeckLinkVideoFrame3DExtensions : public IUnknown + { + public: + virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye( + /* [out] */ IDeckLinkVideoFrame **rightEyeFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame3DExtensionsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame3DExtensions * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame3DExtensions * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame3DExtensions * This); + + BMDVideo3DPackingFormat ( STDMETHODCALLTYPE *Get3DPackingFormat )( + IDeckLinkVideoFrame3DExtensions * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameForRightEye )( + IDeckLinkVideoFrame3DExtensions * This, + /* [out] */ IDeckLinkVideoFrame **rightEyeFrame); + + END_INTERFACE + } IDeckLinkVideoFrame3DExtensionsVtbl; + + interface IDeckLinkVideoFrame3DExtensions + { + CONST_VTBL struct IDeckLinkVideoFrame3DExtensionsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame3DExtensions_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame3DExtensions_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame3DExtensions_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame3DExtensions_Get3DPackingFormat(This) \ + ( (This)->lpVtbl -> Get3DPackingFormat(This) ) + +#define IDeckLinkVideoFrame3DExtensions_GetFrameForRightEye(This,rightEyeFrame) \ + ( (This)->lpVtbl -> GetFrameForRightEye(This,rightEyeFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("05CFE374-537C-4094-9A57-680525118F44") + IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( + /* [in] */ BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( + IDeckLinkVideoInputFrame * This, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration); + + END_INTERFACE + } IDeckLinkVideoInputFrameVtbl; + + interface IDeckLinkVideoInputFrame + { + CONST_VTBL struct IDeckLinkVideoInputFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#define IDeckLinkVideoInputFrame_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ + ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrameAncillary */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrameAncillary; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("732E723C-D1A4-4E29-9E8E-4A88797A0004") + IDeckLinkVideoFrameAncillary : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetBufferForVerticalBlankingLine( + /* [in] */ unsigned int lineNumber, + /* [out] */ void **buffer) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrameAncillaryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrameAncillary * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrameAncillary * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrameAncillary * This); + + HRESULT ( STDMETHODCALLTYPE *GetBufferForVerticalBlankingLine )( + IDeckLinkVideoFrameAncillary * This, + /* [in] */ unsigned int lineNumber, + /* [out] */ void **buffer); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrameAncillary * This); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkVideoFrameAncillary * This); + + END_INTERFACE + } IDeckLinkVideoFrameAncillaryVtbl; + + interface IDeckLinkVideoFrameAncillary + { + CONST_VTBL struct IDeckLinkVideoFrameAncillaryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrameAncillary_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrameAncillary_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrameAncillary_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrameAncillary_GetBufferForVerticalBlankingLine(This,lineNumber,buffer) \ + ( (This)->lpVtbl -> GetBufferForVerticalBlankingLine(This,lineNumber,buffer) ) + +#define IDeckLinkVideoFrameAncillary_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrameAncillary_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ +#define __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioInputPacket */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioInputPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E43D5870-2894-11DE-8C30-0800200C9A66") + IDeckLinkAudioInputPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetSampleFrameCount( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketTime( + /* [out] */ BMDTimeValue *packetTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioInputPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioInputPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioInputPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioInputPacket * This); + + long ( STDMETHODCALLTYPE *GetSampleFrameCount )( + IDeckLinkAudioInputPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkAudioInputPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetPacketTime )( + IDeckLinkAudioInputPacket * This, + /* [out] */ BMDTimeValue *packetTime, + /* [in] */ BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkAudioInputPacketVtbl; + + interface IDeckLinkAudioInputPacket + { + CONST_VTBL struct IDeckLinkAudioInputPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioInputPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioInputPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioInputPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioInputPacket_GetSampleFrameCount(This) \ + ( (This)->lpVtbl -> GetSampleFrameCount(This) ) + +#define IDeckLinkAudioInputPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkAudioInputPacket_GetPacketTime(This,packetTime,timeScale) \ + ( (This)->lpVtbl -> GetPacketTime(This,packetTime,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkScreenPreviewCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438") + IDeckLinkScreenPreviewCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DrawFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkScreenPreviewCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkScreenPreviewCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkScreenPreviewCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkScreenPreviewCallback * This); + + HRESULT ( STDMETHODCALLTYPE *DrawFrame )( + IDeckLinkScreenPreviewCallback * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + END_INTERFACE + } IDeckLinkScreenPreviewCallbackVtbl; + + interface IDeckLinkScreenPreviewCallback + { + CONST_VTBL struct IDeckLinkScreenPreviewCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkScreenPreviewCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkScreenPreviewCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkScreenPreviewCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkScreenPreviewCallback_DrawFrame(This,theFrame) \ + ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ + +/* interface IDeckLinkGLScreenPreviewHelper */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("504E2209-CAC7-4C1A-9FB4-C5BB6274D22F") + IDeckLinkGLScreenPreviewHelper : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat( + /* [in] */ BMD3DPreviewFormat previewFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkGLScreenPreviewHelperVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkGLScreenPreviewHelper * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *InitializeGL )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *PaintGL )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ BMD3DPreviewFormat previewFormat); + + END_INTERFACE + } IDeckLinkGLScreenPreviewHelperVtbl; + + interface IDeckLinkGLScreenPreviewHelper + { + CONST_VTBL struct IDeckLinkGLScreenPreviewHelperVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkGLScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkGLScreenPreviewHelper_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkGLScreenPreviewHelper_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkGLScreenPreviewHelper_InitializeGL(This) \ + ( (This)->lpVtbl -> InitializeGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_PaintGL(This) \ + ( (This)->lpVtbl -> PaintGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#define IDeckLinkGLScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \ + ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ +#define __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ + +/* interface IDeckLinkDX9ScreenPreviewHelper */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDX9ScreenPreviewHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2094B522-D1A1-40C0-9AC7-1C012218EF02") + IDeckLinkDX9ScreenPreviewHelper : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ void *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE Render( + /* [in] */ RECT *rc) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat( + /* [in] */ BMD3DPreviewFormat previewFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDX9ScreenPreviewHelperVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDX9ScreenPreviewHelper * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDX9ScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ void *device); + + HRESULT ( STDMETHODCALLTYPE *Render )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ RECT *rc); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ BMD3DPreviewFormat previewFormat); + + END_INTERFACE + } IDeckLinkDX9ScreenPreviewHelperVtbl; + + interface IDeckLinkDX9ScreenPreviewHelper + { + CONST_VTBL struct IDeckLinkDX9ScreenPreviewHelperVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDX9ScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDX9ScreenPreviewHelper_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDX9ScreenPreviewHelper_Initialize(This,device) \ + ( (This)->lpVtbl -> Initialize(This,device) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Render(This,rc) \ + ( (This)->lpVtbl -> Render(This,rc) ) + +#define IDeckLinkDX9ScreenPreviewHelper_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \ + ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ +#define __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkNotificationCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b002a1ec-070d-4288-8289-bd5d36e5ff0d") + IDeckLinkNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Notify( + /* [in] */ BMDNotifications topic, + /* [in] */ ULONGLONG param1, + /* [in] */ ULONGLONG param2) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *Notify )( + IDeckLinkNotificationCallback * This, + /* [in] */ BMDNotifications topic, + /* [in] */ ULONGLONG param1, + /* [in] */ ULONGLONG param2); + + END_INTERFACE + } IDeckLinkNotificationCallbackVtbl; + + interface IDeckLinkNotificationCallback + { + CONST_VTBL struct IDeckLinkNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkNotificationCallback_Notify(This,topic,param1,param2) \ + ( (This)->lpVtbl -> Notify(This,topic,param1,param2) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkNotification_INTERFACE_DEFINED__ +#define __IDeckLinkNotification_INTERFACE_DEFINED__ + +/* interface IDeckLinkNotification */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkNotification; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0a1fb207-e215-441b-9b19-6fa1575946c5") + IDeckLinkNotification : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Subscribe( + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE Unsubscribe( + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkNotificationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkNotification * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkNotification * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkNotification * This); + + HRESULT ( STDMETHODCALLTYPE *Subscribe )( + IDeckLinkNotification * This, + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *Unsubscribe )( + IDeckLinkNotification * This, + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback); + + END_INTERFACE + } IDeckLinkNotificationVtbl; + + interface IDeckLinkNotification + { + CONST_VTBL struct IDeckLinkNotificationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkNotification_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkNotification_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkNotification_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkNotification_Subscribe(This,topic,theCallback) \ + ( (This)->lpVtbl -> Subscribe(This,topic,theCallback) ) + +#define IDeckLinkNotification_Unsubscribe(This,topic,theCallback) \ + ( (This)->lpVtbl -> Unsubscribe(This,topic,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkNotification_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAttributes_INTERFACE_DEFINED__ +#define __IDeckLinkAttributes_INTERFACE_DEFINED__ + +/* interface IDeckLinkAttributes */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAttributes; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ABC11843-D966-44CB-96E2-A1CB5D3135C4") + IDeckLinkAttributes : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BSTR *value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAttributesVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAttributes * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAttributes * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAttributes * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BSTR *value); + + END_INTERFACE + } IDeckLinkAttributesVtbl; + + interface IDeckLinkAttributes + { + CONST_VTBL struct IDeckLinkAttributesVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAttributes_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAttributes_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAttributes_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAttributes_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAttributes_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkKeyer_INTERFACE_DEFINED__ +#define __IDeckLinkKeyer_INTERFACE_DEFINED__ + +/* interface IDeckLinkKeyer */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkKeyer; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3") + IDeckLinkKeyer : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Enable( + /* [in] */ BOOL isExternal) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetLevel( + /* [in] */ unsigned char level) = 0; + + virtual HRESULT STDMETHODCALLTYPE RampUp( + /* [in] */ unsigned int numberOfFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE RampDown( + /* [in] */ unsigned int numberOfFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE Disable( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkKeyerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkKeyer * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkKeyer * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkKeyer * This); + + HRESULT ( STDMETHODCALLTYPE *Enable )( + IDeckLinkKeyer * This, + /* [in] */ BOOL isExternal); + + HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IDeckLinkKeyer * This, + /* [in] */ unsigned char level); + + HRESULT ( STDMETHODCALLTYPE *RampUp )( + IDeckLinkKeyer * This, + /* [in] */ unsigned int numberOfFrames); + + HRESULT ( STDMETHODCALLTYPE *RampDown )( + IDeckLinkKeyer * This, + /* [in] */ unsigned int numberOfFrames); + + HRESULT ( STDMETHODCALLTYPE *Disable )( + IDeckLinkKeyer * This); + + END_INTERFACE + } IDeckLinkKeyerVtbl; + + interface IDeckLinkKeyer + { + CONST_VTBL struct IDeckLinkKeyerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkKeyer_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkKeyer_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkKeyer_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkKeyer_Enable(This,isExternal) \ + ( (This)->lpVtbl -> Enable(This,isExternal) ) + +#define IDeckLinkKeyer_SetLevel(This,level) \ + ( (This)->lpVtbl -> SetLevel(This,level) ) + +#define IDeckLinkKeyer_RampUp(This,numberOfFrames) \ + ( (This)->lpVtbl -> RampUp(This,numberOfFrames) ) + +#define IDeckLinkKeyer_RampDown(This,numberOfFrames) \ + ( (This)->lpVtbl -> RampDown(This,numberOfFrames) ) + +#define IDeckLinkKeyer_Disable(This) \ + ( (This)->lpVtbl -> Disable(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkKeyer_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_INTERFACE_DEFINED__ +#define __IDeckLinkVideoConversion_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoConversion */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoConversion; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3BBCB8A2-DA2C-42D9-B5D8-88083644E99A") + IDeckLinkVideoConversion : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ConvertFrame( + /* [in] */ IDeckLinkVideoFrame *srcFrame, + /* [in] */ IDeckLinkVideoFrame *dstFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoConversionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoConversion * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoConversion * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoConversion * This); + + HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( + IDeckLinkVideoConversion * This, + /* [in] */ IDeckLinkVideoFrame *srcFrame, + /* [in] */ IDeckLinkVideoFrame *dstFrame); + + END_INTERFACE + } IDeckLinkVideoConversionVtbl; + + interface IDeckLinkVideoConversion + { + CONST_VTBL struct IDeckLinkVideoConversionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoConversion_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoConversion_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoConversion_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoConversion_ConvertFrame(This,srcFrame,dstFrame) \ + ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoConversion_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ +#define __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeviceNotificationCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeviceNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4997053B-0ADF-4CC8-AC70-7A50C4BE728F") + IDeckLinkDeviceNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceArrived( + /* [in] */ IDeckLink *deckLinkDevice) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceRemoved( + /* [in] */ IDeckLink *deckLinkDevice) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeviceNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeviceNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeviceNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceArrived )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ IDeckLink *deckLinkDevice); + + HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceRemoved )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ IDeckLink *deckLinkDevice); + + END_INTERFACE + } IDeckLinkDeviceNotificationCallbackVtbl; + + interface IDeckLinkDeviceNotificationCallback + { + CONST_VTBL struct IDeckLinkDeviceNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeviceNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeviceNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceArrived(This,deckLinkDevice) \ + ( (This)->lpVtbl -> DeckLinkDeviceArrived(This,deckLinkDevice) ) + +#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceRemoved(This,deckLinkDevice) \ + ( (This)->lpVtbl -> DeckLinkDeviceRemoved(This,deckLinkDevice) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDiscovery_INTERFACE_DEFINED__ +#define __IDeckLinkDiscovery_INTERFACE_DEFINED__ + +/* interface IDeckLinkDiscovery */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDiscovery; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CDBF631C-BC76-45FA-B44D-C55059BC6101") + IDeckLinkDiscovery : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications( + /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDiscoveryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDiscovery * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDiscovery * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDiscovery * This); + + HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )( + IDeckLinkDiscovery * This, + /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback); + + HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )( + IDeckLinkDiscovery * This); + + END_INTERFACE + } IDeckLinkDiscoveryVtbl; + + interface IDeckLinkDiscovery + { + CONST_VTBL struct IDeckLinkDiscoveryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDiscovery_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDiscovery_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDiscovery_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDiscovery_InstallDeviceNotifications(This,deviceNotificationCallback) \ + ( (This)->lpVtbl -> InstallDeviceNotifications(This,deviceNotificationCallback) ) + +#define IDeckLinkDiscovery_UninstallDeviceNotifications(This) \ + ( (This)->lpVtbl -> UninstallDeviceNotifications(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDiscovery_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkIterator; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1F2E109A-8F4F-49E4-9203-135595CB6FA5") +CDeckLinkIterator; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkAPIInformation; + +#ifdef __cplusplus + +class DECLSPEC_UUID("263CA19F-ED09-482E-9F9D-84005783A237") +CDeckLinkAPIInformation; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper; + +#ifdef __cplusplus + +class DECLSPEC_UUID("F63E77C7-B655-4A4A-9AD0-3CA85D394343") +CDeckLinkGLScreenPreviewHelper; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkDX9ScreenPreviewHelper; + +#ifdef __cplusplus + +class DECLSPEC_UUID("CC010023-E01D-4525-9D59-80C8AB3DC7A0") +CDeckLinkDX9ScreenPreviewHelper; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7DBBBB11-5B7B-467D-AEA4-CEA468FD368C") +CDeckLinkVideoConversion; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkDiscovery; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1073A05C-D885-47E9-B3C6-129B3F9F648B") +CDeckLinkDiscovery; +#endif + +#ifndef __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration_v10_2 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration_v10_2; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C679A35B-610C-4D09-B748-1D0478100FC0") + IDeckLinkConfiguration_v10_2 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfiguration_v10_2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration_v10_2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration_v10_2 * This); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration_v10_2 * This); + + END_INTERFACE + } IDeckLinkConfiguration_v10_2Vtbl; + + interface IDeckLinkConfiguration_v10_2 + { + CONST_VTBL struct IDeckLinkConfiguration_v10_2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_v10_2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_v10_2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_v10_2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_v10_2_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v9_9 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v9_9; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A3EF0963-0862-44ED-92A9-EE89ABF431C7") + IDeckLinkOutput_v9_9 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus( + /* [out] */ BMDReferenceStatus *referenceStatus) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v9_9Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v9_9 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ BMDReferenceStatus *referenceStatus); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkOutput_v9_9Vtbl; + + interface IDeckLinkOutput_v9_9 + { + CONST_VTBL struct IDeckLinkOutput_v9_9Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v9_9_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v9_9_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v9_9_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v9_9_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkOutput_v9_9_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v9_9_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v9_9_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v9_9_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v9_9_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v9_9_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v9_9_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v9_9_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v9_9_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v9_9_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v9_9_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v9_9_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v9_9_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v9_9_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v9_9_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v9_9_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v9_9_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v9_9_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v9_9_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v9_9_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v9_9_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v9_9_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v9_9_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v9_9_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_v9_9_GetReferenceStatus(This,referenceStatus) \ + ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) ) + +#define IDeckLinkOutput_v9_9_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v9_2 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v9_2; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6D40EF78-28B9-4E21-990D-95BB7750A04F") + IDeckLinkInput_v9_2 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v9_2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v9_2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v9_2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v9_2 * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v9_2 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v9_2 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v9_2 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v9_2 * This, + /* [in] */ IDeckLinkInputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInput_v9_2Vtbl; + + interface IDeckLinkInput_v9_2 + { + CONST_VTBL struct IDeckLinkInput_v9_2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v9_2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v9_2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v9_2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v9_2_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkInput_v9_2_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v9_2_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v9_2_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v9_2_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v9_2_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v9_2_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v9_2_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v9_2_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v9_2_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v9_2_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v9_2_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v9_2_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v9_2_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_v9_2_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControlStatusCallback_v8_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback_v8_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E5F693C1-4283-4716-B18F-C1431521955B") + IDeckLinkDeckControlStatusCallback_v8_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate( + /* [in] */ BMDTimecodeBCD currentTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged( + /* [in] */ BMDDeckControlVTRControlState_v8_1 newState, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived( + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged( + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControlStatusCallback_v8_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControlStatusCallback_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDTimecodeBCD currentTimecode); + + HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlVTRControlState_v8_1 newState, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask); + + END_INTERFACE + } IDeckLinkDeckControlStatusCallback_v8_1Vtbl; + + interface IDeckLinkDeckControlStatusCallback_v8_1 + { + CONST_VTBL struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControlStatusCallback_v8_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControlStatusCallback_v8_1_TimecodeUpdate(This,currentTimecode) \ + ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_VTRControlStateChanged(This,newState,error) \ + ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlEventReceived(This,event,error) \ + ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlStatusChanged(This,flags,mask) \ + ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl_v8_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl_v8_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("522A9E39-0F3C-4742-94EE-D80DE335DA1D") + IDeckLinkDeckControl_v8_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendCommand( + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControl_v8_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl_v8_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *SendCommand )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback); + + END_INTERFACE + } IDeckLinkDeckControl_v8_1Vtbl; + + interface IDeckLinkDeckControl_v8_1 + { + CONST_VTBL struct IDeckLinkDeckControl_v8_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_v8_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_v8_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_v8_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_v8_1_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_v8_1_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_v8_1_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_v8_1_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_v8_1_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \ + ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) ) + +#define IDeckLinkDeckControl_v8_1_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_v8_1_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_v8_1_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v8_1_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v8_1_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_v8_1_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_v8_1_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v8_1_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v8_1_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_v8_1_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_v8_1_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_v8_1_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_v8_1_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLink_v8_0_INTERFACE_DEFINED__ +#define __IDeckLink_v8_0_INTERFACE_DEFINED__ + +/* interface IDeckLink_v8_0 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLink_v8_0; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("62BFF75D-6569-4E55-8D4D-66AA03829ABC") + IDeckLink_v8_0 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetModelName( + /* [out] */ BSTR *modelName) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLink_v8_0Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLink_v8_0 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLink_v8_0 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLink_v8_0 * This); + + HRESULT ( STDMETHODCALLTYPE *GetModelName )( + IDeckLink_v8_0 * This, + /* [out] */ BSTR *modelName); + + END_INTERFACE + } IDeckLink_v8_0Vtbl; + + interface IDeckLink_v8_0 + { + CONST_VTBL struct IDeckLink_v8_0Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLink_v8_0_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLink_v8_0_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLink_v8_0_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLink_v8_0_GetModelName(This,modelName) \ + ( (This)->lpVtbl -> GetModelName(This,modelName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLink_v8_0_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ +#define __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ + +/* interface IDeckLinkIterator_v8_0 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkIterator_v8_0; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("74E936FC-CC28-4A67-81A0-1E94E52D4E69") + IDeckLinkIterator_v8_0 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLink_v8_0 **deckLinkInstance) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkIterator_v8_0Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkIterator_v8_0 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkIterator_v8_0 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkIterator_v8_0 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkIterator_v8_0 * This, + /* [out] */ IDeckLink_v8_0 **deckLinkInstance); + + END_INTERFACE + } IDeckLinkIterator_v8_0Vtbl; + + interface IDeckLinkIterator_v8_0 + { + CONST_VTBL struct IDeckLinkIterator_v8_0Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkIterator_v8_0_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkIterator_v8_0_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkIterator_v8_0_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkIterator_v8_0_Next(This,deckLinkInstance) \ + ( (This)->lpVtbl -> Next(This,deckLinkInstance) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkIterator_v8_0; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D9EDA3B3-2887-41FA-B724-017CF1EB1D37") +CDeckLinkIterator_v8_0; +#endif + +#ifndef __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl_v7_9 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl_v7_9; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A4D81043-0619-42B7-8ED6-602D29041DF7") + IDeckLinkDeckControl_v7_9 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControl_v7_9Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl_v7_9 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl_v7_9 * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl_v7_9 * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ IDeckLinkDeckControlStatusCallback *callback); + + END_INTERFACE + } IDeckLinkDeckControl_v7_9Vtbl; + + interface IDeckLinkDeckControl_v7_9 + { + CONST_VTBL struct IDeckLinkDeckControl_v7_9Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_v7_9_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_v7_9_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_v7_9_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_v7_9_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_v7_9_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_v7_9_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_v7_9_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_v7_9_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_v7_9_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_v7_9_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v7_9_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v7_9_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_v7_9_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_v7_9_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v7_9_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v7_9_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_v7_9_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_v7_9_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_v7_9_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_v7_9_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("455D741F-1779-4800-86F5-0B5D13D79751") + IDeckLinkDisplayModeIterator_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIterator_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator_v7_6 * This, + /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIterator_v7_6Vtbl; + + interface IDeckLinkDisplayModeIterator_v7_6 + { + CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_v7_6_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("87451E84-2B7E-439E-A629-4393EA4A8550") + IDeckLinkDisplayMode_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayMode_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode_v7_6 * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode_v7_6 * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( + IDeckLinkDisplayMode_v7_6 * This); + + END_INTERFACE + } IDeckLinkDisplayMode_v7_6Vtbl; + + interface IDeckLinkDisplayMode_v7_6 + { + CONST_VTBL struct IDeckLinkDisplayMode_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_v7_6_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_v7_6_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#define IDeckLinkDisplayMode_v7_6_GetFieldDominance(This) \ + ( (This)->lpVtbl -> GetFieldDominance(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("29228142-EB8C-4141-A621-F74026450955") + IDeckLinkOutput_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_6 * This, + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_6 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v7_6 * This, + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_6 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_6 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_6 * This, + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkOutput_v7_6Vtbl; + + interface IDeckLinkOutput_v7_6 + { + CONST_VTBL struct IDeckLinkOutput_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_6_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v7_6_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v7_6_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_6_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_6_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_6_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v7_6_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_6_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_6_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_6_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v7_6_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v7_6_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_6_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_6_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_6_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_6_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_6_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v7_6_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_6_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_6_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_6_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_6_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v7_6_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("300C135A-9F43-48E2-9906-6D7911D93CF1") + IDeckLinkInput_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_6 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v7_6 * This, + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v7_6 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_6 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v7_6 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_6 * This, + /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInput_v7_6Vtbl; + + interface IDeckLinkInput_v7_6 + { + CONST_VTBL struct IDeckLinkInput_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_6_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v7_6_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_6_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_6_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v7_6_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_6_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_6_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v7_6_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_6_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_6_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_6_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v7_6_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkTimecode_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkTimecode_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EFB9BCA6-A521-44F7-BD69-2332F24D9EE6") + IDeckLinkTimecode_v7_6 : public IUnknown + { + public: + virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetComponents( + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [out] */ BSTR *timecode) = 0; + + virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkTimecode_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkTimecode_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkTimecode_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkTimecode_v7_6 * This); + + BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( + IDeckLinkTimecode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetComponents )( + IDeckLinkTimecode_v7_6 * This, + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkTimecode_v7_6 * This, + /* [out] */ BSTR *timecode); + + BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkTimecode_v7_6 * This); + + END_INTERFACE + } IDeckLinkTimecode_v7_6Vtbl; + + interface IDeckLinkTimecode_v7_6 + { + CONST_VTBL struct IDeckLinkTimecode_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkTimecode_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkTimecode_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkTimecode_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkTimecode_v7_6_GetBCD(This) \ + ( (This)->lpVtbl -> GetBCD(This) ) + +#define IDeckLinkTimecode_v7_6_GetComponents(This,hours,minutes,seconds,frames) \ + ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) + +#define IDeckLinkTimecode_v7_6_GetString(This,timecode) \ + ( (This)->lpVtbl -> GetString(This,timecode) ) + +#define IDeckLinkTimecode_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A8D8238E-6B18-4196-99E1-5AF717B83D32") + IDeckLinkVideoFrame_v7_6 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + END_INTERFACE + } IDeckLinkVideoFrame_v7_6Vtbl; + + interface IDeckLinkVideoFrame_v7_6 + { + CONST_VTBL struct IDeckLinkVideoFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkMutableVideoFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMutableVideoFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("46FCEE00-B4E6-43D0-91C0-023A7FCEB34F") + IDeckLinkMutableVideoFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlags( + BMDFrameFlags newFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecode( + BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode_v7_6 *timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( + BMDTimecodeFormat format, + unsigned char hours, + unsigned char minutes, + unsigned char seconds, + unsigned char frames, + BMDTimecodeFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMutableVideoFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetFlags )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDFrameFlags newFlags); + + HRESULT ( STDMETHODCALLTYPE *SetTimecode )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode_v7_6 *timecode); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + unsigned char hours, + unsigned char minutes, + unsigned char seconds, + unsigned char frames, + BMDTimecodeFlags flags); + + HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); + + END_INTERFACE + } IDeckLinkMutableVideoFrame_v7_6Vtbl; + + interface IDeckLinkMutableVideoFrame_v7_6 + { + CONST_VTBL struct IDeckLinkMutableVideoFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMutableVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMutableVideoFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMutableVideoFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkMutableVideoFrame_v7_6_SetFlags(This,newFlags) \ + ( (This)->lpVtbl -> SetFlags(This,newFlags) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ + ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9A74FA41-AE9F-47AC-8CF4-01F42DD59965") + IDeckLinkVideoInputFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( + BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( + IDeckLinkVideoInputFrame_v7_6 * This, + BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_6Vtbl; + + interface IDeckLinkVideoInputFrame_v7_6 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_v7_6_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ + ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkScreenPreviewCallback_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("373F499D-4B4D-4518-AD22-6354E5A5825E") + IDeckLinkScreenPreviewCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DrawFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkScreenPreviewCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkScreenPreviewCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkScreenPreviewCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkScreenPreviewCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DrawFrame )( + IDeckLinkScreenPreviewCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + END_INTERFACE + } IDeckLinkScreenPreviewCallback_v7_6Vtbl; + + interface IDeckLinkScreenPreviewCallback_v7_6 + { + CONST_VTBL struct IDeckLinkScreenPreviewCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkScreenPreviewCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkScreenPreviewCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkScreenPreviewCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkScreenPreviewCallback_v7_6_DrawFrame(This,theFrame) \ + ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkGLScreenPreviewHelper_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BA575CD9-A15E-497B-B2C2-F9AFE7BE4EBA") + IDeckLinkGLScreenPreviewHelper_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *InitializeGL )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *PaintGL )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + END_INTERFACE + } IDeckLinkGLScreenPreviewHelper_v7_6Vtbl; + + interface IDeckLinkGLScreenPreviewHelper_v7_6 + { + CONST_VTBL struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkGLScreenPreviewHelper_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkGLScreenPreviewHelper_v7_6_InitializeGL(This) \ + ( (This)->lpVtbl -> InitializeGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_PaintGL(This) \ + ( (This)->lpVtbl -> PaintGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoConversion_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoConversion_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3EB504C9-F97D-40FE-A158-D407D48CB53B") + IDeckLinkVideoConversion_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ConvertFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, + /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoConversion_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoConversion_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoConversion_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoConversion_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( + IDeckLinkVideoConversion_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, + /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame); + + END_INTERFACE + } IDeckLinkVideoConversion_v7_6Vtbl; + + interface IDeckLinkVideoConversion_v7_6 + { + CONST_VTBL struct IDeckLinkVideoConversion_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoConversion_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoConversion_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoConversion_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoConversion_v7_6_ConvertFrame(This,srcFrame,dstFrame) \ + ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B8EAD569-B764-47F0-A73F-AE40DF6CBF10") + IDeckLinkConfiguration_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetConfigurationValidator( + /* [out] */ IDeckLinkConfiguration_v7_6 **configObject) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFormat( + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsVideoOutputActive( + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoOutputFlags( + /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoOutputFlags( + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableFieldFlickerRemovalWhenPaused( + /* [in] */ BOOL enable) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsEnabledFieldFlickerRemovalWhenPaused( + /* [out] */ BOOL *enabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set444And3GBpsVideoOutput( + /* [in] */ BOOL enable444VideoOutput, + /* [in] */ BOOL enable3GbsOutput) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get444And3GBpsVideoOutput( + /* [out] */ BOOL *is444VideoOutputEnabled, + /* [out] */ BOOL *threeGbsOutputEnabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputConversionMode( + /* [in] */ BMDVideoOutputConversionMode conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoOutputConversionMode( + /* [out] */ BMDVideoOutputConversionMode *conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set_HD1080p24_to_HD1080i5994_Conversion( + /* [in] */ BOOL enable) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get_HD1080p24_to_HD1080i5994_Conversion( + /* [out] */ BOOL *enabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputFormat( + /* [in] */ BMDVideoConnection_v7_6 videoInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputFormat( + /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoInputFlags( + /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoInputFlags( + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputConversionMode( + /* [in] */ BMDVideoInputConversionMode conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputConversionMode( + /* [out] */ BMDVideoInputConversionMode *conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetBlackVideoOutputDuringCapture( + /* [in] */ BOOL blackOutInCapture) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBlackVideoOutputDuringCapture( + /* [out] */ BOOL *blackOutInCapture) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set32PulldownSequenceInitialTimecodeFrame( + /* [in] */ unsigned int aFrameTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get32PulldownSequenceInitialTimecodeFrame( + /* [out] */ unsigned int *aFrameTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVancSourceLineMapping( + /* [in] */ unsigned int activeLine1VANCsource, + /* [in] */ unsigned int activeLine2VANCsource, + /* [in] */ unsigned int activeLine3VANCsource) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVancSourceLineMapping( + /* [out] */ unsigned int *activeLine1VANCsource, + /* [out] */ unsigned int *activeLine2VANCsource, + /* [out] */ unsigned int *activeLine3VANCsource) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioInputFormat( + /* [in] */ BMDAudioConnection_v10_2 audioInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAudioInputFormat( + /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfiguration_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetConfigurationValidator )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ IDeckLinkConfiguration_v7_6 **configObject); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection); + + HRESULT ( STDMETHODCALLTYPE *IsVideoOutputActive )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoOutputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAnalogVideoFlags analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoOutputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *EnableFieldFlickerRemovalWhenPaused )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable); + + HRESULT ( STDMETHODCALLTYPE *IsEnabledFieldFlickerRemovalWhenPaused )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *enabled); + + HRESULT ( STDMETHODCALLTYPE *Set444And3GBpsVideoOutput )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable444VideoOutput, + /* [in] */ BOOL enable3GbsOutput); + + HRESULT ( STDMETHODCALLTYPE *Get444And3GBpsVideoOutput )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *is444VideoOutputEnabled, + /* [out] */ BOOL *threeGbsOutputEnabled); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoOutputConversionMode conversionMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoOutputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoOutputConversionMode *conversionMode); + + HRESULT ( STDMETHODCALLTYPE *Set_HD1080p24_to_HD1080i5994_Conversion )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable); + + HRESULT ( STDMETHODCALLTYPE *Get_HD1080p24_to_HD1080i5994_Conversion )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *enabled); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoInputFormat); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat); + + HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoInputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAnalogVideoFlags analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoInputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoInputConversionMode conversionMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoInputConversionMode *conversionMode); + + HRESULT ( STDMETHODCALLTYPE *SetBlackVideoOutputDuringCapture )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL blackOutInCapture); + + HRESULT ( STDMETHODCALLTYPE *GetBlackVideoOutputDuringCapture )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *blackOutInCapture); + + HRESULT ( STDMETHODCALLTYPE *Set32PulldownSequenceInitialTimecodeFrame )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ unsigned int aFrameTimecode); + + HRESULT ( STDMETHODCALLTYPE *Get32PulldownSequenceInitialTimecodeFrame )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ unsigned int *aFrameTimecode); + + HRESULT ( STDMETHODCALLTYPE *SetVancSourceLineMapping )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ unsigned int activeLine1VANCsource, + /* [in] */ unsigned int activeLine2VANCsource, + /* [in] */ unsigned int activeLine3VANCsource); + + HRESULT ( STDMETHODCALLTYPE *GetVancSourceLineMapping )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ unsigned int *activeLine1VANCsource, + /* [out] */ unsigned int *activeLine2VANCsource, + /* [out] */ unsigned int *activeLine3VANCsource); + + HRESULT ( STDMETHODCALLTYPE *SetAudioInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAudioConnection_v10_2 audioInputFormat); + + HRESULT ( STDMETHODCALLTYPE *GetAudioInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat); + + END_INTERFACE + } IDeckLinkConfiguration_v7_6Vtbl; + + interface IDeckLinkConfiguration_v7_6 + { + CONST_VTBL struct IDeckLinkConfiguration_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_v7_6_GetConfigurationValidator(This,configObject) \ + ( (This)->lpVtbl -> GetConfigurationValidator(This,configObject) ) + +#define IDeckLinkConfiguration_v7_6_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoOutputFormat(This,videoOutputConnection) \ + ( (This)->lpVtbl -> SetVideoOutputFormat(This,videoOutputConnection) ) + +#define IDeckLinkConfiguration_v7_6_IsVideoOutputActive(This,videoOutputConnection,active) \ + ( (This)->lpVtbl -> IsVideoOutputActive(This,videoOutputConnection,active) ) + +#define IDeckLinkConfiguration_v7_6_SetAnalogVideoOutputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> SetAnalogVideoOutputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_GetAnalogVideoOutputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> GetAnalogVideoOutputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_EnableFieldFlickerRemovalWhenPaused(This,enable) \ + ( (This)->lpVtbl -> EnableFieldFlickerRemovalWhenPaused(This,enable) ) + +#define IDeckLinkConfiguration_v7_6_IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) \ + ( (This)->lpVtbl -> IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) ) + +#define IDeckLinkConfiguration_v7_6_Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) \ + ( (This)->lpVtbl -> Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) ) + +#define IDeckLinkConfiguration_v7_6_Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) \ + ( (This)->lpVtbl -> Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoOutputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> SetVideoOutputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoOutputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> GetVideoOutputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) \ + ( (This)->lpVtbl -> Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) ) + +#define IDeckLinkConfiguration_v7_6_Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) \ + ( (This)->lpVtbl -> Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoInputFormat(This,videoInputFormat) \ + ( (This)->lpVtbl -> SetVideoInputFormat(This,videoInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoInputFormat(This,videoInputFormat) \ + ( (This)->lpVtbl -> GetVideoInputFormat(This,videoInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_SetAnalogVideoInputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> SetAnalogVideoInputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_GetAnalogVideoInputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> GetAnalogVideoInputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoInputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> SetVideoInputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoInputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> GetVideoInputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_SetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ + ( (This)->lpVtbl -> SetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) + +#define IDeckLinkConfiguration_v7_6_GetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ + ( (This)->lpVtbl -> GetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) + +#define IDeckLinkConfiguration_v7_6_Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ + ( (This)->lpVtbl -> Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) + +#define IDeckLinkConfiguration_v7_6_Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ + ( (This)->lpVtbl -> Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) + +#define IDeckLinkConfiguration_v7_6_SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ + ( (This)->lpVtbl -> SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) + +#define IDeckLinkConfiguration_v7_6_GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ + ( (This)->lpVtbl -> GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) + +#define IDeckLinkConfiguration_v7_6_SetAudioInputFormat(This,audioInputFormat) \ + ( (This)->lpVtbl -> SetAudioInputFormat(This,audioInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_GetAudioInputFormat(This,audioInputFormat) \ + ( (This)->lpVtbl -> GetAudioInputFormat(This,audioInputFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E763A626-4A3C-49D1-BF13-E7AD3692AE52") + IDeckLinkVideoOutputCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + END_INTERFACE + } IDeckLinkVideoOutputCallback_v7_6Vtbl; + + interface IDeckLinkVideoOutputCallback_v7_6 + { + CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_v7_6_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#define IDeckLinkVideoOutputCallback_v7_6_ScheduledPlaybackHasStopped(This) \ + ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("31D28EE7-88B6-4CB1-897A-CDBF79A26414") + IDeckLinkInputCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_6Vtbl; + + interface IDeckLinkInputCallback_v7_6 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_6_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_v7_6_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper_v7_6; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D398CEE7-4434-4CA3-9BA6-5AE34556B905") +CDeckLinkGLScreenPreviewHelper_v7_6; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion_v7_6; + +#ifdef __cplusplus + +class DECLSPEC_UUID("FFA84F77-73BE-4FB7-B03E-B5E44B9F759B") +CDeckLinkVideoConversion_v7_6; +#endif + +#ifndef __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_3 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("FD6F311D-4D00-444B-9ED4-1F25B5730AD0") + IDeckLinkInputCallback_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_3Vtbl; + + interface IDeckLinkInputCallback_v7_3 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_3_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_v7_3_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_3 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("271C65E3-C323-4344-A30F-D908BCB20AA3") + IDeckLinkOutput_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_3 * This, + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_3 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v7_3 * This, + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_3 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_3 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_3 * This, + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_3 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan); + + END_INTERFACE + } IDeckLinkOutput_v7_3Vtbl; + + interface IDeckLinkOutput_v7_3 + { + CONST_VTBL struct IDeckLinkOutput_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_3_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v7_3_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v7_3_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_3_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_3_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_3_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v7_3_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_3_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_3_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_3_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v7_3_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v7_3_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_3_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_3_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_3_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_3_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_3_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v7_3_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_3_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_3_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_3_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_3_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v7_3_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_3 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4973F012-9925-458C-871C-18774CDBBECB") + IDeckLinkInput_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_3 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v7_3 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v7_3 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_3 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v7_3 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_3 * This, + /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback); + + END_INTERFACE + } IDeckLinkInput_v7_3Vtbl; + + interface IDeckLinkInput_v7_3 + { + CONST_VTBL struct IDeckLinkInput_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_3_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v7_3_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_3_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_3_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v7_3_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_3_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_3_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v7_3_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_3_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_3_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_3_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v7_3_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_3 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CF317790-2894-11DE-8C30-0800200C9A66") + IDeckLinkVideoInputFrame_v7_3 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_3 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_3 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame_v7_3 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_3Vtbl; + + interface IDeckLinkVideoInputFrame_v7_3 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_3_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_v7_3_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B28131B6-59AC-4857-B5AC-CD75D5883E2F") + IDeckLinkDisplayModeIterator_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIterator_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator_v7_1 * This, + /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIterator_v7_1Vtbl; + + interface IDeckLinkDisplayModeIterator_v7_1 + { + CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_v7_1_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AF0CD6D5-8376-435E-8433-54F9DD530AC3") + IDeckLinkDisplayMode_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayMode_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode_v7_1 * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode_v7_1 * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + END_INTERFACE + } IDeckLinkDisplayMode_v7_1Vtbl; + + interface IDeckLinkDisplayMode_v7_1 + { + CONST_VTBL struct IDeckLinkDisplayMode_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_v7_1_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_v7_1_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("333F3A10-8C2D-43CF-B79D-46560FEEA1CE") + IDeckLinkVideoFrame_v7_1 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + void **buffer) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame_v7_1 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame_v7_1 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame_v7_1 * This, + void **buffer); + + END_INTERFACE + } IDeckLinkVideoFrame_v7_1Vtbl; + + interface IDeckLinkVideoFrame_v7_1 + { + CONST_VTBL struct IDeckLinkVideoFrame_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C8B41D95-8848-40EE-9B37-6E3417FB114B") + IDeckLinkVideoInputFrame_v7_1 : public IDeckLinkVideoFrame_v7_1 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFrameTime( + BMDTimeValue *frameTime, + BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_1 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_1 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_1 * This, + void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetFrameTime )( + IDeckLinkVideoInputFrame_v7_1 * This, + BMDTimeValue *frameTime, + BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_1Vtbl; + + interface IDeckLinkVideoInputFrame_v7_1 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + + +#define IDeckLinkVideoInputFrame_v7_1_GetFrameTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameTime(This,frameTime,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioInputPacket_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioInputPacket_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C86DE4F6-A29F-42E3-AB3A-1363E29F0788") + IDeckLinkAudioInputPacket_v7_1 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetSampleCount( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAudioPacketTime( + BMDTimeValue *packetTime, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioInputPacket_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioInputPacket_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioInputPacket_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioInputPacket_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetSampleCount )( + IDeckLinkAudioInputPacket_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkAudioInputPacket_v7_1 * This, + void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetAudioPacketTime )( + IDeckLinkAudioInputPacket_v7_1 * This, + BMDTimeValue *packetTime, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkAudioInputPacket_v7_1Vtbl; + + interface IDeckLinkAudioInputPacket_v7_1 + { + CONST_VTBL struct IDeckLinkAudioInputPacket_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioInputPacket_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioInputPacket_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioInputPacket_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioInputPacket_v7_1_GetSampleCount(This) \ + ( (This)->lpVtbl -> GetSampleCount(This) ) + +#define IDeckLinkAudioInputPacket_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkAudioInputPacket_v7_1_GetAudioPacketTime(This,packetTime,timeScale) \ + ( (This)->lpVtbl -> GetAudioPacketTime(This,packetTime,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EBD01AFA-E4B0-49C6-A01D-EDB9D1B55FD9") + IDeckLinkVideoOutputCallback_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallback_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback_v7_1 * This, + /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + END_INTERFACE + } IDeckLinkVideoOutputCallback_v7_1Vtbl; + + interface IDeckLinkVideoOutputCallback_v7_1 + { + CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_v7_1_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7F94F328-5ED4-4E9F-9729-76A86BDC99CC") + IDeckLinkInputCallback_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_1 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_1Vtbl; + + interface IDeckLinkInputCallback_v7_1 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_1_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AE5B3E9B-4E1E-4535-B6E8-480FF52F6CE5") + IDeckLinkOutput_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrameFromBuffer( + void *buffer, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + IDeckLinkVideoFrame_v7_1 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + IDeckLinkVideoFrame_v7_1 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_1 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_1 * This, + BMDDisplayMode displayMode); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_1 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrameFromBuffer )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_1 * This, + IDeckLinkVideoFrame_v7_1 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_1 * This, + IDeckLinkVideoFrame_v7_1 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_1 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_1 * This, + /* [out] */ unsigned int *bufferedSampleCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_1 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_1 * This, + BMDTimeValue stopPlaybackAtTime, + BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_1 * This, + BMDTimeScale desiredTimeScale, + BMDTimeValue *elapsedTimeSinceSchedulerBegan); + + END_INTERFACE + } IDeckLinkOutput_v7_1Vtbl; + + interface IDeckLinkOutput_v7_1 + { + CONST_VTBL struct IDeckLinkOutput_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_1_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_1_EnableVideoOutput(This,displayMode) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode) ) + +#define IDeckLinkOutput_v7_1_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_1_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_1_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_1_CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_1_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_1_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_1_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_1_EnableAudioOutput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkOutput_v7_1_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_1_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_1_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_1_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_1_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) + +#define IDeckLinkOutput_v7_1_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_1_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_1_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_1_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_1_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2B54EDEF-5B32-429F-BA11-BB990596EACD") + IDeckLinkInput_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReadAudioSamples( + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesRead, + /* [out] */ BMDTimeValue *audioPacketTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_1 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_1 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ReadAudioSamples )( + IDeckLinkInput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesRead, + /* [out] */ BMDTimeValue *audioPacketTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkInput_v7_1 * This, + /* [out] */ unsigned int *bufferedSampleCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_1 * This, + /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback); + + END_INTERFACE + } IDeckLinkInput_v7_1Vtbl; + + interface IDeckLinkInput_v7_1 + { + CONST_VTBL struct IDeckLinkInput_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_1_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_1_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_1_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_1_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_1_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_1_ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) \ + ( (This)->lpVtbl -> ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) ) + +#define IDeckLinkInput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) + +#define IDeckLinkInput_v7_1_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_1_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_1_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_1_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ */ + +#endif /* __DeckLinkAPI_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/intern/decklink/win/DeckLinkAPI_i.c b/intern/decklink/win/DeckLinkAPI_i.c new file mode 100644 index 00000000000..a13d486aae8 --- /dev/null +++ b/intern/decklink/win/DeckLinkAPI_i.c @@ -0,0 +1,343 @@ + + +/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ + +/* link this file in with the server and any clients */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Mon Apr 13 20:57:05 2015 + */ +/* Compiler settings for ..\..\include\DeckLinkAPI.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#ifdef __cplusplus +extern "C"{ +#endif + + +#include <rpc.h> +#include <rpcndr.h> + +#ifdef _MIDL_USE_GUIDDEF_ + +#ifndef INITGUID +#define INITGUID +#include <guiddef.h> +#undef INITGUID +#else +#include <guiddef.h> +#endif + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) + +#else // !_MIDL_USE_GUIDDEF_ + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef struct _IID +{ + unsigned long x; + unsigned short s1; + unsigned short s2; + unsigned char c[8]; +} IID; + +#endif // __IID_DEFINED__ + +#ifndef CLSID_DEFINED +#define CLSID_DEFINED +typedef IID CLSID; +#endif // CLSID_DEFINED + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} + +#endif !_MIDL_USE_GUIDDEF_ + +MIDL_DEFINE_GUID(IID, LIBID_DeckLinkAPI,0xD864517A,0xEDD5,0x466D,0x86,0x7D,0xC8,0x19,0xF1,0xC0,0x52,0xBB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode,0xBC6CFBD3,0x8317,0x4325,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator,0x9C88499F,0xF601,0x4021,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode,0x3EB2C1AB,0x0A3D,0x4523,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLink,0xC418FBDD,0x0587,0x48ED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration,0x1E69FCF6,0x4203,0x4936,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback,0x53436FFB,0xB434,0x4906,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl,0x8E1C3ACE,0x19C7,0x4E00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceNotificationCallback,0xF9531D64,0x3305,0x4B29,0xA3,0x87,0x7F,0x74,0xBB,0x0D,0x0E,0x84); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264InputCallback,0x823C475F,0x55AE,0x46F9,0x89,0x0C,0x53,0x7C,0xC5,0xCE,0xDC,0xCA); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDiscovery,0x2C837444,0xF989,0x4D87,0x90,0x1A,0x47,0xC8,0xA3,0x6D,0x09,0x6D); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingMode,0x1AB8035B,0xCD13,0x458D,0xB6,0xDF,0x5E,0x8F,0x7C,0x21,0x41,0xD9); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMutableVideoEncodingMode,0x19BF7D90,0x1E0A,0x400D,0xB2,0xC6,0xFF,0xC4,0xE7,0x8A,0xD4,0x9D); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingModePresetIterator,0x7AC731A3,0xC950,0x4AD0,0x80,0x4A,0x83,0x77,0xAA,0x51,0xC6,0xC4); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceInput,0x24B6B6EC,0x1727,0x44BB,0x98,0x18,0x34,0xFF,0x08,0x6A,0xCF,0x98); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALPacket,0xE260E955,0x14BE,0x4395,0x97,0x75,0x9F,0x02,0xCC,0x0A,0x9D,0x89); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingAudioPacket,0xD9EB5902,0x1AD2,0x43F4,0x9E,0x2C,0x3C,0xFA,0x50,0xB5,0xEE,0x19); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMPEG2TSPacket,0x91810D1C,0x4FB3,0x4AAA,0xAE,0x56,0xFA,0x30,0x1D,0x3D,0xFA,0x4C); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALParser,0x5867F18C,0x5BFA,0x4CCC,0xB2,0xA7,0x9D,0xFD,0x14,0x04,0x17,0xD2); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingDiscovery,0x0CAA31F6,0x8A26,0x40B0,0x86,0xA4,0xBF,0x58,0xDC,0xCA,0x71,0x0C); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingH264NALParser,0x7753EFBD,0x951C,0x407C,0x97,0xA5,0x23,0xC7,0x37,0xB7,0x3B,0x52); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback,0x20AA5225,0x1958,0x47CB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback,0xDD04E5EC,0x7415,0x42AB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMemoryAllocator,0xB36EB6E7,0x9D29,0x4AA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioOutputCallback,0x403C681B,0x7F46,0x4A12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator,0x50FB36CD,0x3063,0x4B73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAPIInformation,0x7BEA3C68,0x730D,0x4322,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput,0xCC5C8A6E,0x3F2F,0x4B3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput,0xAF22762B,0xDFAC,0x4846,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame,0x3F716FE0,0xF023,0x4111,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame,0x69E2639F,0x40DA,0x4E19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame3DExtensions,0xDA0F7E4A,0xEDC7,0x48A8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame,0x05CFE374,0x537C,0x4094,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrameAncillary,0x732E723C,0xD1A4,0x4E29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket,0xE43D5870,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback,0xB1D3F49A,0x85FE,0x4C5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper,0x504E2209,0xCAC7,0x4C1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDX9ScreenPreviewHelper,0x2094B522,0xD1A1,0x40C0,0x9A,0xC7,0x1C,0x01,0x22,0x18,0xEF,0x02); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotificationCallback,0xb002a1ec,0x070d,0x4288,0x82,0x89,0xbd,0x5d,0x36,0xe5,0xff,0x0d); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotification,0x0a1fb207,0xe215,0x441b,0x9b,0x19,0x6f,0xa1,0x57,0x59,0x46,0xc5); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAttributes,0xABC11843,0xD966,0x44CB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkKeyer,0x89AFCAF5,0x65F8,0x421E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion,0x3BBCB8A2,0xDA2C,0x42D9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeviceNotificationCallback,0x4997053B,0x0ADF,0x4CC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDiscovery,0xCDBF631C,0xBC76,0x45FA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator,0x1F2E109A,0x8F4F,0x49E4,0x92,0x03,0x13,0x55,0x95,0xCB,0x6F,0xA5); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkAPIInformation,0x263CA19F,0xED09,0x482E,0x9F,0x9D,0x84,0x00,0x57,0x83,0xA2,0x37); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper,0xF63E77C7,0xB655,0x4A4A,0x9A,0xD0,0x3C,0xA8,0x5D,0x39,0x43,0x43); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDX9ScreenPreviewHelper,0xCC010023,0xE01D,0x4525,0x9D,0x59,0x80,0xC8,0xAB,0x3D,0xC7,0xA0); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion,0x7DBBBB11,0x5B7B,0x467D,0xAE,0xA4,0xCE,0xA4,0x68,0xFD,0x36,0x8C); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDiscovery,0x1073A05C,0xD885,0x47E9,0xB3,0xC6,0x12,0x9B,0x3F,0x9F,0x64,0x8B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v10_2,0xC679A35B,0x610C,0x4D09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v9_9,0xA3EF0963,0x0862,0x44ED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v9_2,0x6D40EF78,0x28B9,0x4E21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback_v8_1,0xE5F693C1,0x4283,0x4716,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v8_1,0x522A9E39,0x0F3C,0x4742,0x94,0xEE,0xD8,0x0D,0xE3,0x35,0xDA,0x1D); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLink_v8_0,0x62BFF75D,0x6569,0x4E55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator_v8_0,0x74E936FC,0xCC28,0x4A67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator_v8_0,0xD9EDA3B3,0x2887,0x41FA,0xB7,0x24,0x01,0x7C,0xF1,0xEB,0x1D,0x37); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v7_9,0xA4D81043,0x0619,0x42B7,0x8E,0xD6,0x60,0x2D,0x29,0x04,0x1D,0xF7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_6,0x455D741F,0x1779,0x4800,0x86,0xF5,0x0B,0x5D,0x13,0xD7,0x97,0x51); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_6,0x87451E84,0x2B7E,0x439E,0xA6,0x29,0x43,0x93,0xEA,0x4A,0x85,0x50); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_6,0x29228142,0xEB8C,0x4141,0xA6,0x21,0xF7,0x40,0x26,0x45,0x09,0x55); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_6,0x300C135A,0x9F43,0x48E2,0x99,0x06,0x6D,0x79,0x11,0xD9,0x3C,0xF1); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode_v7_6,0xEFB9BCA6,0xA521,0x44F7,0xBD,0x69,0x23,0x32,0xF2,0x4D,0x9E,0xE6); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_6,0xA8D8238E,0x6B18,0x4196,0x99,0xE1,0x5A,0xF7,0x17,0xB8,0x3D,0x32); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame_v7_6,0x46FCEE00,0xB4E6,0x43D0,0x91,0xC0,0x02,0x3A,0x7F,0xCE,0xB3,0x4F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_6,0x9A74FA41,0xAE9F,0x47AC,0x8C,0xF4,0x01,0xF4,0x2D,0xD5,0x99,0x65); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback_v7_6,0x373F499D,0x4B4D,0x4518,0xAD,0x22,0x63,0x54,0xE5,0xA5,0x82,0x5E); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper_v7_6,0xBA575CD9,0xA15E,0x497B,0xB2,0xC2,0xF9,0xAF,0xE7,0xBE,0x4E,0xBA); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion_v7_6,0x3EB504C9,0xF97D,0x40FE,0xA1,0x58,0xD4,0x07,0xD4,0x8C,0xB5,0x3B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v7_6,0xB8EAD569,0xB764,0x47F0,0xA7,0x3F,0xAE,0x40,0xDF,0x6C,0xBF,0x10); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_6,0xE763A626,0x4A3C,0x49D1,0xBF,0x13,0xE7,0xAD,0x36,0x92,0xAE,0x52); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_6,0x31D28EE7,0x88B6,0x4CB1,0x89,0x7A,0xCD,0xBF,0x79,0xA2,0x64,0x14); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper_v7_6,0xD398CEE7,0x4434,0x4CA3,0x9B,0xA6,0x5A,0xE3,0x45,0x56,0xB9,0x05); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion_v7_6,0xFFA84F77,0x73BE,0x4FB7,0xB0,0x3E,0xB5,0xE4,0x4B,0x9F,0x75,0x9B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_3,0xFD6F311D,0x4D00,0x444B,0x9E,0xD4,0x1F,0x25,0xB5,0x73,0x0A,0xD0); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_3,0x271C65E3,0xC323,0x4344,0xA3,0x0F,0xD9,0x08,0xBC,0xB2,0x0A,0xA3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_3,0x4973F012,0x9925,0x458C,0x87,0x1C,0x18,0x77,0x4C,0xDB,0xBE,0xCB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_3,0xCF317790,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_1,0xB28131B6,0x59AC,0x4857,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_1,0xAF0CD6D5,0x8376,0x435E,0x84,0x33,0x54,0xF9,0xDD,0x53,0x0A,0xC3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_1,0x333F3A10,0x8C2D,0x43CF,0xB7,0x9D,0x46,0x56,0x0F,0xEE,0xA1,0xCE); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_1,0xC8B41D95,0x8848,0x40EE,0x9B,0x37,0x6E,0x34,0x17,0xFB,0x11,0x4B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket_v7_1,0xC86DE4F6,0xA29F,0x42E3,0xAB,0x3A,0x13,0x63,0xE2,0x9F,0x07,0x88); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_1,0xEBD01AFA,0xE4B0,0x49C6,0xA0,0x1D,0xED,0xB9,0xD1,0xB5,0x5F,0xD9); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_1,0x7F94F328,0x5ED4,0x4E9F,0x97,0x29,0x76,0xA8,0x6B,0xDC,0x99,0xCC); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_1,0xAE5B3E9B,0x4E1E,0x4535,0xB6,0xE8,0x48,0x0F,0xF5,0x2F,0x6C,0xE5); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_1,0x2B54EDEF,0x5B32,0x429F,0xBA,0x11,0xBB,0x99,0x05,0x96,0xEA,0xCD); + +#undef MIDL_DEFINE_GUID + +#ifdef __cplusplus +} +#endif + + + diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index d31e9472168..e549a48d4b9 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -223,6 +223,10 @@ elseif(WITH_X11) ) endif() + if(WITH_X11_ALPHA) + add_definitions(-DWITH_X11_ALPHA) + endif() + if(WITH_INPUT_NDOF) list(APPEND SRC intern/GHOST_NDOFManagerUnix.cpp diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 4c48473c7b8..08045b93db9 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -277,7 +277,7 @@ public: */ virtual GHOST_TSuccess beginFullScreen( const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0) = 0; + const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0) = 0; /** * Updates the resolution while in fullscreen mode. diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index b3e560ab4b4..0dd5d15b011 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -57,7 +57,8 @@ typedef struct { typedef enum { GHOST_glStereoVisual = (1 << 0), - GHOST_glDebugContext = (1 << 1) + GHOST_glDebugContext = (1 << 1), + GHOST_glAlphaBackground = (1 << 2), } GHOST_GLFlags; @@ -529,7 +530,7 @@ typedef struct { #ifdef _WIN32 -typedef long GHOST_TEmbedderWindowID; +typedef void* GHOST_TEmbedderWindowID; #endif // _WIN32 #ifndef _WIN32 diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 90d810b7986..9ac61db4041 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -62,6 +62,7 @@ GHOST_ContextGLX::GHOST_ContextGLX( Window window, Display *display, XVisualInfo *visualInfo, + GLXFBConfig fbconfig, int contextProfileMask, int contextMajorVersion, int contextMinorVersion, @@ -70,6 +71,7 @@ GHOST_ContextGLX::GHOST_ContextGLX( : GHOST_Context(stereoVisual, numOfAASamples), m_display(display), m_visualInfo(visualInfo), + m_fbconfig(fbconfig), m_window(window), m_contextProfileMask(contextProfileMask), m_contextMajorVersion(contextMajorVersion), @@ -153,15 +155,7 @@ void GHOST_ContextGLX::initContextGLXEW() GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() { -#ifdef WITH_X11_XINPUT - /* use our own event handlers to avoid exiting blender, - * this would happen for eg: - * if you open blender, unplug a tablet, then open a new window. */ - XErrorHandler old_handler = XSetErrorHandler (GHOST_X11_ApplicationErrorHandler ); - XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); -#endif - - + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); /* -------------------------------------------------------------------- */ /* Begin Inline Glew */ @@ -285,19 +279,24 @@ const bool GLXEW_ARB_create_context_robustness = attribs[i++] = 0; /* Create a GL 3.x context */ - GLXFBConfig *framebuffer_config = NULL; - { - int glx_attribs[64]; - int fbcount = 0; + if (m_fbconfig) { + m_context = glXCreateContextAttribsARB(m_display, m_fbconfig, s_sharedContext, true, attribs); + } + else { + GLXFBConfig *framebuffer_config = NULL; + { + int glx_attribs[64]; + int fbcount = 0; - GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, true); + GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, false, true); - framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount); - } + framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount); + } - if (framebuffer_config) { - m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs); - XFree(framebuffer_config); + if (framebuffer_config) { + m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs); + XFree(framebuffer_config); + } } } else { @@ -343,11 +342,8 @@ const bool GLXEW_ARB_create_context_robustness = success = GHOST_kFailure; } -#ifdef WITH_X11_XINPUT - /* Restore handler */ - XSetErrorHandler (old_handler); - XSetIOErrorHandler(old_handler_io); -#endif + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); return success; } @@ -401,16 +397,11 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut) int GHOST_X11_GL_GetAttributes( int *attribs, int attribs_max, int samples, bool is_stereo_visual, + bool need_alpha, bool for_fb_config) { int i = 0; -#ifdef GHOST_OPENGL_ALPHA - const bool need_alpha = true; -#else - const bool need_alpha = false; -#endif - #ifdef GHOST_OPENGL_STENCIL const bool need_stencil = true; #else diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index 8c2231a0b01..f0f010d1942 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -66,6 +66,7 @@ public: Window window, Display *display, XVisualInfo *visualInfo, + GLXFBConfig fbconfig, int contextProfileMask, int contextMajorVersion, int contextMinorVersion, @@ -128,6 +129,7 @@ private: Display *m_display; XVisualInfo *m_visualInfo; + GLXFBConfig m_fbconfig; Window m_window; const int m_contextProfileMask; @@ -151,6 +153,7 @@ private: int GHOST_X11_GL_GetAttributes( int *attribs, int attribs_max, int samples, bool is_stereo_visual, + bool need_alpha, bool for_fb_config); #endif // __GHOST_CONTEXTGLX_H__ diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index cb580f60bd7..abce3ea6588 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -63,6 +63,7 @@ static bool is_crappy_intel_card() GHOST_ContextWGL::GHOST_ContextWGL( bool stereoVisual, + bool alphaBackground, GHOST_TUns16 numOfAASamples, HWND hWnd, HDC hDC, @@ -78,6 +79,7 @@ GHOST_ContextWGL::GHOST_ContextWGL( m_contextMajorVersion(contextMajorVersion), m_contextMinorVersion(contextMinorVersion), m_contextFlags(contextFlags), + m_alphaBackground(alphaBackground), m_contextResetNotificationStrategy(contextResetNotificationStrategy), m_hGLRC(NULL) #ifdef WITH_GLEW_MX @@ -168,7 +170,7 @@ GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext() /* Ron Fosner's code for weighting pixel formats and forcing software. * See http://www.opengl.org/resources/faq/technical/weight.cpp */ -static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd) +static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR &preferredPFD) { int weight = 0; @@ -194,11 +196,12 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd) weight += pfd.cColorBits - 8; -#ifdef GHOST_OPENGL_ALPHA - if (pfd.cAlphaBits > 0) + if (preferredPFD.cAlphaBits > 0 && pfd.cAlphaBits > 0) + weight++; +#ifdef WIN32_COMPOSITING + if ((preferredPFD.dwFlags & PFD_SUPPORT_COMPOSITION) && (pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) weight++; #endif - #ifdef GHOST_OPENGL_STENCIL if (pfd.cStencilBits >= 8) weight++; @@ -239,7 +242,7 @@ static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredP WIN32_CHK(check == lastPFD); - int w = weight_pixel_format(pfd); + int w = weight_pixel_format(pfd, preferredPFD); if (w > weight) { weight = w; @@ -496,7 +499,10 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( { std::vector<int> iAttributes; +#define _MAX_PIXEL_FORMATS 32 + int iPixelFormat = 0; + int iPixelFormats[_MAX_PIXEL_FORMATS]; int samples; @@ -521,8 +527,31 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( sRGB); UINT nNumFormats; - WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, 1, &iPixelFormat, &nNumFormats)); - + WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, _MAX_PIXEL_FORMATS, iPixelFormats, &nNumFormats)); + +#ifdef WIN32_COMPOSITING + if (needAlpha && nNumFormats) { + // scan through all pixel format to make sure one supports compositing + PIXELFORMATDESCRIPTOR pfd; + int i; + + for (i = 0; i < nNumFormats; i++) { + if (DescribePixelFormat(m_hDC, iPixelFormats[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { + if (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) { + iPixelFormat = iPixelFormats[i]; + break; + } + } + } + if (i == nNumFormats) { + fprintf(stderr, + "Warning! Unable to find a pixel format with compositing capability.\n"); + iPixelFormat = iPixelFormats[0]; + } + } + else +#endif + iPixelFormat = iPixelFormats[0]; /* total number of formats that match (regardless of size of iPixelFormat array) * see: WGL_ARB_pixel_format extension spec */ if (nNumFormats > 0) @@ -538,7 +567,7 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( // check how many samples were actually gotten if (iPixelFormat != 0) { int iQuery[] = { WGL_SAMPLES_ARB }; - int actualSamples; + int actualSamples, alphaBits; wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples); if (actualSamples != *numOfAASamples) { @@ -549,6 +578,14 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( *numOfAASamples = actualSamples; // set context property to actual value } + if (needAlpha) { + iQuery[0] = WGL_ALPHA_BITS_ARB; + wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &alphaBits); + if (alphaBits == 0) { + fprintf(stderr, + "Warning! Unable to find a frame buffer with alpha channel.\n"); + } + } } else { *numOfAASamples = 0; @@ -670,20 +707,27 @@ int GHOST_ContextWGL::choose_pixel_format( PIXELFORMATDESCRIPTOR preferredPFD = { sizeof(PIXELFORMATDESCRIPTOR), /* size */ 1, /* version */ + (DWORD) ( PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_SWAP_COPY | /* support swap copy */ PFD_DOUBLEBUFFER | /* support double-buffering */ - (stereoVisual ? PFD_STEREO : 0), /* support stereo */ + (stereoVisual ? PFD_STEREO : 0) |/* support stereo */ + ( +#ifdef WIN32_COMPOSITING + needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */ +#endif + 0 + )), PFD_TYPE_RGBA, /* color type */ - 24, /* preferred color depth */ + (BYTE) (needAlpha ? 32 : 24), /* preferred color depth */ 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - needAlpha ? 8 : 0, /* alpha buffer */ + (BYTE) (needAlpha ? 8 : 0), /* alpha buffer */ 0, /* alpha shift (ignored) */ 0, /* no accumulation buffer */ 0, 0, 0, 0, /* accum bits (ignored) */ 24, /* depth buffer */ - needStencil ? 8 : 0, /* stencil buffer */ + (BYTE) (needStencil ? 8 : 0), /* stencil buffer */ 0, /* no auxiliary buffers */ PFD_MAIN_PLANE, /* main layer */ 0, /* reserved */ @@ -727,11 +771,7 @@ static void reportContextString(const char *name, const char *dummy, const char GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() { -#ifdef GHOST_OPENGL_ALPHA - const bool needAlpha = true; -#else - const bool needAlpha = false; -#endif + const bool needAlpha = m_alphaBackground; #ifdef GHOST_OPENGL_STENCIL const bool needStencil = true; diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index 3b04a33b662..580b4dcb82f 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -32,6 +32,8 @@ #ifndef __GHOST_CONTEXTWGL_H__ #define __GHOST_CONTEXTWGL_H__ +//#define WIN32_COMPOSITING + #include "GHOST_Context.h" #ifdef WITH_GLEW_MX @@ -65,6 +67,7 @@ public: */ GHOST_ContextWGL( bool stereoVisual, + bool alphaBackground, GHOST_TUns16 numOfAASamples, HWND hWnd, HDC hDC, @@ -164,6 +167,7 @@ private: const int m_contextMajorVersion; const int m_contextMinorVersion; const int m_contextFlags; + const bool m_alphaBackground; const int m_contextResetNotificationStrategy; HGLRC m_hGLRC; diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 96ff79aa65a..cbf37bf1b16 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -125,8 +125,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWO */ HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - if (m_window->canAcceptDragOperation()) - { + if (m_window->canAcceptDragOperation()) { *pdwEffect = allowedDropEffect(*pdwEffect); } else { @@ -154,8 +153,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { void *data = getGhostData(pDataObject); - if (m_window->canAcceptDragOperation()) - { + if (m_window->canAcceptDragOperation()) { *pdwEffect = allowedDropEffect(*pdwEffect); } @@ -189,15 +187,13 @@ GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObje * conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS. */ FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) - { + if (pDataObject->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeString; } // Filesnames fmtetc.cfFormat = CF_HDROP; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) - { + if (pDataObject->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeFilenames; } diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp index bc531bd515b..0675ac734ed 100644 --- a/intern/ghost/intern/GHOST_EventManager.cpp +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -167,11 +167,9 @@ void GHOST_EventManager::removeWindowEvents(GHOST_IWindow *window) { TEventStack::iterator iter; iter = m_events.begin(); - while (iter != m_events.end()) - { + while (iter != m_events.end()) { GHOST_IEvent *event = *iter; - if (event->getWindow() == window) - { + if (event->getWindow() == window) { GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n"); /* * Found an event for this window, remove it. @@ -191,11 +189,9 @@ void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow * { TEventStack::iterator iter; iter = m_events.begin(); - while (iter != m_events.end()) - { + while (iter != m_events.end()) { GHOST_IEvent *event = *iter; - if ((event->getType() == type) && (!window || (event->getWindow() == window))) - { + if ((event->getType() == type) && (!window || (event->getWindow() == window))) { GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n"); /* * Found an event of this type for the window, remove it. diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index af5a2ed7097..96bd12faef8 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -64,7 +64,7 @@ bool GHOST_ImeWin32::SetInputLanguage() * while composing a text. */ HKL keyboard_layout = ::GetKeyboardLayout(0); - input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout); + input_language_id_ = LOWORD(keyboard_layout); ime_status_ = ::ImmIsIME(keyboard_layout); return ime_status_; } diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index 27285e49e9e..c8e14ad357f 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -299,6 +299,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ m_buttonMask = 0x07C0F137; m_hidMap = Modern3Dx_HID_map; break; + case 0xC633: + puts("ndof: using SpaceMouse Enterprise"); + m_deviceType = NDOF_SpaceMouseEnterprise; + m_buttonCount = 31; + m_hidMap = Modern3Dx_HID_map; + break; default: printf("ndof: unknown 3Dconnexion product %04hx\n", product_id); @@ -372,8 +378,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64 NDOF_ButtonT button = (button_number < m_buttonCount) ? m_hidMap[button_number] : NDOF_BUTTON_NONE; - switch (button) - { + switch (button) { case NDOF_BUTTON_NONE: #ifdef DEBUG_NDOF_BUTTONS printf("discarded\n"); diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index ba82f37bb2a..d3c70bbac50 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -40,6 +40,7 @@ typedef enum { NDOF_SpaceMousePro, NDOF_SpaceMouseWireless, NDOF_SpaceMouseProWireless, + NDOF_SpaceMouseEnterprise, // older devices NDOF_SpacePilot, diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 639ce451d23..c53580818e6 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -140,7 +140,7 @@ bool GHOST_System::validWindow(GHOST_IWindow *window) GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples) + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples) { GHOST_TSuccess success = GHOST_kFailure; GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager"); @@ -152,7 +152,7 @@ GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting); if (success == GHOST_kSuccess) { //GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); - success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, numOfAASamples); + success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, alphaBackground, numOfAASamples); if (success == GHOST_kSuccess) { m_windowManager->beginFullScreen(*window, stereoVisual); } @@ -349,12 +349,14 @@ GHOST_TSuccess GHOST_System::exit() } GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples) + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples) { GHOST_GLSettings glSettings = {0}; if (stereoVisual) glSettings.flags |= GHOST_glStereoVisual; + if (alphaBackground) + glSettings.flags |= GHOST_glAlphaBackground; glSettings.numOfAASamples = numOfAASamples; /* note: don't use getCurrentDisplaySetting() because on X11 we may diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index c4951adb4fd..a10259bc9e9 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -144,8 +144,8 @@ public: * \return Indication of success. */ GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0); - + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples = 0); + /** * Updates the resolution while in fullscreen mode. * \param setting The new setting of the display. @@ -336,7 +336,7 @@ protected: * \return Indication of success. */ GHOST_TSuccess createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0); + const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0); /** The display manager (platform dependent). */ GHOST_DisplayManager *m_displayManager; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index c9855cfdf7e..bce390732fe 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -830,7 +830,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, window->updateDrawingContext(); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); //Mouse up event is trapped by the resizing event loop, so send it anyway to the window manager - pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, convertButton(0))); + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); //m_ignoreWindowSizedMessages = true; } break; @@ -1278,19 +1278,29 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) switch ([event type]) { case NSLeftMouseDown: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSRightMouseDown: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSOtherMouseDown: pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); - //Handle tablet events combined with mouse events - handleTabletEvent(event); + handleTabletEvent(event); //Handle tablet events combined with mouse events break; case NSLeftMouseUp: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSRightMouseUp: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSOtherMouseUp: pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); - //Handle tablet events combined with mouse events - handleTabletEvent(event); + handleTabletEvent(event); //Handle tablet events combined with mouse events break; case NSLeftMouseDragged: diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp index 2bd380050f1..7d0ce5158fe 100644 --- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp @@ -76,8 +76,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *version HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16); - if (hResult == S_OK) - { + if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); strcat(knownpath, "\\Blender Foundation\\Blender\\"); strcat(knownpath, versionstr); @@ -94,8 +93,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16); - if (hResult == S_OK) - { + if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); strcat(knownpath, "\\Blender Foundation\\Blender\\"); strcat(knownpath, versionstr); diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 43fb5dc4205..1ce8002520f 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -241,6 +241,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow( state, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), + ((glSettings.flags & GHOST_glAlphaBackground) != 0), glSettings.numOfAASamples, parentWindow, ((glSettings.flags & GHOST_glDebugContext) != 0)); @@ -408,7 +409,11 @@ GHOST_TSuccess GHOST_SystemWin32::init() ::LoadIcon(NULL, IDI_APPLICATION); } wc.hCursor = ::LoadCursor(0, IDC_ARROW); - wc.hbrBackground = 0; + wc.hbrBackground = +#ifdef INW32_COMPISITING + (HBRUSH)CreateSolidBrush +#endif + (0x00000000); wc.lpszMenuName = 0; wc.lpszClassName = L"GHOST_WindowClass"; @@ -1540,8 +1545,7 @@ static bool isStartedFromCommandPrompt() int GHOST_SystemWin32::toggleConsole(int action) { - switch (action) - { + switch (action) { case 3: // startup: hide if not started from command prompt { if (isStartedFromCommandPrompt()) { diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index c9946c13122..727bc9a01fb 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -61,6 +61,11 @@ #include <X11/XF86keysym.h> #endif +/* for XIWarpPointer */ +#ifdef WITH_X11_XINPUT +# include <X11/extensions/XInput2.h> +#endif + /* For timing */ #include <sys/time.h> #include <unistd.h> @@ -73,6 +78,10 @@ /* for debugging - so we can breakpoint X11 errors */ // #define USE_X11_ERROR_HANDLERS +#ifdef WITH_X11_XINPUT +# define USE_XINPUT_HOTPLUG +#endif + /* see [#34039] Fix Alt key glitch on Unity desktop */ #define USE_UNITY_WORKAROUND @@ -169,11 +178,36 @@ GHOST_SystemX11( } #ifdef WITH_X11_XINPUT + /* detect if we have xinput (for reuse) */ + { + memset(&m_xinput_version, 0, sizeof(m_xinput_version)); + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + if (version && (version != (XExtensionVersion *)NoSuchExtension)) { + if (version->present) { + m_xinput_version = *version; + } + XFree(version); + } + } + +#ifdef USE_XINPUT_HOTPLUG + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + DevicePresence(m_display, xi_presence, class_presence); + XSelectExtensionEvent( + m_display, + RootWindow(m_display, DefaultScreen(m_display)), + &class_presence, 1); + (void)xi_presence; + } +#endif /* USE_XINPUT_HOTPLUG */ + /* initialize incase X11 fails to load */ memset(&m_xtablet, 0, sizeof(m_xtablet)); - initXInputDevices(); -#endif + refreshXInputDevices(); +#endif /* WITH_X11_XINPUT */ } GHOST_SystemX11:: @@ -310,6 +344,7 @@ createWindow(const STR_String& title, left, top, width, height, state, parentWindow, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, + ((glSettings.flags & GHOST_glAlphaBackground) != 0), glSettings.numOfAASamples, (glSettings.flags & GHOST_glDebugContext) != 0); if (window) { @@ -419,8 +454,7 @@ static Bool init_timestamp_scanner(Display *, XEvent *event, XPointer arg) { init_timestamp_data *data = reinterpret_cast<init_timestamp_data *>(arg); - switch (event->type) - { + switch (event->type) { case ButtonPress: case ButtonRelease: data->timestamp = event->xbutton.time; @@ -627,8 +661,13 @@ static bool checkTabletProximity(Display *display, XDevice *device) return false; } + /* needed since unplugging will abort() without this */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); + state = XQueryDeviceState(display, device); + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); + if (state) { XInputClass *cls = state->data; // printf("%d class%s :\n", state->num_classes, @@ -661,6 +700,41 @@ GHOST_SystemX11::processEvent(XEvent *xe) GHOST_WindowX11 *window = findGhostWindow(xe->xany.window); GHOST_Event *g_event = NULL; +#ifdef USE_XINPUT_HOTPLUG + /* Hot-Plug support */ + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + + DevicePresence(m_display, xi_presence, class_presence); + (void)class_presence; + + if (xe->type == xi_presence) { + XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe; + if ((notify_event->devchange == DeviceEnabled) || + (notify_event->devchange == DeviceDisabled) || + (notify_event->devchange == DeviceAdded) || + (notify_event->devchange == DeviceRemoved)) + { + refreshXInputDevices(); + + /* update all window events */ + { + vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); + vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); + vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it); + window->refreshXInputDevices(); + } + } + } + } + } +#endif /* USE_XINPUT_HOTPLUG */ + + if (!window) { return; } @@ -680,7 +754,6 @@ GHOST_SystemX11::processEvent(XEvent *xe) } } #endif /* WITH_X11_XINPUT */ - switch (xe->type) { case Expose: { @@ -1401,7 +1474,22 @@ setCursorPosition( int relx = x - cx; int rely = y - cy; - XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely); +#ifdef WITH_X11_XINPUT + if ((m_xinput_version.present) && + (m_xinput_version.major_version >= 2)) + { + /* Needed to account for XInput "Coordinate Transformation Matrix", see T48901 */ + int device_id; + if (XIGetClientPointer(m_display, None, &device_id) != False) { + XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely); + } + } + else +#endif + { + XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely); + } + XSync(m_display, 0); /* Sync to process all requests */ return GHOST_kSuccess; @@ -1917,11 +2005,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, ); } #endif - -#if defined(USE_X11_ERROR_HANDLERS) || defined(WITH_X11_XINPUT) -/* +/** * These callbacks can be used for debugging, so we can breakpoint 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 @@ -1952,7 +2037,6 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/) /* No exit! - but keep lint happy */ return 0; } -#endif #ifdef WITH_X11_XINPUT /* These C functions are copied from Wine 1.1.13's wintab.c */ @@ -1963,8 +2047,7 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/) static bool match_token(const char *haystack, const char *needle) { const char *p, *q; - for (p = haystack; *p; ) - { + for (p = haystack; *p; ) { while (*p && isspace(*p)) p++; if (!*p) @@ -2050,23 +2133,27 @@ static BOOL is_eraser(const char *name, const char *type) #undef FALSE /* end code copied from wine */ -void GHOST_SystemX11::initXInputDevices() +void GHOST_SystemX11::refreshXInputDevices() { - static XErrorHandler old_handler = (XErrorHandler) 0; - static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0; + if (m_xinput_version.present) { - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + if (m_xtablet.StylusDevice) { + XCloseDevice(m_display, m_xtablet.StylusDevice); + m_xtablet.StylusDevice = NULL; + } + + if (m_xtablet.EraserDevice) { + XCloseDevice(m_display, m_xtablet.EraserDevice); + m_xtablet.EraserDevice = NULL; + } - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { + /* Install our error handler to override Xlib's termination behavior */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); + + { int device_count; XDeviceInfo *device_info = XListInputDevices(m_display, &device_count); - m_xtablet.StylusDevice = NULL; - m_xtablet.EraserDevice = NULL; - /* Install our error handler to override Xlib's termination behavior */ - old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler); - old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); for (int i = 0; i < device_count; ++i) { char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL; @@ -2125,13 +2212,10 @@ void GHOST_SystemX11::initXInputDevices() } } - /* Restore handler */ - (void) XSetErrorHandler(old_handler); - (void) XSetIOErrorHandler(old_handler_io); - XFreeDeviceList(device_info); } - XFree(version); + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); } } diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index a0088dbe8f0..e60cab6a194 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -52,6 +52,20 @@ int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); int GHOST_X11_ApplicationIOErrorHandler(Display *display); +#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \ + struct { \ + XErrorHandler handler; \ + XIOErrorHandler handler_io; \ + } var = { \ + XSetErrorHandler(GHOST_X11_ApplicationErrorHandler), \ + XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler), \ + } + +#define GHOST_X11_ERROR_HANDLERS_RESTORE(var) \ + { \ + (void)XSetErrorHandler(var.handler); \ + (void)XSetIOErrorHandler(var.handler_io); \ + } ((void)0) class GHOST_WindowX11; @@ -328,6 +342,10 @@ public: #endif } m_atom; +#ifdef WITH_X11_XINPUT + XExtensionVersion m_xinput_version; +#endif + private: Display *m_display; @@ -367,7 +385,7 @@ private: #endif #ifdef WITH_X11_XINPUT - void initXInputDevices(); + void refreshXInputDevices(); #endif GHOST_WindowX11 * diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 81c08f4fc06..6a27d7aadf9 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -43,7 +43,9 @@ #else # include "GHOST_ContextWGL.h" #endif - +#ifdef WIN32_COMPOSITING +#include <Dwmapi.h> +#endif #include <math.h> #include <string.h> @@ -70,7 +72,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, - bool wantStereoVisual, + bool wantStereoVisual, + bool alphaBackground, GHOST_TUns16 wantNumOfAASamples, GHOST_TEmbedderWindowID parentwindowhwnd, bool is_debug) @@ -83,6 +86,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_hasGrabMouse(false), m_nPressedButtons(0), m_customCursor(0), + m_wantAlphaBackground(alphaBackground), m_wintab(NULL), m_tabletData(NULL), m_tablet(0), @@ -91,31 +95,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { - OSVERSIONINFOEX versionInfo; - bool hasMinVersionForTaskbar = false; - - ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX)); - - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - } - else { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - if (state != GHOST_kWindowStateFullScreen) { RECT rect; MONITORINFO monitor; @@ -181,17 +160,17 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); m_hWnd = ::CreateWindowW( - s_windowClassName, // pointer to registered class name - title_16, // pointer to window name - wintype, // window style - left, // horizontal position of window - top, // vertical position of window - width, // window width - height, // window height - (HWND) m_parentWindowHwnd, // handle to parent or owner window - 0, // handle to menu or child-window identifier - ::GetModuleHandle(0), // handle to application instance - 0); // pointer to window-creation data + s_windowClassName, // pointer to registered class name + title_16, // pointer to window name + wintype, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + (HWND)m_parentWindowHwnd, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data free(title_16); } else { @@ -243,6 +222,24 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } ::ShowWindow(m_hWnd, nCmdShow); +#ifdef WIN32_COMPOSITING + if (alphaBackground && parentwindowhwnd == 0) { + + HRESULT hr = S_OK; + + // Create and populate the Blur Behind structure + DWM_BLURBEHIND bb = { 0 }; + + // Enable Blur Behind and apply to the entire client area + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.fEnable = true; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + + // Apply Blur Behind + hr = DwmEnableBlurBehindWindow(m_hWnd, &bb); + DeleteObject(bb.hRgnBlur); + } +#endif // Force an initial paint of the window ::UpdateWindow(m_hWnd); } @@ -319,11 +316,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } } } - - if (hasMinVersionForTaskbar) - CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar); - else - m_Bar = NULL; + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } @@ -622,6 +615,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #if defined(WITH_GL_PROFILE_CORE) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, @@ -632,6 +626,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #elif defined(WITH_GL_PROFILE_ES20) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, @@ -642,6 +637,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #elif defined(WITH_GL_PROFILE_COMPAT) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index b508c2f37df..a1cf58c9ceb 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -89,6 +89,7 @@ public: GHOST_TWindowState state, GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, bool wantStereoVisual = false, + bool alphaBackground = false, GHOST_TUns16 wantNumOfAASamples = 0, GHOST_TEmbedderWindowID parentWindowHwnd = 0, bool is_debug = false); @@ -328,6 +329,8 @@ private: int m_nPressedButtons; /** HCURSOR structure of the custom cursor */ HCURSOR m_customCursor; + /** request GL context aith alpha channel */ + bool m_wantAlphaBackground; /** ITaskbarList3 structure for progress bar*/ ITaskbarList3 *m_Bar; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index e68e0901dab..ec2b65e67d0 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -33,7 +33,9 @@ #include <X11/cursorfont.h> #include <X11/Xatom.h> #include <X11/Xutil.h> - +#ifdef WITH_X11_ALPHA +#include <X11/extensions/Xrender.h> +#endif #include "GHOST_WindowX11.h" #include "GHOST_SystemX11.h" #include "STR_String.h" @@ -49,6 +51,11 @@ # include "GHOST_ContextGLX.h" #endif +/* for XIWarpPointer */ +#ifdef WITH_X11_XINPUT +# include <X11/extensions/XInput2.h> +#endif + #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) # include <strings.h> #endif @@ -164,15 +171,21 @@ static const unsigned long BLENDER_ICON_48x48x32[] = { static XVisualInfo *x11_visualinfo_from_glx( Display *display, - bool stereoVisual, GHOST_TUns16 *r_numOfAASamples) + bool stereoVisual, + GHOST_TUns16 *r_numOfAASamples, + bool needAlpha, + GLXFBConfig *fbconfig) { - XVisualInfo *visualInfo = NULL; + XVisualInfo *visual = NULL; GHOST_TUns16 numOfAASamples = *r_numOfAASamples; + int glx_major, glx_minor, glx_version; /* GLX version: major.minor */ GHOST_TUns16 actualSamples; + int glx_attribs[64]; + + *fbconfig = NULL; /* Set up the minimum attributes that we require and see if * X can find us a visual matching those requirements. */ - int glx_major, glx_minor; /* GLX version: major.minor */ if (!glXQueryVersion(display, &glx_major, &glx_minor)) { fprintf(stderr, @@ -182,53 +195,118 @@ static XVisualInfo *x11_visualinfo_from_glx( return NULL; } + glx_version = glx_major*100 + glx_minor; - /* GLX >= 1.4 required for multi-sample */ - if ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4)) { + if (glx_version >= 104) { actualSamples = numOfAASamples; } else { numOfAASamples = 0; actualSamples = 0; } + +#ifdef WITH_X11_ALPHA + if ( needAlpha + && glx_version >= 103 + && (glXChooseFBConfig || + (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXChooseFBConfig")) != NULL) + && (glXGetVisualFromFBConfig || + (glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVisualFromFBConfig")) != NULL) + ) { + GLXFBConfig *fbconfigs; + int nbfbconfig; + int i; + + for (;;) { + + GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, true); + + fbconfigs = glXChooseFBConfig(display, DefaultScreen(display), glx_attribs, &nbfbconfig); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (nbfbconfig > 0) { + /* take a frame buffer config that has alpha cap */ + for (i=0 ;i<nbfbconfig; i++) { + visual = (XVisualInfo*)glXGetVisualFromFBConfig(display, fbconfigs[i]); + if (!visual) + continue; + /* if we don't need a alpha background, the first config will do, otherwise + * test the alphaMask as it won't necessarily be present */ + if (needAlpha) { + XRenderPictFormat *pict_format = XRenderFindVisualFormat(display, visual->visual); + if (!pict_format) + continue; + if (pict_format->direct.alphaMask <= 0) + continue; + } + *fbconfig = fbconfigs[i]; + break; + } + XFree(fbconfigs); + if (i<nbfbconfig) { + if (actualSamples < numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + } + break; + } + visual = NULL; + } - /* Find the display with highest samples, starting at level requested */ - for (;;) { - int glx_attribs[64]; - - GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, false); - - visualInfo = glXChooseVisual(display, DefaultScreen(display), glx_attribs); - - /* Any sample level or even zero, which means oversampling disabled, is good - * but we need a valid visual to continue */ - if (visualInfo != NULL) { - if (actualSamples < numOfAASamples) { + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ fprintf(stderr, - "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " - "Substituting one that uses %d samples.\n", - numOfAASamples, actualSamples); + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + return NULL; + } + else { + --actualSamples; } - break; } + } + else +#endif + { + /* legacy, don't use extension */ + for (;;) { + GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false); + + visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (visual != NULL) { + if (actualSamples < numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + } + break; + } - if (actualSamples == 0) { - /* All options exhausted, cannot continue */ - fprintf(stderr, - "%s:%d: X11 glXChooseVisual() failed, " - "verify working openGL system!\n", - __FILE__, __LINE__); + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ + fprintf(stderr, + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); - return NULL; - } - else { - --actualSamples; + return NULL; + } + else { + --actualSamples; + } } } - *r_numOfAASamples = actualSamples; - - return visualInfo; + return visual; } GHOST_WindowX11:: @@ -244,10 +322,12 @@ GHOST_WindowX11(GHOST_SystemX11 *system, GHOST_TDrawingContextType type, const bool stereoVisual, const bool exclusive, + const bool alphaBackground, const GHOST_TUns16 numOfAASamples, const bool is_debug) : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples), m_display(display), m_visualInfo(NULL), + m_fbconfig(NULL), m_normal_state(GHOST_kWindowStateNormal), m_system(system), m_invalid_window(false), @@ -264,7 +344,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, m_is_debug_context(is_debug) { if (type == GHOST_kDrawingContextTypeOpenGL) { - m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples); + m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples, alphaBackground, (GLXFBConfig*)&m_fbconfig); } else { XVisualInfo tmp = {0}; @@ -491,7 +571,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, } #ifdef WITH_X11_XINPUT - initXInputDevices(); + refreshXInputDevices(); m_tabletData.Active = GHOST_kTabletModeNone; #endif @@ -558,45 +638,40 @@ bool GHOST_WindowX11::createX11_XIC() #endif #ifdef WITH_X11_XINPUT -void GHOST_WindowX11::initXInputDevices() +void GHOST_WindowX11::refreshXInputDevices() { - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); - - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { - GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); - XEventClass xevents[8], ev; - int dcount = 0; - - /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets - * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, - * otherwise we do not get any tablet motion event once pen is pressed... See T43367. - */ - - if (xtablet.StylusDevice) { - DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); - if (ev) xevents[dcount++] = ev; - } - if (xtablet.EraserDevice) { - DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); - if (ev) xevents[dcount++] = ev; - } + if (m_system->m_xinput_version.present) { + GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); + XEventClass xevents[8], ev; + int dcount = 0; + + /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, + * otherwise we do not get any tablet motion event once pen is pressed... See T43367. + */ - XSelectExtensionEvent(m_display, m_window, xevents, dcount); + if (xtablet.StylusDevice) { + DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); + if (ev) xevents[dcount++] = ev; + } + if (xtablet.EraserDevice) { + DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); + if (ev) xevents[dcount++] = ev; } - XFree(version); + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); } } @@ -1240,6 +1315,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 3, 2, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), @@ -1251,6 +1327,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, 2, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), @@ -1262,6 +1339,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, 0, // profile bit 0, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), @@ -1447,7 +1525,21 @@ setWindowCursorGrab( /* use to generate a mouse move event, otherwise the last event * blender gets can be outside the screen causing menus not to show * properly unless the user moves the mouse */ - XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0); + +#ifdef WITH_X11_XINPUT + if ((m_system->m_xinput_version.present) && + (m_system->m_xinput_version.major_version >= 2)) + { + int device_id; + if (XIGetClientPointer(m_display, None, &device_id) != False) { + XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, 0, 0); + } + } + else +#endif + { + XWarpPointer(m_display, None, None, 0, 0, 0, 0, 0, 0); + } } /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 5beb7b43032..9380aa9d631 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -73,6 +73,7 @@ public: * \param parentWindow Parent (embedder) window * \param type The type of drawing context installed in this window. * \param stereoVisual Stereo visual for quad buffered stereo. + * \param alphaBackground Enable alpha blending of window with display background * \param numOfAASamples Number of samples used for AA (zero if no AA) */ GHOST_WindowX11( @@ -88,6 +89,7 @@ public: GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, const bool stereoVisual = false, const bool exclusive = false, + const bool alphaBackground = false, const GHOST_TUns16 numOfAASamples = 0, const bool is_debug = false ); @@ -210,6 +212,10 @@ public: bool createX11_XIC(); #endif +#ifdef WITH_X11_XINPUT + void refreshXInputDevices(); +#endif + #ifdef WITH_XDND GHOST_DropTargetX11 *getDropTarget() { @@ -313,14 +319,11 @@ private: Cursor getEmptyCursor( ); - -#ifdef WITH_X11_XINPUT - void initXInputDevices(); -#endif Window m_window; Display *m_display; XVisualInfo *m_visualInfo; + void *m_fbconfig; GHOST_TWindowState m_normal_state; diff --git a/intern/gpudirect/CMakeLists.txt b/intern/gpudirect/CMakeLists.txt new file mode 100644 index 00000000000..88c09a663b8 --- /dev/null +++ b/intern/gpudirect/CMakeLists.txt @@ -0,0 +1,41 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2015, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Foundation. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + # XXX, bad level include! + ../../source/blender/blenlib +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + +set(SRC + dvpapi.cpp + dvpapi.h +) + +blender_add_lib(bf_intern_gpudirect "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/gpudirect/dvpapi.cpp b/intern/gpudirect/dvpapi.cpp new file mode 100644 index 00000000000..56b58e0a348 --- /dev/null +++ b/intern/gpudirect/dvpapi.cpp @@ -0,0 +1,147 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpudirect/dvpapi.c + * \ingroup gpudirect + */ + +#ifdef WIN32 + +#include <stdlib.h> +#include "dvpapi.h" + +extern "C" { +#include "BLI_dynlib.h" +} + +#define KDVPAPI_Name "dvp.dll" + +typedef DVPStatus (DVPAPIENTRY * PFNDVPINITGLCONTEXT) (uint32_t flags); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCLOSEGLCONTEXT) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPGETLIBRARYVERSION)(uint32_t *major, uint32_t *minor); + +static uint32_t __dvpMajorVersion = 0; +static uint32_t __dvpMinorVersion = 0; +static PFNDVPGETLIBRARYVERSION __dvpGetLibrayVersion = NULL; +static PFNDVPINITGLCONTEXT __dvpInitGLContext = NULL; +static PFNDVPCLOSEGLCONTEXT __dvpCloseGLContext = NULL; +PFNDVPBEGIN __dvpBegin = NULL; +PFNDVPEND __dvpEnd = NULL; +PFNDVPCREATEBUFFER __dvpCreateBuffer = NULL; +PFNDVPDESTROYBUFFER __dvpDestroyBuffer = NULL; +PFNDVPFREEBUFFER __dvpFreeBuffer = NULL; +PFNDVPMEMCPYLINED __dvpMemcpyLined = NULL; +PFNDVPMEMCPY __dvpMemcpy = NULL; +PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject = NULL; +PFNDVPFREESYNCOBJECT __dvpFreeSyncObject = NULL; +PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI = NULL; +PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP = NULL; +PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP = NULL; +PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI = NULL; +PFNDVPBINDTOGLCTX __dvpBindToGLCtx = NULL; +PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx = NULL; +PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL = NULL; +PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx = NULL; + +static DynamicLibrary *__dvpLibrary = NULL; + +DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor) +{ + if (!__dvpLibrary) + return DVP_STATUS_ERROR; + *major = __dvpMajorVersion; + *minor = __dvpMinorVersion; + return DVP_STATUS_OK; +} + +DVPStatus dvpInitGLContext(uint32_t flags) +{ + DVPStatus status; + if (!__dvpLibrary) { + __dvpLibrary = BLI_dynlib_open(KDVPAPI_Name); + if (!__dvpLibrary) { + return DVP_STATUS_ERROR; + } +// "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z"; + __dvpInitGLContext = (PFNDVPINITGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z"); + __dvpCloseGLContext = (PFNDVPCLOSEGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCloseGLContext@@YA?AW4DVPStatus@@XZ"); + __dvpGetLibrayVersion = (PFNDVPGETLIBRARYVERSION)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetLibrayVersion@@YA?AW4DVPStatus@@PEAI0@Z"); + __dvpBegin = (PFNDVPBEGIN)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBegin@@YA?AW4DVPStatus@@XZ"); + __dvpEnd = (PFNDVPEND)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpEnd@@YA?AW4DVPStatus@@XZ"); + __dvpCreateBuffer = (PFNDVPCREATEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateBuffer@@YA?AW4DVPStatus@@PEAUDVPSysmemBufferDescRec@@PEA_K@Z"); + __dvpDestroyBuffer = (PFNDVPDESTROYBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpDestroyBuffer@@YA?AW4DVPStatus@@_K@Z"); + __dvpFreeBuffer = (PFNDVPFREEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeBuffer@@YA?AW4DVPStatus@@_K@Z"); + __dvpMemcpyLined = (PFNDVPMEMCPYLINED)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpyLined@@YA?AW4DVPStatus@@_K0I000III@Z"); + __dvpMemcpy = (PFNDVPMEMCPY)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpy2D@@YA?AW4DVPStatus@@_K0I000IIIII@Z"); + __dvpImportSyncObject = (PFNDVPIMPORTSYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpImportSyncObject@@YA?AW4DVPStatus@@PEAUDVPSyncObjectDescRec@@PEA_K@Z"); + __dvpFreeSyncObject = (PFNDVPFREESYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeSyncObject@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferEndAPI = (PFNDVPMAPBUFFERENDAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndAPI@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferWaitDVP = (PFNDVPMAPBUFFERWAITDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitDVP@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferEndDVP = (PFNDVPMAPBUFFERENDDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndDVP@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferWaitAPI = (PFNDVPMAPBUFFERWAITAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitAPI@@YA?AW4DVPStatus@@_K@Z"); + __dvpBindToGLCtx = (PFNDVPBINDTOGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBindToGLCtx@@YA?AW4DVPStatus@@_K@Z"); + __dvpGetRequiredConstantsGLCtx = (PFNDVPGETREQUIREDCONSTANTSGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetRequiredConstantsGLCtx@@YA?AW4DVPStatus@@PEAI00000@Z"); + __dvpCreateGPUTextureGL = (PFNDVPCREATEGPUTEXTUREGL)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateGPUTextureGL@@YA?AW4DVPStatus@@IPEA_K@Z"); + __dvpUnbindFromGLCtx = (PFNDVPUNBINDFROMGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpUnbindFromGLCtx@@YA?AW4DVPStatus@@_K@Z"); + if (!__dvpInitGLContext || + !__dvpCloseGLContext || + !__dvpGetLibrayVersion || + !__dvpBegin || + !__dvpEnd || + !__dvpCreateBuffer || + !__dvpDestroyBuffer || + !__dvpFreeBuffer || + !__dvpMemcpyLined || + !__dvpMemcpy || + !__dvpImportSyncObject || + !__dvpFreeSyncObject || + !__dvpMapBufferEndAPI || + !__dvpMapBufferWaitDVP || + !__dvpMapBufferEndDVP || + !__dvpMapBufferWaitAPI || + !__dvpBindToGLCtx || + !__dvpGetRequiredConstantsGLCtx || + !__dvpCreateGPUTextureGL || + !__dvpUnbindFromGLCtx) + { + return DVP_STATUS_ERROR; + } + // check that the library version is what we want + if ((status = __dvpGetLibrayVersion(&__dvpMajorVersion, &__dvpMinorVersion)) != DVP_STATUS_OK) + return status; + if (__dvpMajorVersion != DVP_MAJOR_VERSION || __dvpMinorVersion < DVP_MINOR_VERSION) + return DVP_STATUS_ERROR; + } + return (!__dvpInitGLContext) ? DVP_STATUS_ERROR : __dvpInitGLContext(flags); +} + +DVPStatus dvpCloseGLContext(void) +{ + return (!__dvpCloseGLContext) ? DVP_STATUS_ERROR : __dvpCloseGLContext(); +} + +#endif // WIN32 diff --git a/intern/gpudirect/dvpapi.h b/intern/gpudirect/dvpapi.h new file mode 100644 index 00000000000..cafc4e862ae --- /dev/null +++ b/intern/gpudirect/dvpapi.h @@ -0,0 +1,667 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpudirect/dvpapi.h + * \ingroup gpudirect + */ + +#ifndef __DVPAPI_H__ +#define __DVPAPI_H__ + +#ifdef WIN32 + +#include <stdlib.h> +#include <stdint.h> + +#include "GL/glew.h" + +#if defined(__GNUC__) && __GNUC__>=4 +# define DVPAPI extern __attribute__ ((visibility("default"))) +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define DVPAPI extern __global +#else +# define DVPAPI extern +#endif + +#define DVPAPIENTRY +#define DVP_MAJOR_VERSION 1 +#define DVP_MINOR_VERSION 63 + +typedef uint64_t DVPBufferHandle; +typedef uint64_t DVPSyncObjectHandle; + +typedef enum { + DVP_STATUS_OK = 0, + DVP_STATUS_INVALID_PARAMETER = 1, + DVP_STATUS_UNSUPPORTED = 2, + DVP_STATUS_END_ENUMERATION = 3, + DVP_STATUS_INVALID_DEVICE = 4, + DVP_STATUS_OUT_OF_MEMORY = 5, + DVP_STATUS_INVALID_OPERATION = 6, + DVP_STATUS_TIMEOUT = 7, + DVP_STATUS_INVALID_CONTEXT = 8, + DVP_STATUS_INVALID_RESOURCE_TYPE = 9, + DVP_STATUS_INVALID_FORMAT_OR_TYPE = 10, + DVP_STATUS_DEVICE_UNINITIALIZED = 11, + DVP_STATUS_UNSIGNALED = 12, + DVP_STATUS_SYNC_ERROR = 13, + DVP_STATUS_SYNC_STILL_BOUND = 14, + DVP_STATUS_ERROR = -1, +} DVPStatus; + +// Pixel component formats stored in the system memory buffer +// analogous to those defined in the OpenGL API, except for +// DVP_BUFFER and the DVP_CUDA_* types. DVP_BUFFER provides +// an unspecified format type to allow for general interpretation +// of the bytes at a later stage (in GPU shader). Note that not +// all paths will achieve optimal speeds due to lack of HW support +// for the transformation. The CUDA types are to be used when +// copying to/from a system memory buffer from-to a CUDA array, as the +// CUDA array implies a memory layout that matches the array. +typedef enum { + DVP_BUFFER, // Buffer treated as a raw buffer + // and copied directly into GPU buffer + // without any interpretation of the + // stored bytes. + DVP_DEPTH_COMPONENT, + DVP_RGBA, + DVP_BGRA, + DVP_RED, + DVP_GREEN, + DVP_BLUE, + DVP_ALPHA, + DVP_RGB, + DVP_BGR, + DVP_LUMINANCE, + DVP_LUMINANCE_ALPHA, + DVP_CUDA_1_CHANNEL, + DVP_CUDA_2_CHANNELS, + DVP_CUDA_4_CHANNELS, + DVP_RGBA_INTEGER, + DVP_BGRA_INTEGER, + DVP_RED_INTEGER, + DVP_GREEN_INTEGER, + DVP_BLUE_INTEGER, + DVP_ALPHA_INTEGER, + DVP_RGB_INTEGER, + DVP_BGR_INTEGER, + DVP_LUMINANCE_INTEGER, + DVP_LUMINANCE_ALPHA_INTEGER, +} DVPBufferFormats; + +// Possible pixel component storage types for system memory buffers +typedef enum { + DVP_UNSIGNED_BYTE, + DVP_BYTE, + DVP_UNSIGNED_SHORT, + DVP_SHORT, + DVP_UNSIGNED_INT, + DVP_INT, + DVP_FLOAT, + DVP_HALF_FLOAT, + DVP_UNSIGNED_BYTE_3_3_2, + DVP_UNSIGNED_BYTE_2_3_3_REV, + DVP_UNSIGNED_SHORT_5_6_5, + DVP_UNSIGNED_SHORT_5_6_5_REV, + DVP_UNSIGNED_SHORT_4_4_4_4, + DVP_UNSIGNED_SHORT_4_4_4_4_REV, + DVP_UNSIGNED_SHORT_5_5_5_1, + DVP_UNSIGNED_SHORT_1_5_5_5_REV, + DVP_UNSIGNED_INT_8_8_8_8, + DVP_UNSIGNED_INT_8_8_8_8_REV, + DVP_UNSIGNED_INT_10_10_10_2, + DVP_UNSIGNED_INT_2_10_10_10_REV, +} DVPBufferTypes; + +// System memory descriptor describing the size and storage formats +// of the buffer +typedef struct DVPSysmemBufferDescRec { + uint32_t width; // Buffer Width + uint32_t height; // Buffer Height + uint32_t stride; // Stride + uint32_t size; // Specifies the surface size if + // format == DVP_BUFFER + DVPBufferFormats format; // see enum above + DVPBufferTypes type; // see enum above + void *bufAddr; // Buffer memory address +} DVPSysmemBufferDesc; + +// Flags specified at sync object creation: +// ---------------------------------------- +// Tells the implementation to use events wherever +// possible instead of software spin loops. Note if HW +// wait operations are supported by the implementation +// then events will not be used in the dvpMemcpy* +// functions. In such a case, events may still be used +// in dvpSyncObjClientWait* functions. +#define DVP_SYNC_OBJECT_FLAGS_USE_EVENTS 0x00000001 + +typedef struct DVPSyncObjectDescRec { + uint32_t *sem; // Location to write semaphore value + uint32_t flags; // See above DVP_SYNC_OBJECT_FLAGS_* bits + DVPStatus (*externalClientWaitFunc) (DVPSyncObjectHandle sync, + uint32_t value, + bool GEQ, // If true then the function should wait for the sync value to be + // greater than or equal to the value parameter. Otherwise just a + // straight forward equality comparison should be performed. + uint64_t timeout); + // If non-null, externalClientWaitFunc allows the DVP library + // to call the application to wait for a sync object to be + // released. This allows the application to create events, + // which can be triggered on device interrupts instead of + // using spin loops inside the DVP library. Upon succeeding + // the function must return DVP_STATUS_OK, non-zero for failure + // and DVP_STATUS_TIMEOUT on timeout. The externalClientWaitFunc should + // not alter the current GL or CUDA context state +} DVPSyncObjectDesc; + +// Time used when event timeouts should be ignored +#define DVP_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull + +typedef DVPStatus (DVPAPIENTRY * PFNDVPBEGIN) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPEND) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEBUFFER)(DVPSysmemBufferDesc *desc, DVPBufferHandle *hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPDESTROYBUFFER)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPFREEBUFFER)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPYLINED)(DVPBufferHandle srcBuffer, + DVPSyncObjectHandle srcSync, + uint32_t srcAcquireValue, + uint64_t timeout, + DVPBufferHandle dstBuffer, + DVPSyncObjectHandle dstSync, + uint32_t dstReleaseValue, + uint32_t startingLine, + uint32_t numberOfLines); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPY)(DVPBufferHandle srcBuffer, + DVPSyncObjectHandle srcSync, + uint32_t srcAcquireValue, + uint64_t timeout, + DVPBufferHandle dstBuffer, + DVPSyncObjectHandle dstSync, + uint32_t dstReleaseValue, + uint32_t srcOffset, + uint32_t dstOffset, + uint32_t count); +typedef DVPStatus (DVPAPIENTRY * PFNDVPIMPORTSYNCOBJECT)(DVPSyncObjectDesc *desc, + DVPSyncObjectHandle *syncObject); +typedef DVPStatus (DVPAPIENTRY * PFNDVPFREESYNCOBJECT)(DVPSyncObjectHandle syncObject); +typedef DVPStatus (DVPAPIENTRY * PFNDVPGETREQUIREDCONSTANTSGLCTX)(uint32_t *bufferAddrAlignment, + uint32_t *bufferGPUStrideAlignment, + uint32_t *semaphoreAddrAlignment, + uint32_t *semaphoreAllocSize, + uint32_t *semaphorePayloadOffset, + uint32_t *semaphorePayloadSize); +typedef DVPStatus (DVPAPIENTRY * PFNDVPBINDTOGLCTX)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPUNBINDFROMGLCTX)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDAPI)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITDVP)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDDVP)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITAPI)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEGPUTEXTUREGL)(GLuint texID, + DVPBufferHandle *bufferHandle); + +// Flags supplied to the dvpInit* functions: +// +// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is only supported for OpenGL +// contexts and is the only supported flag for CUDA. It allows for +// certain cases to be optimized by sharing the context +// of the application for the DVP operations. This removes the +// need to do certain synchronizations. See issue 5 for parallel +// issues. When used, the app's GL context must be current for all calls +// to the DVP library. +// the DVP library. +#define DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT 0x000000001 + +//------------------------------------------------------------------------ +// Function: dvpInitGLContext +// +// To be called before any DVP resources are allocated. +// This call allows for specification of flags that may +// change the way DVP operations are performed. See above +// for the list of flags. +// +// The OpenGL context must be current at time of call. +// +// Parameters: flags[IN] - Buffer description structure +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +extern DVPStatus dvpInitGLContext(uint32_t flags); + +//------------------------------------------------------------------------ +// Function: dvpCloseGLContext +// +// Function to be called when app closes to allow freeing +// of any DVP library allocated resources. +// +// The OpenGL context must be current at time of call. +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +extern DVPStatus dvpCloseGLContext(); + +//------------------------------------------------------------------------ +// Function: dvpGetLibrayVersion +// +// Description: Returns the current version of the library +// +// Parameters: major[OUT] - returned major version +// minor[OUT] - returned minor version +// +// Returns: DVP_STATUS_OK +//------------------------------------------------------------------------ +extern DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor); + +//------------------------------------------------------------------------ +// Function: dvpBegin +// +// Description: dvpBegin must be called before any combination of DVP +// function calls dvpMemCpy*, dvpMapBufferWaitDVP, +// dvpSyncObjClientWait*, and dvpMapBufferEndDVP. After +// the last of these functions has been called is dvpEnd +// must be called. This allows for more efficient batched +// DVP operations. +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpBegin DVPAPI_GET_FUN(__dvpBegin) + +//------------------------------------------------------------------------ +// Function: dvpEnd +// +// Description: dvpEnd signals the end of a batch of DVP function calls +// that began with dvpBegin +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpEnd DVPAPI_GET_FUN(__dvpEnd) + + +//------------------------------------------------------------------------ +// Function: dvpCreateBuffer +// +// Description: Create a DVP buffer using system memory, wrapping a user +// passed pointer. The pointer must be aligned +// to values returned by dvpGetRequiredAlignments* +// +// Parameters: desc[IN] - Buffer description structure +// hBuf[OUT] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpCreateBuffer DVPAPI_GET_FUN(__dvpCreateBuffer) + + +//------------------------------------------------------------------------ +// Function: dvpDestroyBuffer +// +// Description: Destroy a previously created DVP buffer. +// +// Parameters: hBuf[IN] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpDestroyBuffer DVPAPI_GET_FUN(__dvpDestroyBuffer) + +//------------------------------------------------------------------------ +// Function: dvpFreeBuffer +// +// Description: dvpFreeBuffer frees the DVP buffer reference +// +// Parameters: gpuBufferHandle[IN] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpFreeBuffer DVPAPI_GET_FUN(__dvpFreeBuffer) + +//------------------------------------------------------------------------ +// Function: dvpMemcpyLined +// +// Description: dvpMemcpyLined provides buffer copies between a +// DVP sysmem buffer and a graphics API texture (as opposed to +// a buffer type). Other buffer types (such +// as graphics API buffers) return DVP_STATUS_INVALID_PARAMETER. +// +// In addition, see "dvpMemcpy* general comments" above. +// +// Parameters: srcBuffer[IN] - src buffer handle +// srcSync[IN] - sync to acquire on before transfer +// srcAcquireValue[IN] - value to acquire on before transfer +// timeout[IN] - time out value in nanoseconds. +// dstBuffer[IN] - src buffer handle +// dstSync[IN] - sync to release on transfer completion +// dstReleaseValue[IN] - value to release on completion +// startingLine[IN] - starting line of buffer +// numberOfLines[IN] - number of lines to copy +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// +// GL state effected: The following GL state may be altered by this +// function (not relevant if no GL source or destination +// is used): +// -GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, +// GL_PACK_ROW_LENGTH +// -The buffer bound to GL_PIXEL_PACK_BUFFER +// -The current bound framebuffer (GL_FRAMEBUFFER_EXT) +// -GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, +// GL_UNPACK_ROW_LENGTH +// -The buffer bound to GL_PIXEL_UNPACK_BUFFER +// -The texture bound to GL_TEXTURE_2D +//------------------------------------------------------------------------ +#define dvpMemcpyLined DVPAPI_GET_FUN(__dvpMemcpyLined) + + +//------------------------------------------------------------------------ +// Function: dvpMemcpy +// +// Description: dvpMemcpy provides buffer copies between a +// DVP sysmem buffer and a graphics API pure buffer (as +// opposed to a texture type). Other buffer types (such +// as graphics API textures) return +// DVP_STATUS_INVALID_PARAMETER. +// +// The start address of the srcBuffer is given by srcOffset +// and the dstBuffer start address is given by dstOffset. +// +// In addition, see "dvpMemcpy* general comments" above. +// +// Parameters: srcBuffer[IN] - src buffer handle +// srcSync[IN] - sync to acquire on before transfer +// srcAcquireValue[IN] - value to acquire on before transfer +// timeout[IN] - time out value in nanoseconds. +// dstBuffer[IN] - src buffer handle +// dstSync[IN] - sync to release on completion +// dstReleaseValue[IN] - value to release on completion +// uint32_t srcOffset[IN] - byte offset of srcBuffer +// uint32_t dstOffset[IN] - byte offset of dstBuffer +// uint32_t count[IN] - number of bytes to copy +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// +// GL state effected: The following GL state may be altered by this +// function (not relevant if no GL source or destination +// is used): +// - The buffer bound to GL_COPY_WRITE_BUFFER +// - The buffer bound to GL_COPY_READ_BUFFER +// +//------------------------------------------------------------------------ +#define dvpMemcpy DVPAPI_GET_FUN(__dvpMemcpy) + +//------------------------------------------------------------------------ +// Function: dvpImportSyncObject +// +// Description: dvpImportSyncObject creates a DVPSyncObject from the +// DVPSyncObjectDesc. Note that a sync object is not +// supported for copy operations targeting different APIs. +// This means, for example, it is illegal to call dvpMemCpy* +// for source or target GL texture with sync object A and +// then later use that same sync object in dvpMemCpy* +// operation for a source or target CUDA buffer. The same +// semaphore memory can still be used for two different sync +// objects. +// +// Parameters: desc[IN] - data describing the sync object +// syncObject[OUT] - handle to sync object +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpImportSyncObject DVPAPI_GET_FUN(__dvpImportSyncObject) + +//------------------------------------------------------------------------ +// Function: dvpFreeSyncObject +// +// Description: dvpFreeSyncObject waits for any outstanding releases on +// this sync object before freeing the resources allocated for +// the specified sync object. The application must make sure +// any outstanding acquire operations have already been +// completed. +// +// If OpenGL is being used and the app's GL context is being +// shared (via the DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT flag), +// then dvpFreeSyncObject needs to be called while each context, +// on which the sync object was used, is current. If +// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is used and there are out +// standing contexts from which this sync object must be free'd +// then dvpFreeSyncObject will return DVP_STATUS_SYNC_STILL_BOUND. +// +// Parameters: syncObject[IN] - handle to sync object to be free'd +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_SYNC_STILL_BOUND +//------------------------------------------------------------------------ +#define dvpFreeSyncObject DVPAPI_GET_FUN(__dvpFreeSyncObject) + + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndAPI +// +// Description: Tells DVP to setup a signal for this buffer in the +// callers API context or device. The signal follows all +// previous API operations up to this point and, thus, +// allows subsequent DVP calls to know when then this buffer +// is ready for use within the DVP library. This function +// would be followed by a call to dvpMapBufferWaitDVP to +// synchronize rendering in the API stream and the DVP +// stream. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// The use of dvpMapBufferEndAPI is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_UNSIGNALED - returned if the API is +// unable to place a signal in the API context queue +//------------------------------------------------------------------------ +#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndAPI +// +// Description: Tells DVP to setup a signal for this buffer in the +// callers API context or device. The signal follows all +// previous API operations up to this point and, thus, +// allows subsequent DVP calls to know when then this buffer +// is ready for use within the DVP library. This function +// would be followed by a call to dvpMapBufferWaitDVP to +// synchronize rendering in the API stream and the DVP +// stream. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// The use of dvpMapBufferEndAPI is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_UNSIGNALED - returned if the API is +// unable to place a signal in the API context queue +//------------------------------------------------------------------------ +#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferWaitDVP +// +// Description: Tells DVP to make the DVP stream wait for a previous +// signal triggered by a dvpMapBufferEndAPI call. +// +// This must be called inside the dvpBegin/dvpEnd pair. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferWaitDVP DVPAPI_GET_FUN(__dvpMapBufferWaitDVP) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndDVP +// +// Description: Tells DVP to setup a signal for this buffer after +// DVP operations are complete. The signal allows +// the API to know when then this buffer is +// ready for use within a API stream. This function would +// be followed by a call to dvpMapBufferWaitAPI to +// synchronize copies in the DVP stream and the API +// rendering stream. +// +// This must be called inside the dvpBegin/dvpEnd pair. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferEndDVP DVPAPI_GET_FUN(__dvpMapBufferEndDVP) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferWaitAPI +// +// Description: Tells DVP to make the current API context or device to +// wait for a previous signal triggered by a +// dvpMapBufferEndDVP call. +// +// The use of dvpMapBufferWaitCUDAStream is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferWaitAPI DVPAPI_GET_FUN(__dvpMapBufferWaitAPI) + +//------------------------------------------------------------------------ +// If the multiple GL contexts used in the application access the same +// sysmem buffers, then application must create those GL contexts with +// display list shared. +//------------------------------------------------------------------------ +#define dvpBindToGLCtx DVPAPI_GET_FUN(__dvpBindToGLCtx) +#define dvpGetRequiredConstantsGLCtx DVPAPI_GET_FUN(__dvpGetRequiredConstantsGLCtx) +#define dvpCreateGPUTextureGL DVPAPI_GET_FUN(__dvpCreateGPUTextureGL) +#define dvpUnbindFromGLCtx DVPAPI_GET_FUN(__dvpUnbindFromGLCtx) + + +DVPAPI PFNDVPBEGIN __dvpBegin; +DVPAPI PFNDVPEND __dvpEnd; +DVPAPI PFNDVPCREATEBUFFER __dvpCreateBuffer; +DVPAPI PFNDVPDESTROYBUFFER __dvpDestroyBuffer; +DVPAPI PFNDVPFREEBUFFER __dvpFreeBuffer; +DVPAPI PFNDVPMEMCPYLINED __dvpMemcpyLined; +DVPAPI PFNDVPMEMCPY __dvpMemcpy; +DVPAPI PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject; +DVPAPI PFNDVPFREESYNCOBJECT __dvpFreeSyncObject; +DVPAPI PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI; +DVPAPI PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP; +DVPAPI PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP; +DVPAPI PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI; + + +//------------------------------------------------------------------------ +// If the multiple GL contexts used in the application access the same +// sysmem buffers, then application must create those GL contexts with +// display list shared. +//------------------------------------------------------------------------ +DVPAPI PFNDVPBINDTOGLCTX __dvpBindToGLCtx; +DVPAPI PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx; +DVPAPI PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL; +DVPAPI PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx; + +#define DVPAPI_GET_FUN(x) x + +#endif // WIN32 + +#endif // __DVPAPI_H__ + diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c index 841b47bd4f1..79d55dd02cc 100644 --- a/intern/guardedalloc/test/simpletest/memtest.c +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -26,7 +26,6 @@ */ /** - * Copyright (C) 2001 NaN Technologies B.V. * Simple test of memory. */ diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc index f0cbc68f11e..3b7c9c5a010 100644 --- a/intern/libmv/intern/autotrack.cc +++ b/intern/libmv/intern/autotrack.cc @@ -67,12 +67,12 @@ int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker); libmv_configureTrackRegionOptions(*libmv_options, &options); - (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, - &result, - &options)); + bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, + &result, + &options)); libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker); libmv_regionTrackergetResult(result, libmv_result); - return result.is_usable(); + return ok && result.is_usable(); } void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h index 3220bc2dbbc..8f304f31ec6 100644 --- a/intern/libmv/libmv/multiview/projection.h +++ b/intern/libmv/libmv/multiview/projection.h @@ -122,7 +122,7 @@ inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { Vec3 hx; - Project(P, X, x); + Project(P, X, &hx); *x = hx.head<2>() / hx(2); } diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc index 9007663c8e2..3fc1e3b2bfd 100644 --- a/intern/libmv/libmv/numeric/numeric.cc +++ b/intern/libmv/libmv/numeric/numeric.cc @@ -109,7 +109,7 @@ void MeanAndVarianceAlongRows(const Mat &A, } void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) { - assert(left.rows() == left.rows()); + assert(left.rows() == right.rows()); int n = left.rows(); int m1 = left.cols(); int m2 = right.cols(); diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index 20a4a29e5ba..a42dab8c7a2 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -148,7 +148,7 @@ using Eigen::Matrix; // A = U * diag(s) * VT // template <typename TMat, typename TVec> -inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) { +inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { assert(0); } diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h index 045cc3b8361..2ecac81ea6f 100644 --- a/intern/moto/include/MT_Matrix4x4.h +++ b/intern/moto/include/MT_Matrix4x4.h @@ -144,6 +144,16 @@ public: } /** + * Scale the rows of this matrix with x, y, z, w respectively. + */ + void tscale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) { + m_el[0][0] *= x; m_el[1][0] *= y; m_el[2][0] *= z; m_el[3][0] *= w; + m_el[0][1] *= x; m_el[1][1] *= y; m_el[2][1] *= z; m_el[3][1] *= w; + m_el[0][2] *= x; m_el[1][2] *= y; m_el[2][2] *= z; m_el[3][2] *= w; + m_el[0][3] *= x; m_el[1][3] *= y; m_el[2][3] *= z; m_el[3][3] *= w; + } + + /** * Return a column-scaled version of this matrix. */ MT_Matrix4x4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const { diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl index 5921d6d9c73..853bf575582 100644 --- a/intern/opencolorio/gpu_shader_display_transform.glsl +++ b/intern/opencolorio/gpu_shader_display_transform.glsl @@ -38,7 +38,7 @@ float read_curve_mapping(int table, int index) * But is it actually correct to subtract 1 here? */ float texture_index = float(index) / float(curve_mapping_lut_size - 1); - return texture1D(curve_mapping_texture, texture_index) [table]; + return texture1D(curve_mapping_texture, texture_index)[table]; } float curvemap_calc_extend(int table, float x, vec2 first, vec2 last) diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 311b89b97cf..f8e80de7f8f 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -47,6 +47,7 @@ set(SRC opensubdiv_device_context_cuda.h opensubdiv_device_context_opencl.h opensubdiv_intern.h + opensubdiv_topology_refiner.h ) macro(OPENSUBDIV_DEFINE_COMPONENT component) @@ -69,6 +70,7 @@ add_definitions(-DGLEW_STATIC) if(WIN32) add_definitions(-DNOMINMAX) + add_definitions(-D_USE_MATH_DEFINES) endif() # TODO(sergey): Put CUEW back when CUDA is officially supported by OSD. diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl index 51e8ed46c34..5193d3a71dc 100644 --- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl +++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl @@ -99,6 +99,7 @@ in block { } uniform samplerBuffer FVarDataBuffer; +uniform isamplerBuffer FVarDataOffsetBuffer; out block { VertexData v; @@ -111,7 +112,7 @@ void emit(int index, vec3 normal) outpt.v.normal = normal; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); @@ -135,7 +136,7 @@ void emit(int index) outpt.v.normal = inpt[index].v.normal; /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); vec2 st = quadst[index]; INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); @@ -208,6 +209,7 @@ struct LightSource { float spotCutoff; float spotExponent; float spotCosCutoff; + float pad, pad2; #endif }; @@ -240,6 +242,7 @@ void main() vec3 L_diffuse = vec3(0.0); vec3 L_specular = vec3(0.0); +#ifdef USE_LIGHTING #ifndef USE_COLOR_MATERIAL /* Assume NUM_SOLID_LIGHTS directional lights. */ for (int i = 0; i < NUM_SOLID_LIGHTS; i++) { @@ -261,7 +264,7 @@ void main() #else /* USE_COLOR_MATERIAL */ vec3 varying_position = inpt.v.position.xyz; vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? - normalize(varying_position): vec3(0.0, 0.0, -1.0); + normalize(varying_position) : vec3(0.0, 0.0, -1.0); for (int i = 0; i < num_enabled_lights; i++) { /* todo: this is a slow check for disabled lights */ if (lightSource[i].specular.a == 0.0) @@ -299,7 +302,7 @@ void main() /* diffuse light */ vec3 light_diffuse = lightSource[i].diffuse.rgb; float diffuse_bsdf = max(dot(N, light_direction), 0.0); - L_diffuse += light_diffuse*diffuse_bsdf*intensity; + L_diffuse += light_diffuse * diffuse_bsdf * intensity; /* specular light */ vec3 light_specular = lightSource[i].specular.rgb; @@ -307,9 +310,12 @@ void main() float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess); - L_specular += light_specular*specular_bsdf * intensity; + L_specular += light_specular * specular_bsdf * intensity; } #endif /* USE_COLOR_MATERIAL */ +#else /* USE_LIGHTING */ + L_diffuse = vec3(1.0); +#endif /* Compute diffuse color. */ #ifdef USE_TEXTURE_2D diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index 9b9f4baa39e..ab904953c70 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -67,8 +67,10 @@ #include <opensubdiv/osd/glPatchTable.h> #include <opensubdiv/far/stencilTable.h> +#include <opensubdiv/far/primvarRefiner.h> #include "opensubdiv_intern.h" +#include "opensubdiv_topology_refiner.h" #include "MEM_guardedalloc.h" @@ -142,11 +144,73 @@ typedef Mesh<GLVertexBuffer, GLPatchTable> OsdGLSLComputeMesh; #endif +namespace { + +struct FVarVertex { + float u, v; + void Clear() { + u = v = 0.0f; + } + void AddWithWeight(FVarVertex const & src, float weight) { + u += weight * src.u; + v += weight * src.v; + } +}; + +static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner, + const std::vector<float> uvs, + std::vector<float> &fvar_data) { + /* TODO(sergey): Make it somehow more generic way. */ + const int fvar_width = 2; + const int max_level = refiner.GetMaxLevel(); + size_t fvar_data_offset = 0, values_offset = 0; + for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { + const int num_values = refiner.GetLevel(0).GetNumFVarValues(0) * 2, + num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel), + num_values_total = refiner.GetNumFVarValuesTotal(channel); + if (num_values_total <= 0) { + continue; + } + OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); + if (refiner.IsUniform()) { + /* For uniform we only keep the highest level of refinement. */ + fvar_data.resize(fvar_data.size() + num_values_max * fvar_width); + std::vector<FVarVertex> buffer(num_values_total - num_values_max); + FVarVertex *src = &buffer[0]; + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + /* Defer the last level to treat separately with its alternate + * destination. + */ + for (int level = 1; level < max_level; ++level) { + FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); + primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + /* For adaptive we keep all levels. */ + fvar_data.resize(fvar_data.size() + num_values_total * fvar_width); + FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]); + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + for (int level = 1; level <= max_level; ++level) { + FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + fvar_data_offset += num_values_total * fvar_width; + } + values_offset += num_values; + } +} + +} // namespace + struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( OpenSubdiv_TopologyRefinerDescr *topology_refiner, int evaluator_type, - int level, - int /*subdivide_uvs*/) + int level) { using OpenSubdiv::Far::TopologyRefiner; @@ -164,7 +228,7 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( const int num_varying_elements = 3; GLMeshInterface *mesh = NULL; - TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner; + TopologyRefiner *refiner = topology_refiner->osd_refiner; switch(evaluator_type) { #define CHECK_EVALUATOR_TYPE(type, class) \ @@ -210,13 +274,23 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh); gl_mesh->evaluator_type = evaluator_type; gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh; - gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner; + gl_mesh->topology_refiner = topology_refiner; + + if (refiner->GetNumFVarChannels() > 0) { + std::vector<float> fvar_data; + interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data); + openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]); + } + else { + gl_mesh->fvar_data = NULL; + } return gl_mesh; } void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh) { + openSubdiv_osdGLDestroyFVar(gl_mesh); switch (gl_mesh->evaluator_type) { #define CHECK_EVALUATOR_TYPE(type, class) \ case OPENSUBDIV_EVALUATOR_ ## type: \ @@ -249,6 +323,8 @@ void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh) #undef CHECK_EVALUATOR_TYPE } + /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */ + OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr); OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh); } @@ -299,6 +375,9 @@ int openSubdiv_supportGPUDisplay(void) return openSubdiv_gpu_legacy_support() && (GLEW_VERSION_3_2 || (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) || - (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); + (GLEW_VERSION_3_0 && + GLEW_EXT_geometry_shader4 && + GLEW_ARB_uniform_buffer_object && + (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); /* also ARB_explicit_attrib_location? */ } diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index b40505b197d..c3a194813e6 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -32,16 +32,19 @@ extern "C" { // Types declaration. struct OpenSubdiv_GLMesh; +struct OpenSubdiv_GLMeshFVarData; struct OpenSubdiv_TopologyRefinerDescr; typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh; #ifdef __cplusplus struct OpenSubdiv_GLMeshDescr; + typedef struct OpenSubdiv_GLMesh { int evaluator_type; OpenSubdiv_GLMeshDescr *descriptor; OpenSubdiv_TopologyRefinerDescr *topology_refiner; + OpenSubdiv_GLMeshFVarData *fvar_data; } OpenSubdiv_GLMesh; #endif @@ -66,8 +69,7 @@ enum { OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, int evaluator_type, - int level, - int subdivide_uvs); + int level); void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh); unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer( @@ -138,6 +140,11 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, int start_patch, int num_patches); +void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, + const float *fvar_data); +void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh); + /* ** Utility functions ** */ int openSubdiv_supportGPUDisplay(void); int openSubdiv_getAvailableEvaluators(void); diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index 3fadde68d32..ea41a56768f 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -32,8 +32,12 @@ #include <opensubdiv/far/topologyRefinerFactory.h> +#include "MEM_guardedalloc.h" + #include "opensubdiv_converter_capi.h" #include "opensubdiv_intern.h" +#include "opensubdiv_topology_refiner.h" + #include <stack> @@ -49,6 +53,11 @@ inline void reverse_face_verts(int *face_verts, int num_verts) face_verts[0] = last_vert; } +struct TopologyRefinerData { + const OpenSubdiv_Converter& conv; + std::vector<float> *uvs; +}; + } /* namespace */ #endif /* OPENSUBDIV_ORIENT_TOPOLOGY */ @@ -137,10 +146,11 @@ inline void check_oriented_vert_connectivity(const int num_vert_edges, } /* namespace */ template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology( +inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; /* Faces and face-verts */ const int num_faces = conv.get_num_faces(&conv); setNumBaseFaces(refiner, num_faces); @@ -168,10 +178,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopolog } template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopology( +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData &cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; using Far::IndexArray; /* Face relations. */ const int num_faces = conv.get_num_faces(&conv); @@ -332,7 +343,6 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog else { /* Special handle of non-manifold vertex. */ for (int i = 0; i < num_vert_edges; ++i) { - bool start_found = false; edge_start = vert_edges[i]; IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); if (edge_faces.size() == 1) { @@ -343,14 +353,10 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog face_edges = getBaseFaceEdges(refiner, face_start); face_vert_start = findInArray(face_verts, vert); if (edge_start == face_edges[face_vert_start]) { - start_found = true; break; } } } - if (start_found) { - break; - } /* Reset indices for sanity check below. */ face_start = edge_start = face_vert_start = -1; } @@ -431,10 +437,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog }; template <> -inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags( +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( TopologyRefiner& refiner, - const OpenSubdiv_Converter& conv) + const TopologyRefinerData& cb_data) { + const OpenSubdiv_Converter& conv = cb_data.conv; typedef OpenSubdiv::Sdc::Crease Crease; int num_edges = conv.get_num_edges(&conv); @@ -481,14 +488,52 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags( } template <> -inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology( +inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology( TopologyError /*errCode*/, const char *msg, - const OpenSubdiv_Converter& /*mesh*/) + const TopologyRefinerData& /*mesh*/) { printf("OpenSubdiv Error: %s\n", msg); } +template <> +inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology( + TopologyRefiner& refiner, + const TopologyRefinerData& cb_data) +{ + const OpenSubdiv_Converter& conv = cb_data.conv; + const int num_layers = conv.get_num_uv_layers(&conv); + if (num_layers <= 0) { + /* No UV maps, we can skip any face-varying data. */ + return true; + } + const int num_faces = getNumBaseFaces(refiner); + size_t uvs_offset = 0; + for (int layer = 0; layer < num_layers; ++layer) { + conv.precalc_uv_layer(&conv, layer); + const int num_uvs = conv.get_num_uvs(&conv); + /* Fill in UV coordinates. */ + cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2); + conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset)); + uvs_offset += num_uvs * 2; + /* Fill in per-corner index of the UV. */ + const int channel = createBaseFVarChannel(refiner, num_uvs); + for (int face = 0; face < num_faces; ++face) { + Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, + face, + channel); + for (int corner = 0; corner < dst_face_uvs.size(); ++corner) { + const int uv_index = conv.get_face_corner_uv_index(&conv, + face, + corner); + dst_face_uvs[corner] = uv_index; + } + } + conv.finish_uv_layer(&conv); + } + return true; +} + } /* namespace Far */ } /* namespace OPENSUBDIV_VERSION */ } /* namespace OpenSubdiv */ @@ -522,33 +567,43 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr( Options options; options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); options.SetCreasingMethod(Options::CREASE_UNIFORM); - options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); + if (converter->get_subdiv_uvs(converter)) { + options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_ONLY); + } + else { + options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); + } - TopologyRefinerFactory<OpenSubdiv_Converter>::Options + TopologyRefinerFactory<TopologyRefinerData>::Options topology_options(scheme_type, options); #ifdef OPENSUBDIV_VALIDATE_TOPOLOGY topology_options.validateFullTopology = true; #endif + OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr); + TopologyRefinerData cb_data = {*converter, &result->uvs}; /* We don't use guarded allocation here so we can re-use the refiner * for GL mesh creation directly. */ - return (struct OpenSubdiv_TopologyRefinerDescr*) - TopologyRefinerFactory<OpenSubdiv_Converter>::Create( - *converter, + result->osd_refiner = + TopologyRefinerFactory<TopologyRefinerData>::Create( + cb_data, topology_options); + + return result; } void openSubdiv_deleteTopologyRefinerDescr( OpenSubdiv_TopologyRefinerDescr *topology_refiner) { - delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner; + delete topology_refiner->osd_refiner; + OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr); } int openSubdiv_topologyRefinerGetSubdivLevel( const OpenSubdiv_TopologyRefinerDescr *topology_refiner) { using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; return refiner->GetMaxLevel(); } @@ -557,7 +612,7 @@ int openSubdiv_topologyRefinerGetNumVerts( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumVertices(); } @@ -567,7 +622,7 @@ int openSubdiv_topologyRefinerGetNumEdges( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumEdges(); } @@ -577,7 +632,7 @@ int openSubdiv_topologyRefinerGetNumFaces( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetNumFaces(); } @@ -588,7 +643,7 @@ int openSubdiv_topologyRefinerGetNumFaceVerts( { using OpenSubdiv::Far::TopologyLevel; using OpenSubdiv::Far::TopologyRefiner; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); return base_level.GetFaceVertices(face).size(); } @@ -597,10 +652,11 @@ int openSubdiv_topologyRefnerCompareConverter( const OpenSubdiv_TopologyRefinerDescr *topology_refiner, OpenSubdiv_Converter *converter) { + typedef OpenSubdiv::Sdc::Options Options; using OpenSubdiv::Far::ConstIndexArray; using OpenSubdiv::Far::TopologyRefiner; using OpenSubdiv::Far::TopologyLevel; - const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner; + const TopologyRefiner *refiner = topology_refiner->osd_refiner; const TopologyLevel &base_level = refiner->GetLevel(0); const int num_verts = base_level.GetNumVertices(); const int num_edges = base_level.GetNumEdges(); @@ -611,6 +667,12 @@ int openSubdiv_topologyRefnerCompareConverter( if (scheme_type != refiner->GetSchemeType()) { return false; } + const Options options = refiner->GetSchemeOptions(); + Options::FVarLinearInterpolation interp = options.GetFVarLinearInterpolation(); + const bool subdiv_uvs = (interp != Options::FVAR_LINEAR_ALL); + if (converter->get_subdiv_uvs(converter) != subdiv_uvs) { + return false; + } if (converter->get_num_verts(converter) != num_verts || converter->get_num_edges(converter) != num_edges || converter->get_num_faces(converter) != num_faces) diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index 1f09fa074d8..6eda6ae5d8a 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -47,6 +47,8 @@ typedef struct OpenSubdiv_Converter { OpenSubdiv_SchemeType (*get_type)(const OpenSubdiv_Converter *converter); + bool (*get_subdiv_uvs)(const OpenSubdiv_Converter *converter); + int (*get_num_faces)(const OpenSubdiv_Converter *converter); int (*get_num_edges)(const OpenSubdiv_Converter *converter); int (*get_num_verts)(const OpenSubdiv_Converter *converter); @@ -83,6 +85,20 @@ typedef struct OpenSubdiv_Converter { int vert, int *vert_faces); + /* Face-varying data. */ + + int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter); + + void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer); + void (*finish_uv_layer)(const OpenSubdiv_Converter *converter); + + int (*get_num_uvs)(const OpenSubdiv_Converter *converter); + void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs); + + int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter, + int face, + int corner); + void (*free_user_data)(const OpenSubdiv_Converter *converter); void *user_data; } OpenSubdiv_Converter; diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 698fdfee00f..0cf6fcfef43 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -42,11 +42,29 @@ #include <opensubdiv/osd/cpuGLVertexBuffer.h> #include <opensubdiv/osd/cpuEvaluator.h> +#include "MEM_guardedalloc.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_topology_refiner.h" + using OpenSubdiv::Osd::GLMeshInterface; extern "C" char datatoc_gpu_shader_opensubd_display_glsl[]; +/* TODO(sergey): This is bit of bad level calls :S */ +extern "C" { +void copy_m3_m3(float m1[3][3], float m2[3][3]); +void copy_m3_m4(float m1[3][3], float m2[4][4]); +void adjoint_m3_m3(float m1[3][3], float m[3][3]); +float determinant_m3_array(float m[3][3]); +bool invert_m3_m3(float m1[3][3], float m2[3][3]); +bool invert_m3(float m[3][3]); +void transpose_m3(float mat[3][3]); +} + #define MAX_LIGHTS 8 +#define SUPPORT_COLOR_MATERIAL + typedef struct Light { float position[4]; float ambient[4]; @@ -60,6 +78,7 @@ typedef struct Light { float spot_cutoff; float spot_exponent; float spot_cos_cutoff; + float pad, pad2; #endif } Light; @@ -75,114 +94,116 @@ typedef struct Transform { } Transform; static bool g_use_osd_glsl = false; -static int g_active_uv_index = -1; +static int g_active_uv_index = 0; static GLuint g_flat_fill_solid_program = 0; static GLuint g_flat_fill_texture2d_program = 0; static GLuint g_smooth_fill_solid_program = 0; static GLuint g_smooth_fill_texture2d_program = 0; + +static GLuint g_flat_fill_solid_shadeless_program = 0; +static GLuint g_flat_fill_texture2d_shadeless_program = 0; +static GLuint g_smooth_fill_solid_shadeless_program = 0; +static GLuint g_smooth_fill_texture2d_shadeless_program = 0; + static GLuint g_wireframe_program = 0; static GLuint g_lighting_ub = 0; static Lighting g_lighting_data; static Transform g_transform; -/* TODO(sergey): This is actually duplicated code from BLI. */ -namespace { -void copy_m3_m3(float m1[3][3], float m2[3][3]) -{ - /* destination comes first: */ - memcpy(&m1[0], &m2[0], 9 * sizeof(float)); -} - -void copy_m3_m4(float m1[3][3], float m2[4][4]) -{ - m1[0][0] = m2[0][0]; - m1[0][1] = m2[0][1]; - m1[0][2] = m2[0][2]; - - m1[1][0] = m2[1][0]; - m1[1][1] = m2[1][1]; - m1[1][2] = m2[1][2]; - - m1[2][0] = m2[2][0]; - m1[2][1] = m2[2][1]; - m1[2][2] = m2[2][2]; -} - -void adjoint_m3_m3(float m1[3][3], float m[3][3]) -{ - m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; - m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1]; - m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - - m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0]; - m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0]; - m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0]; - - m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0]; - m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0]; - m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; -} - -float determinant_m3_array(float m[3][3]) +struct OpenSubdiv_GLMeshFVarData { - return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - - m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + - m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); -} - -bool invert_m3_m3(float m1[3][3], float m2[3][3]) -{ - float det; - int a, b; - bool success; - - /* calc adjoint */ - adjoint_m3_m3(m1, m2); + OpenSubdiv_GLMeshFVarData() : + texture_buffer(0) { + } - /* then determinant old matrix! */ - det = determinant_m3_array(m2); + ~OpenSubdiv_GLMeshFVarData() + { + Release(); + } - success = (det != 0.0f); + void Release() + { + if (texture_buffer) { + glDeleteTextures(1, &texture_buffer); + } + if (offset_buffer) { + glDeleteTextures(1, &offset_buffer); + } + texture_buffer = 0; + offset_buffer = 0; + fvar_width = 0; + channel_offsets.clear(); + } - if (det != 0.0f) { - det = 1.0f / det; - for (a = 0; a < 3; a++) { - for (b = 0; b < 3; b++) { - m1[a][b] *= det; + void Create(const OpenSubdiv::Far::TopologyRefiner *refiner, + const OpenSubdiv::Far::PatchTable *patch_table, + int fvar_width, + const float *fvar_src_data) + { + Release(); + + this->fvar_width = fvar_width; + + /* Expand fvar data to per-patch array */ + const int max_level = refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); + std::vector<float> data; + int fvar_data_offset = 0; + channel_offsets.resize(num_channels); + for (int channel = 0; channel < num_channels; ++channel) { + OpenSubdiv::Far::ConstIndexArray indices = + patch_table->GetFVarValues(channel); + + channel_offsets[channel] = data.size(); + data.reserve(data.size() + indices.size() * fvar_width); + + for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { + int index = indices[fvert] * fvar_width; + for (int i = 0; i < fvar_width; ++i) { + data.push_back(fvar_src_data[fvar_data_offset + index++]); + } + } + if (refiner->IsUniform()) { + const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + const int num_values_total = refiner->GetNumFVarValuesTotal(channel); + fvar_data_offset += num_values_total * fvar_width; } } - } - return success; -} + GLuint buffer; + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float), + &data[0], GL_STATIC_DRAW); -bool invert_m3(float m[3][3]) -{ - float tmp[3][3]; - bool success; + glGenTextures(1, &texture_buffer); + glBindTexture(GL_TEXTURE_BUFFER, texture_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); - success = invert_m3_m3(tmp, m); - copy_m3_m3(m, tmp); + glDeleteBuffers(1, &buffer); - return success; -} + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int), + &channel_offsets[0], GL_STATIC_DRAW); -void transpose_m3(float mat[3][3]) -{ - float t; - - t = mat[0][1]; - mat[0][1] = mat[1][0]; - mat[1][0] = t; - t = mat[0][2]; - mat[0][2] = mat[2][0]; - mat[2][0] = t; - t = mat[1][2]; - mat[1][2] = mat[2][1]; - mat[2][1] = t; -} + glGenTextures(1, &offset_buffer); + glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + GLuint texture_buffer; + GLuint offset_buffer; + std::vector<int> channel_offsets; + int fvar_width; +}; + +namespace { GLuint compileShader(GLenum shaderType, const char *section, @@ -196,11 +217,14 @@ GLuint compileShader(GLenum shaderType, version, define, sdefine, +#ifdef SUPPORT_COLOR_MATERIAL + "#define SUPPORT_COLOR_MATERIAL\n", +#endif datatoc_gpu_shader_opensubd_display_glsl }; GLuint shader = glCreateShader(shaderType); - glShaderSource(shader, 4, sources, NULL); + glShaderSource(shader, 5, sources, NULL); glCompileShader(shader); GLint status; @@ -295,14 +319,17 @@ GLuint linkProgram(const char *version, const char *define) 0); /* GL_TEXTURE0 */ glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ return program; } -void bindProgram(GLMeshInterface * /*mesh*/, - int program) +void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) { glUseProgram(program); @@ -346,23 +373,34 @@ void bindProgram(GLMeshInterface * /*mesh*/, glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); } - /* TODO(sergey): Bring face varying back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); - } -#endif + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } - /* TODO(sergey): Bring face varying back. */ - glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), - 0/* * mesh->GetFVarCount()*/); + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), - g_active_uv_index * 2); + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), + gl_mesh->fvar_data->fvar_width); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } } } /* namespace */ @@ -390,11 +428,51 @@ bool openSubdiv_osdGLDisplayInit(void) /* minimum supported for OpenSubdiv */ } - g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n"); - g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n"); - g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n"); - g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); + g_flat_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_flat_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_wireframe_program = linkProgram( + version, + "#define WIREFRAME\n"); glGenBuffers(1, &g_lighting_ub); glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); @@ -416,28 +494,31 @@ void openSubdiv_osdGLDisplayDeinit(void) if (g_lighting_ub != 0) { glDeleteBuffers(1, &g_lighting_ub); } - if (g_flat_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_flat_fill_texture2d_program) { - glDeleteProgram(g_flat_fill_texture2d_program); - } - if (g_smooth_fill_solid_program) { - glDeleteProgram(g_flat_fill_solid_program); - } - if (g_smooth_fill_texture2d_program) { - glDeleteProgram(g_smooth_fill_texture2d_program); - } - if (g_wireframe_program) { - glDeleteProgram(g_wireframe_program); - } +#define SAFE_DELETE_PROGRAM(program) \ + do { \ + if (program) { \ + glDeleteProgram(program); \ + } \ + } while (false) + + SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_wireframe_program); + +#undef SAFE_DELETE_PROGRAM } void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, int active_uv_index) { - g_use_osd_glsl = use_osd_glsl != 0; g_active_uv_index = active_uv_index; + g_use_osd_glsl = (use_osd_glsl != 0); /* Update transformation matrices. */ glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); @@ -494,7 +575,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, } } -static GLuint prepare_patchDraw(GLMeshInterface *mesh, +static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, bool fill_quads) { GLint program = 0; @@ -509,51 +590,74 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, glUniform1i(location, model == GL_FLAT); } - /* TODO(sergey): Bring this back. */ -#if 0 /* Face-vertex data */ - if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) { - glActiveTexture(GL_TEXTURE31); - glBindTexture(GL_TEXTURE_BUFFER, - mesh->GetDrawContext()->GetFvarDataTextureBuffer()); - glActiveTexture(GL_TEXTURE0); + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } GLint location = glGetUniformLocation(program, "osd_fvar_count"); if (location != -1) { - glUniform1i(location, mesh->GetFVarCount()); + glUniform1i(location, gl_mesh->fvar_data->fvar_width); } location = glGetUniformLocation(program, "osd_active_uv_offset"); if (location != -1) { - glUniform1i(location, - g_active_uv_index * 2); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && + g_active_uv_index >= 0) + { + glUniform1i(location, + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(location, 0); + } } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); } -#endif - } return program; } if (fill_quads) { int model; - GLboolean use_texture_2d; + GLboolean use_texture_2d, use_lighting; glGetIntegerv(GL_SHADE_MODEL, &model); glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); + glGetBooleanv(GL_LIGHTING, &use_lighting); if (model == GL_FLAT) { if (use_texture_2d) { - program = g_flat_fill_texture2d_program; + program = use_lighting + ? g_flat_fill_texture2d_program + : g_flat_fill_texture2d_shadeless_program; } else { - program = g_flat_fill_solid_program; + program = use_lighting + ? g_flat_fill_solid_program + : g_flat_fill_solid_shadeless_program; } } else { if (use_texture_2d) { - program = g_smooth_fill_texture2d_program; + program = use_lighting + ? g_smooth_fill_texture2d_program + : g_smooth_fill_texture2d_shadeless_program; } else { - program = g_smooth_fill_solid_program; + program = use_lighting + ? g_smooth_fill_solid_program + : g_smooth_fill_solid_shadeless_program; } } } @@ -562,7 +666,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh, program = g_wireframe_program; } - bindProgram(mesh, program); + bindProgram(gl_mesh, program); return program; } @@ -623,7 +727,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh, const int num_draw_patches = std::min(num_remained_patches, num_block_patches - start_draw_patch); perform_drawElements(program, - i, + i + start_draw_patch, num_draw_patches * num_control_verts, patch.GetIndexBase() + start_draw_patch * num_control_verts); num_remained_patches -= num_draw_patches; @@ -669,7 +773,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, } /* Setup GLSL/OpenGL to draw patches in current context. */ - GLuint program = prepare_patchDraw(mesh, fill_quads != 0); + GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); if (start_patch != -1) { draw_partition_patches_range(mesh, @@ -684,3 +788,23 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, /* Finish patch drawing by restoring all changes to the OpenGL context. */ finish_patchDraw(fill_quads != 0); } + +void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, + const float *fvar_data) +{ + GLMeshInterface *mesh = + (GLMeshInterface *)(gl_mesh->descriptor); + gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData); + gl_mesh->fvar_data->Create(topology_refiner->osd_refiner, + mesh->GetFarPatchTable(), + 2, + fvar_data); +} + +void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh) +{ + if (gl_mesh->fvar_data != NULL) { + OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData); + } +} diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h new file mode 100644 index 00000000000..b00f6a54201 --- /dev/null +++ b/intern/opensubdiv/opensubdiv_topology_refiner.h @@ -0,0 +1,41 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENSUBDIV_TOPOLOGY_REFINER_H__ +#define __OPENSUBDIV_TOPOLOGY_REFINER_H__ + +#include <opensubdiv/far/topologyRefiner.h> + +typedef struct OpenSubdiv_TopologyRefinerDescr { + OpenSubdiv::Far::TopologyRefiner *osd_refiner; + + /* TODO(sergey): For now only, need to find better place + * after revisiting whole OSD drawing pipeline and Blender + * integration. + */ + std::vector<float> uvs; +} OpenSubdiv_TopologyRefinerDescr; + +#endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */ |