diff options
Diffstat (limited to 'intern')
56 files changed, 1192 insertions, 608 deletions
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/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 140862721a8..0b3dd552f62 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -503,6 +503,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", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 120199479fe..6656beb4478 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -401,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): @@ -458,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") diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 4bd385c4200..ec11a893b5a 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -680,6 +680,43 @@ static void create_subd_mesh(Scene *scene, /* 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) @@ -821,6 +858,9 @@ 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; @@ -910,6 +950,11 @@ 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); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 80768c096e3..22a0b3988c8 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -253,11 +253,10 @@ 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); + p = transform_perspective(&worldtondc, p); if(p.z >= -margin) { all_behind = false; } - p /= p.z; bb_min = min(bb_min, p); bb_max = max(bb_max, p); } @@ -720,12 +719,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_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 2510cebcdc0..188d23d0c59 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -519,6 +519,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/bvh.cpp b/intern/cycles/bvh/bvh.cpp index e92526ac1c4..1bb3e95c810 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -463,8 +463,7 @@ void RegularBVH::pack_aligned_inner(const BVHStackEntry& e, pack_aligned_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), - e0.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED, - e1.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED); + e0.node->m_visibility, e1.node->m_visibility); } void RegularBVH::pack_aligned_node(int idx, @@ -475,7 +474,8 @@ void RegularBVH::pack_aligned_node(int idx, { int4 data[BVH_NODE_SIZE] = { - make_int4(visibility0, visibility1, c0, c1), + 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)), @@ -688,9 +688,7 @@ 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]; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index afe21c49730..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, @@ -1694,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, @@ -2078,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, @@ -2110,7 +2124,7 @@ public: return false; } /* Save binary for reuse. */ - if(!save_binary(program, clbin)) { + if(!save_binary(program, cache_clbin)) { return false; } } @@ -2208,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/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 1869457f0c3..b27afaa9869 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -283,7 +283,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index b5405e8e57b..d7f6bf86c71 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -206,7 +206,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -252,7 +252,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 34753ff067d..eb98eaf7455 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -366,7 +366,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index a877e5bb341..90cad9d91c0 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -273,7 +273,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -312,7 +312,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index aa21633070a..7bf7c2806d4 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -615,6 +615,36 @@ ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness sc->data1 = fmaxf(roughness, sc->data1); /* 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; @@ -646,10 +676,8 @@ 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 */ @@ -668,24 +696,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; @@ -740,10 +752,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 */ @@ -820,8 +830,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 +845,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; @@ -906,8 +906,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 index 6060d7d8ccb..acb50ce6faa 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -42,7 +42,7 @@ ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) /* 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) { + 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)); @@ -117,7 +117,7 @@ ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda if(dotW_WH < 0.0f) return make_float3(0.0f, 0.0f, 0.0f); - float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH); + 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 @@ -200,9 +200,9 @@ 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 -1.0f; + return -0.9999f; - const float inv_wz2 = 1.0f / (w.z*w.z); + 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) @@ -271,7 +271,10 @@ ccl_device_inline float mf_ggx_albedo(float r) ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) { - return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z; + 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) @@ -348,11 +351,7 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc) ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc) { -#ifdef __KERNEL_OPENCL__ - if(all(sc->T == 0.0f)) -#else - if(sc->T == make_float3(0.0f, 0.0f, 0.0f)) -#endif + if(is_zero(sc->T)) sc->T = make_float3(1.0f, 0.0f, 0.0f); return bsdf_microfacet_multi_ggx_common_setup(sc); @@ -410,6 +409,10 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC *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; } @@ -467,10 +470,23 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const S *eval *= *pdf; *omega_in = X*localO.x + Y*localO.y + Z*localO.z; - if(localO.z*localI.z > 0.0f) + 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 + } + else { +#ifdef __RAY_DIFFERENTIALS__ + float cosI = dot(Z, I); + float dnp = max(sqrtf(1.0f - (sc->data2 * sc->data2 * (1.0f - cosI*cosI))), 1e-7f); + *domega_in_dx = -(sc->data2 * dIdx) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdx, Z)) * Z; + *domega_in_dy = -(sc->data2 * dIdy) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdy, Z)) * Z; +#endif + return LABEL_TRANSMIT|LABEL_GLOSSY; + } } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 89b1998d1ce..b0c5280b6cb 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__ diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index 2fb8e219884..dabba3fb1f0 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -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_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index fc081bda525..eb0decc800b 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -255,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; @@ -277,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. */ @@ -335,9 +342,16 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg, 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 suc hcases 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__ @@ -393,9 +407,16 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, 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_shadow.h b/intern/cycles/kernel/kernel_shadow.h index db2fc84834a..d1576754d2e 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -75,7 +75,12 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, } uint num_hits; - blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + if(max_hits == 0) { + blocked = true; + num_hits = 0; + } else { + blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + } /* if no opaque surface found but we did find transparent hits, shade them */ if(!blocked && num_hits > 0) { diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 5de58ba28ed..a9be2ae717a 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -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 */ 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/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/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b14da3e63d0..a632ddc0598 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 @@ -49,6 +50,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/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp new file mode 100644 index 00000000000..1fee6b2c081 --- /dev/null +++ b/intern/cycles/render/constant_fold.cpp @@ -0,0 +1,122 @@ +/* + * 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" + +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 +{ + 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::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, float3 input_value, bool clamp) const +{ + if(!input->link) { + make_constant_clamp(input_value, clamp); + return true; + } + else if(!clamp) { + bypass(input->link); + return true; + } + + return false; +} + +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..978c8e5335a --- /dev/null +++ b/intern/cycles/render/constant_fold.h @@ -0,0 +1,59 @@ +/* + * 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" + +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, always return true for convenience. */ + 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; + + /* 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, float3 input_value, bool clamp) const; +}; + +CCL_NAMESPACE_END + +#endif /* __CONSTANT_FOLD_H__ */ + diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index fd48bf2631e..66601fa3502 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" @@ -126,17 +127,6 @@ ShaderOutput *ShaderNode::output(ustring name) return NULL; } -bool ShaderNode::all_inputs_constant() const -{ - foreach(ShaderInput *input, inputs) { - if(input->link) { - return false; - } - } - - return true; -} - void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) { foreach(ShaderInput *input, inputs) { @@ -278,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); @@ -373,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 */ @@ -525,15 +514,8 @@ void ShaderGraph::constant_fold() } } /* Optimize current node. */ - if(node->constant_fold(this, output, output->links[0])) { - /* Apply optimized value to other connected sockets and disconnect. */ - vector<ShaderInput*> links(output->links); - for(size_t i = 0; i < links.size(); i++) { - if(i > 0) - links[i]->parent->copy_value(links[i]->socket_type, *links[0]->parent, links[0]->socket_type); - disconnect(links[i]); - } - } + ConstantFolder folder(this, node, output); + node->constant_fold(folder); } } } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 61100cda60b..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. @@ -41,6 +41,7 @@ class ShaderGraph; class SVMCompiler; class OSLCompiler; class OutputNode; +class ConstantFolder; /* Bump * @@ -140,9 +141,7 @@ public: /* ** Node optimization ** */ /* Check whether the node can be replaced with single constant. */ - virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; } - - bool all_inputs_constant() const; + 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. @@ -251,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/integrator.cpp b/intern/cycles/render/integrator.cpp index 2a10eb474a4..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); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 661719ed545..8b0ed9f77b2 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -588,7 +588,8 @@ void Mesh::compute_bvh(DeviceScene *dscene, 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; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, objects); @@ -1222,7 +1223,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; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, scene->objects); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 15b55d17301..e26084c690b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -22,6 +22,7 @@ #include "svm_color_util.h" #include "svm_math_util.h" #include "osl.h" +#include "constant_fold.h" #include "util_sky_model.h" #include "util_foreach.h" @@ -1576,14 +1577,11 @@ RGBToBWNode::RGBToBWNode() { } -bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void RGBToBWNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(linear_rgb_to_gray(color)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(linear_rgb_to_gray(color)); } - - return false; } void RGBToBWNode::compile(SVMCompiler& compiler) @@ -1661,38 +1659,35 @@ ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool auto special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } -bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ConvertNode::constant_fold(const ConstantFolder& folder) { /* 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(all_inputs_constant()) { + if(folder.all_inputs_constant()) { if(from == SocketType::FLOAT) { if(SocketType::is_float3(to)) { - optimized->set(make_float3(value_float, value_float, value_float)); - return true; + folder.make_constant(make_float3(value_float, value_float, value_float)); } } else if(SocketType::is_float3(from)) { if(to == SocketType::FLOAT) { - if(from == SocketType::COLOR) + if(from == SocketType::COLOR) { /* color to float */ - optimized->set(linear_rgb_to_gray(value_color)); - else + folder.make_constant(linear_rgb_to_gray(value_color)); + } + else { /* vector/point/normal to float */ - optimized->set(average(value_vector)); - return true; + folder.make_constant(average(value_vector)); + } } else if(SocketType::is_float3(to)) { - optimized->set(value_color); - return true; + folder.make_constant(value_color); } } } - - return false; } void ConvertNode::compile(SVMCompiler& compiler) @@ -2362,13 +2357,15 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void EmissionNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 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 */ @@ -2412,13 +2409,15 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void BackgroundNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 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 */ @@ -3380,10 +3379,9 @@ ValueNode::ValueNode() { } -bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ValueNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ValueNode::compile(SVMCompiler& compiler) @@ -3416,10 +3414,9 @@ ColorNode::ColorNode() { } -bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ColorNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ColorNode::compile(SVMCompiler& compiler) @@ -3468,6 +3465,20 @@ 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) @@ -3499,35 +3510,28 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +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 == 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 == 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 */ @@ -3589,26 +3593,21 @@ InvertNode::InvertNode() { } -bool InvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +void InvertNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); if(!fac_in->link) { /* evaluate fully constant node */ if(!color_in->link) { - optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); - return true; + folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); } /* remove no-op node */ else if(fac == 0.0f) { - graph->relink(this, color_out, color_in->link); - return true; + folder.bypass(color_in->link); } } - - return false; } void InvertNode::compile(SVMCompiler& compiler) @@ -3697,61 +3696,47 @@ void MixNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +void MixNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *color1_in = input("Color1"); ShaderInput *color2_in = input("Color2"); - ShaderOutput *color_out = output("Color"); /* evaluate fully constant node */ - if(all_inputs_constant()) { - float3 result = svm_mix(type, fac, color1, color2); - optimized->set(use_clamp ? svm_mix_clamp(result) : result); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); + return; } /* remove no-op node when factor is 0.0 */ if(!fac_in->link && fac <= 0.0f) { /* note that some of the modes will clamp out of bounds values even without use_clamp */ - if(!color1_in->link) { - float3 result = svm_mix(type, 0.0f, color1, color1); - optimized->set(use_clamp ? svm_mix_clamp(result) : result); - return true; + if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { + if(!color1_in->link) { + folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp); + return; + } } - else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) { - graph->relink(this, color_out, color1_in->link); - return true; + else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; } } - if(type != NODE_MIX_BLEND) { - return false; - } - - /* remove useless mix colors nodes */ - if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) { - graph->relink(this, color_out, color1_in->link); - return true; - } - if(!color1_in->link && !color2_in->link && color1 == color2) { - optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); - return true; - } - - /* remove no-op mix color node when factor is 1.0 */ - if(!fac_in->link && fac >= 1.0f) { - if(!color2_in->link) { - optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); - return true; + if(type == NODE_MIX_BLEND) { + /* remove useless mix colors nodes */ + if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { + if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; + } } - else if(!use_clamp) { - graph->relink(this, color_out, color2_in->link); - return true; + + /* remove no-op mix color node when factor is 1.0 */ + if(!fac_in->link && fac >= 1.0f) { + if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) { + return; + } } } - - return false; } /* Combine RGB */ @@ -3774,14 +3759,11 @@ CombineRGBNode::CombineRGBNode() { } -bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineRGBNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(make_float3(r, g, b)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(r, g, b)); } - - return false; } void CombineRGBNode::compile(SVMCompiler& compiler) @@ -3829,14 +3811,11 @@ CombineXYZNode::CombineXYZNode() { } -bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineXYZNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(make_float3(x, y, z)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(x, y, z)); } - - return false; } void CombineXYZNode::compile(SVMCompiler& compiler) @@ -3884,14 +3863,11 @@ CombineHSVNode::CombineHSVNode() { } -bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void CombineHSVNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(hsv_to_rgb(make_float3(h, s, v))); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); } - - return false; } void CombineHSVNode::compile(SVMCompiler& compiler) @@ -3932,14 +3908,11 @@ GammaNode::GammaNode() { } -bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void GammaNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_math_gamma_color(color, gamma)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_gamma_color(color, gamma)); } - - return false; } void GammaNode::compile(SVMCompiler& compiler) @@ -3979,14 +3952,11 @@ BrightContrastNode::BrightContrastNode() { } -bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void BrightContrastNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_brightness_contrast(color, bright, contrast)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_brightness_contrast(color, bright, contrast)); } - - return false; } void BrightContrastNode::compile(SVMCompiler& compiler) @@ -4029,18 +3999,16 @@ SeparateRGBNode::SeparateRGBNode() { } -bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateRGBNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(color[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(color[channel]); + return; } } } - - return false; } void SeparateRGBNode::compile(SVMCompiler& compiler) @@ -4088,18 +4056,16 @@ SeparateXYZNode::SeparateXYZNode() { } -bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateXYZNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(vector[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(vector[channel]); + return; } } } - - return false; } void SeparateXYZNode::compile(SVMCompiler& compiler) @@ -4147,20 +4113,18 @@ SeparateHSVNode::SeparateHSVNode() { } -bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void SeparateHSVNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { float3 hsv = rgb_to_hsv(color); for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == socket) { - optimized->set(hsv[channel]); - return true; + if(outputs[channel] == folder.output) { + folder.make_constant(hsv[channel]); + return; } } } - - return false; } void SeparateHSVNode::compile(SVMCompiler& compiler) @@ -4546,14 +4510,11 @@ BlackbodyNode::BlackbodyNode() { } -bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void BlackbodyNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - optimized->set(svm_math_blackbody_color(temperature)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_blackbody_color(temperature)); } - - return false; } void BlackbodyNode::compile(SVMCompiler& compiler) @@ -4655,15 +4616,11 @@ MathNode::MathNode() { } -bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void MathNode::constant_fold(const ConstantFolder& folder) { - if(all_inputs_constant()) { - float value = svm_math(type, value1, value2); - optimized->set(use_clamp ? saturate(value) : value); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); } - - return false; } void MathNode::compile(SVMCompiler& compiler) @@ -4717,29 +4674,25 @@ VectorMathNode::VectorMathNode() { } -bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void VectorMathNode::constant_fold(const ConstantFolder& folder) { float value; float3 vector; - if(all_inputs_constant()) { + if(folder.all_inputs_constant()) { svm_vector_math(&value, &vector, type, vector1, vector2); - if(socket == output("Value")) { - optimized->set(value); - return true; + if(folder.output == output("Value")) { + folder.make_constant(value); } - else if(socket == output("Vector")) { - optimized->set(vector); - return true; + else if(folder.output == output("Vector")) { + folder.make_constant(vector); } } - - return false; } void VectorMathNode::compile(SVMCompiler& compiler) @@ -4873,7 +4826,7 @@ void BumpNode::compile(OSLCompiler& compiler) compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +void BumpNode::constant_fold(const ConstantFolder& folder) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4881,18 +4834,15 @@ bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) 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; } @@ -5112,12 +5062,10 @@ OSLNode::~OSLNode() ShaderNode *OSLNode::clone() const { - OSLNode *node = new OSLNode(*this); - node->type = new NodeType(*type); - return node; + return OSLNode::create(this->inputs.size(), this); } -OSLNode* OSLNode::create(size_t num_inputs) +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 */ @@ -5127,7 +5075,17 @@ OSLNode* OSLNode::create(size_t num_inputs) char *node_memory = (char*) operator new(node_size + inputs_size); memset(node_memory, 0, node_size + inputs_size); - return new(node_memory) OSLNode(); + 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() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 3245fdfb6d9..caad11af0f8 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -289,7 +289,7 @@ public: class RGBToBWNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBToBWNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 color; }; @@ -299,7 +299,7 @@ public: ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); SHADER_NODE_BASE_CLASS(ConvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); SocketType::Type from, to; @@ -436,7 +436,7 @@ public: class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } @@ -449,7 +449,7 @@ public: class BackgroundNode : public ShaderNode { public: SHADER_NODE_CLASS(BackgroundNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } float3 color; @@ -605,7 +605,7 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value; }; @@ -614,7 +614,7 @@ class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 value; }; @@ -622,12 +622,13 @@ public: 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, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float fac; }; @@ -643,7 +644,7 @@ public: class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float fac; @@ -653,7 +654,7 @@ public: class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } @@ -667,7 +668,7 @@ public: class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float r, g, b; @@ -676,7 +677,7 @@ public: class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float h, s, v; @@ -685,7 +686,7 @@ public: class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float x, y, z; @@ -694,7 +695,7 @@ public: class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -704,7 +705,7 @@ public: class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -715,7 +716,7 @@ public: class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -724,7 +725,7 @@ public: class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -733,7 +734,7 @@ public: class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 vector; @@ -806,7 +807,7 @@ public: class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float temperature; @@ -816,7 +817,7 @@ 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, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value1; float value2; @@ -837,7 +838,7 @@ 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, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 vector1; float3 vector2; @@ -859,7 +860,7 @@ public: class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); bool has_spatial_varying() { return true; } virtual int get_feature() { return NODE_FEATURE_BUMP; @@ -920,7 +921,7 @@ public: class OSLNode : public ShaderNode { public: - static OSLNode *create(size_t num_inputs); + static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL); ~OSLNode(); ShaderNode *clone() const; diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index ff1f678c2d2..662d87e8b6b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -184,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) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index e8367e1eb36..b341837b7e8 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -263,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 925e84ad96d..05e807ff60c 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -136,6 +136,7 @@ public: BVH_NUM_TYPES, } bvh_type; bool use_bvh_spatial_split; + bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; @@ -144,6 +145,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; } @@ -152,6 +154,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); } }; @@ -210,6 +213,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/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/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 7e77ba3a41f..0dd5d15b011 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -530,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_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index eeb6a2469ee..abce3ea6588 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -707,6 +707,7 @@ 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 */ @@ -717,16 +718,16 @@ int GHOST_ContextWGL::choose_pixel_format( needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */ #endif 0 - ), + )), PFD_TYPE_RGBA, /* color type */ - (needAlpha ? 32 : 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 */ 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_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 55d013f6e5f..6f349543eed 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1985,9 +1985,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, ); } #endif -/* +/** * 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 diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index c9bcb38ab68..6a27d7aadf9 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -95,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; @@ -341,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); } 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/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 a17dcef81c7..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; @@ -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++) { @@ -310,6 +313,9 @@ void main() 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__ */ |