diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2017-03-28 11:41:10 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2017-03-28 11:41:10 +0300 |
commit | 885260117d6a9080ce073a1fb402b7af060f8645 (patch) | |
tree | 1769a4c180115a0fdda86d5554159c43691f461b /intern | |
parent | 6d21970aa06a31398ed4a78b1c596f30a0b9ee87 (diff) | |
parent | e1909958d9ec48333a7bfd0d34aede66efc9b1ad (diff) |
Merge branch 'master' into blender2.8
Conflicts:
source/blender/blenloader/intern/readfile.c
source/blender/windowmanager/intern/wm_window.c
Diffstat (limited to 'intern')
55 files changed, 826 insertions, 148 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 6c5bcf09305..cbf469b3a89 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1096,6 +1096,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup): default=1.0, ) + cls.is_shadow_catcher = BoolProperty( + name="Shadow Catcher", + description="Only render shadows on this object, for compositing renders into real footage", + default=False, + ) + @classmethod def unregister(cls): del bpy.types.Object.cycles diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index eec897474c5..4894b301606 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -268,7 +268,7 @@ class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel): row = col.row() row.prop(ccscene, "minimum_width", text="Min Pixels") - row.prop(ccscene, "maximum_width", text="Max Ext.") + row.prop(ccscene, "maximum_width", text="Max Extension") class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): @@ -786,6 +786,8 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): if ob.type != 'LAMP': flow.prop(visibility, "shadow") + layout.prop(cob, "is_shadow_catcher") + col = layout.column() col.label(text="Performance:") row = col.row() diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 637cf7abda8..968861391a2 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -343,6 +343,13 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, object_updated = true; } + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher"); + if(is_shadow_catcher != object->is_shadow_catcher) { + object->is_shadow_catcher = is_shadow_catcher; + object_updated = true; + } + /* object sync * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 8baa53fc2ec..f35565d8330 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -28,6 +28,7 @@ #include "util_debug.h" #include "util_string.h" +#include "util_task.h" CCL_NAMESPACE_BEGIN @@ -1164,6 +1165,8 @@ void BlenderSync::sync_materials(bool update_all) /* material loop */ BL::BlendData::materials_iterator b_mat; + TaskPool pool; + for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) { Shader *shader; @@ -1199,9 +1202,22 @@ void BlenderSync::sync_materials(bool update_all) shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP; shader->set_graph(graph); + + /* By simplifying the shader graph as soon as possible, some redundant shader nodes + * might be removed which prevents loading unneccessary attributes later. + * + * However, since graph simplification also accounts for e.g. mix weight, this would + * cause frequent expensive resyncs in interactive sessions, so for those sessions + * optimization is only performed right before compiling. */ + if(!preview) { + pool.push(function_bind(&ShaderGraph::simplify, shader->graph, scene)); + } + shader->tag_update(scene); } } + + pool.wait_work(); } /* Sync World */ diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 6b07b9d04bd..21eb3379694 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -48,11 +48,11 @@ std::ostream& operator <<(std::ostream &os, os << "Max nodes group: " << requested_features.max_nodes_group << std::endl; /* TODO(sergey): Decode bitflag into list of names. */ os << "Nodes features: " << requested_features.nodes_features << std::endl; - os << "Use hair: " + os << "Use Hair: " << string_from_bool(requested_features.use_hair) << std::endl; - os << "Use object motion: " + os << "Use Object Motion: " << string_from_bool(requested_features.use_object_motion) << std::endl; - os << "Use camera motion: " + os << "Use Camera Motion: " << string_from_bool(requested_features.use_camera_motion) << std::endl; os << "Use Baking: " << string_from_bool(requested_features.use_baking) << std::endl; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index ec15a254f81..468a5b1515a 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -121,6 +121,9 @@ public: /* Use Transparent shadows */ bool use_transparent; + /* Use various shadow tricks, such as shadow catcher. */ + bool use_shadow_tricks; + DeviceRequestedFeatures() { /* TODO(sergey): Find more meaningful defaults. */ @@ -137,6 +140,7 @@ public: use_integrator_branched = false; use_patch_evaluation = false; use_transparent = false; + use_shadow_tricks = false; } bool modified(const DeviceRequestedFeatures& requested_features) @@ -153,7 +157,8 @@ public: use_volume == requested_features.use_volume && use_integrator_branched == requested_features.use_integrator_branched && use_patch_evaluation == requested_features.use_patch_evaluation && - use_transparent == requested_features.use_transparent); + use_transparent == requested_features.use_transparent && + use_shadow_tricks == requested_features.use_shadow_tricks); } /* Convert the requested features structure to a build options, @@ -197,6 +202,9 @@ public: if(!use_transparent && !use_volume) { build_options += " -D__NO_TRANSPARENT__"; } + if(!use_shadow_tricks) { + build_options += " -D__NO_SHADOW_TRICKS__"; + } return build_options; } }; diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 598e138dbea..1358288f832 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -230,30 +230,63 @@ ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg, #endif #ifdef __SHADOW_RECORD_ALL__ -ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, uint max_hits, uint *num_hits) +ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, + const Ray *ray, + Intersection *isect, + int skip_object, + uint max_hits, + uint *num_hits) { # ifdef __OBJECT_MOTION__ if(kernel_data.bvh.have_motion) { # ifdef __HAIR__ - if(kernel_data.bvh.have_curves) - return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_curves) { + return bvh_intersect_shadow_all_hair_motion(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __HAIR__ */ - return bvh_intersect_shadow_all_motion(kg, ray, isect, max_hits, num_hits); + return bvh_intersect_shadow_all_motion(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); } # endif /* __OBJECT_MOTION__ */ # ifdef __HAIR__ - if(kernel_data.bvh.have_curves) - return bvh_intersect_shadow_all_hair(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_curves) { + return bvh_intersect_shadow_all_hair(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __HAIR__ */ # ifdef __INSTANCING__ - if(kernel_data.bvh.have_instancing) - return bvh_intersect_shadow_all_instancing(kg, ray, isect, max_hits, num_hits); + if(kernel_data.bvh.have_instancing) { + return bvh_intersect_shadow_all_instancing(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); + } # endif /* __INSTANCING__ */ - return bvh_intersect_shadow_all(kg, ray, isect, max_hits, num_hits); + return bvh_intersect_shadow_all(kg, + ray, + isect, + skip_object, + max_hits, + num_hits); } #endif /* __SHADOW_RECORD_ALL__ */ diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 8f7c005e961..b2555b3a6bb 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -45,6 +45,7 @@ ccl_device_inline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, + const int skip_object, const uint max_hits, uint *num_hits) { @@ -189,6 +190,16 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, while(prim_addr < prim_addr2) { kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); +#ifdef __SHADOW_TRICKS__ + uint tri_object = (object == OBJECT_NONE) + ? kernel_tex_fetch(__prim_object, prim_addr) + : object; + if(tri_object == skip_object) { + ++prim_addr; + continue; + } +#endif + bool hit; /* todo: specialized intersect functions which don't fill in @@ -398,6 +409,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, + const int skip_object, const uint max_hits, uint *num_hits) { @@ -406,6 +418,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(QBVH)(kg, ray, isect_array, + skip_object, max_hits, num_hits); } @@ -416,6 +429,7 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, + skip_object, max_hits, num_hits); } diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 5d960787134..1663e23c334 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -33,6 +33,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, + const int skip_object, const uint max_hits, uint *num_hits) { @@ -270,6 +271,16 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, while(prim_addr < prim_addr2) { kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); +#ifdef __SHADOW_TRICKS__ + uint tri_object = (object == OBJECT_NONE) + ? kernel_tex_fetch(__prim_object, prim_addr) + : object; + if(tri_object == skip_object) { + ++prim_addr; + continue; + } +#endif + bool hit; /* todo: specialized intersect functions which don't fill in diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index c589c112cc2..823d30dde78 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -52,10 +52,17 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v { eval->diffuse = value; } +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis = make_float3(0.0f, 0.0f, 0.0f); +#endif } -ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value) +ccl_device_inline void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value, float mis_weight) { +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis += value; +#endif + value *= mis_weight; #ifdef __PASSES__ if(eval->use_light_pass) { if(CLOSURE_IS_BSDF_DIFFUSE(type)) @@ -96,7 +103,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) } } -ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) +ccl_device_inline void bsdf_eval_mis(BsdfEval *eval, float value) { #ifdef __PASSES__ if(eval->use_light_pass) { @@ -115,8 +122,19 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) } } +ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) +{ +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis *= value; +#endif + bsdf_eval_mis(eval, value); +} + ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value) { +#ifdef __SHADOW_TRICKS__ + eval->sum_no_mis *= value; +#endif #ifdef __PASSES__ if(eval->use_light_pass) { eval->diffuse *= value; @@ -134,7 +152,7 @@ ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value) #endif } -ccl_device_inline float3 bsdf_eval_sum(BsdfEval *eval) +ccl_device_inline float3 bsdf_eval_sum(const BsdfEval *eval) { #ifdef __PASSES__ if(eval->use_light_pass) { @@ -198,6 +216,12 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) { L->emission = make_float3(0.0f, 0.0f, 0.0f); } + +#ifdef __SHADOW_TRICKS__ + L->path_total = make_float3(0.0f, 0.0f, 0.0f); + L->path_total_shaded = make_float3(0.0f, 0.0f, 0.0f); + L->shadow_color = make_float3(0.0f, 0.0f, 0.0f); +#endif } ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput, @@ -252,7 +276,12 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro } } -ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 alpha, float3 bsdf, float3 ao, int bounce) +ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, + float3 throughput, + float3 alpha, + float3 bsdf, + float3 ao, + int bounce) { #ifdef __PASSES__ if(L->use_light_pass) { @@ -271,6 +300,26 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput { L->emission += throughput*bsdf*ao; } + +#ifdef __SHADOW_TRICKS__ + float3 light = throughput * bsdf; + L->path_total += light; + L->path_total_shaded += ao * light; +#endif +} + +ccl_device_inline void path_radiance_accum_total_ao( + PathRadiance *L, + float3 throughput, + float3 bsdf) +{ +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * bsdf; +#else + (void) L; + (void) throughput; + (void) bsdf; +#endif } ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, float3 shadow, float shadow_fac, int bounce, bool is_lamp) @@ -301,15 +350,38 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through { L->emission += throughput*bsdf_eval->diffuse*shadow; } + +#ifdef __SHADOW_TRICKS__ + float3 light = throughput * bsdf_eval->sum_no_mis; + L->path_total += light; + L->path_total_shaded += shadow * light; +#endif +} + +ccl_device_inline void path_radiance_accum_total_light( + PathRadiance *L, + float3 throughput, + const BsdfEval *bsdf_eval) +{ +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * bsdf_eval->sum_no_mis; +#else + (void) L; + (void) throughput; + (void) bsdf_eval; +#endif } -ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 throughput, float3 value, int bounce) +ccl_device_inline void path_radiance_accum_background(PathRadiance *L, + ccl_addr_space PathState *state, + float3 throughput, + float3 value) { #ifdef __PASSES__ if(L->use_light_pass) { - if(bounce == 0) + if(state->bounce == 0) L->background += throughput*value; - else if(bounce == 1) + else if(state->bounce == 1) L->direct_emission += throughput*value; else L->indirect += throughput*value; @@ -319,6 +391,13 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th { L->emission += throughput*value; } + +#ifdef __SHADOW_TRICKS__ + L->path_total += throughput * value; + if(state->flag & PATH_RAY_SHADOW_CATCHER_ONLY) { + L->path_total_shaded += throughput * value; + } +#endif } ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L) @@ -501,5 +580,34 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance L->emission += L_sample->emission * fac; } -CCL_NAMESPACE_END +#ifdef __SHADOW_TRICKS__ +/* Calculate current shadow of the path. */ +ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L) +{ + float path_total = average(L->path_total); + float path_total_shaded = average(L->path_total_shaded); + if(path_total != 0.0f) { + return path_total_shaded / path_total; + } + return 1.0f; +} +/* Calculate final light sum and transparency for shadow catcher object. */ +ccl_device_inline float3 path_radiance_sum_shadowcatcher(KernelGlobals *kg, + const PathRadiance *L, + ccl_addr_space float* L_transparent) +{ + const float shadow = path_radiance_sum_shadow(L); + float3 L_sum; + if(kernel_data.background.transparent) { + *L_transparent = shadow; + L_sum = make_float3(0.0f, 0.0f, 0.0f); + } + else { + L_sum = L->shadow_color * shadow; + } + return L_sum; +} +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index cf14a159e47..9e7d51f23f5 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -156,7 +156,12 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, if(bsdf_eval_is_zero(eval)) return false; - if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + if(kernel_data.integrator.light_inv_rr_threshold > 0.0f +#ifdef __SHADOW_TRICKS__ + && (state->flag & PATH_RAY_SHADOW_CATCHER) == 0 +#endif + ) + { float probability = max3(fabs(bsdf_eval_sum(eval))) * kernel_data.integrator.light_inv_rr_threshold; if(probability < 1.0f) { if(rand_terminate >= probability) { diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index ebf03ad9778..31d5285796c 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -92,6 +92,9 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce); } + else { + path_radiance_accum_total_ao(L, throughput, ao_bsdf); + } } } @@ -290,9 +293,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* sample background shader */ float3 L_background = indirect_background(kg, emission_sd, state, ray); path_radiance_accum_background(L, + state, throughput, - L_background, - state->bounce); + L_background); #endif /* __BACKGROUND__ */ break; @@ -312,6 +315,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, shader_merge_closures(sd); #endif /* __BRANCHED_PATH__ */ +#ifdef __SHADOW_TRICKS__ + if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { + state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + } +#endif /* __SHADOW_TRICKS__ */ + /* blurring of bsdf after bounces, for rays that have a small likelihood * of following this particular path (diffuse, rough glossy) */ if(kernel_data.integrator.filter_glossy != FLT_MAX) { @@ -374,7 +383,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); float bssrdf_u, bssrdf_v; path_state_rng_2D(kg, @@ -396,7 +405,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #if defined(__EMISSION__) && defined(__BRANCHED_PATH__) if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_indirect; + int all = (kernel_data.integrator.sample_all_lights_indirect) || + (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, rng, sd, @@ -466,7 +476,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, &state, 0x51633e2d); + lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); } if(state.bounce > kernel_data.integrator.ao_bounces) { @@ -611,7 +621,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __BACKGROUND__ /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(&L, throughput, L_background, state.bounce); + path_radiance_accum_background(&L, &state, throughput, L_background); #endif /* __BACKGROUND__ */ break; @@ -625,6 +635,21 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); +#ifdef __SHADOW_TRICKS__ + if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { + if(state.flag & PATH_RAY_CAMERA) { + state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY); + state.catcher_object = sd.object; + if(!kernel_data.background.transparent) { + L.shadow_color = indirect_background(kg, &emission_sd, &state, &ray); + } + } + } + else { + state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + } +#endif /* __SHADOW_TRICKS__ */ + /* holdout */ #ifdef __HOLDOUT__ if(((sd.flag & SD_HOLDOUT) || @@ -742,7 +767,16 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } #endif /* __SUBSURFACE__ */ - float3 L_sum = path_radiance_clamp_and_sum(kg, &L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state.flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, &L); + } kernel_write_light_passes(kg, buffer, &L, sample); diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index d58960cae4e..36fd6c95fe7 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -55,8 +55,12 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, light_ray.dP = sd->dP; light_ray.dD = differential3_zero(); - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) + if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce); + } + else { + path_radiance_accum_total_ao(L, throughput*num_samples_inv, ao_bsdf); + } } } } @@ -147,7 +151,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, continue; /* set up random number generator */ - uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; RNG bssrdf_rng = cmj_hash(*rng, i); @@ -206,7 +210,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, #ifdef __EMISSION__ /* direct light */ if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_direct; + int all = (kernel_data.integrator.sample_all_lights_direct) || + (state->flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light( kg, rng, @@ -280,7 +285,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(rng, &state, 0x51633e2d); + lcg_state = lcg_state_init(rng, state.rng_offset, state.sample, 0x51633e2d); } bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); @@ -461,7 +466,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __BACKGROUND__ /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); - path_radiance_accum_background(&L, throughput, L_background, state.bounce); + path_radiance_accum_background(&L, &state, throughput, L_background); #endif /* __BACKGROUND__ */ break; @@ -472,6 +477,21 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); shader_merge_closures(&sd); +#ifdef __SHADOW_TRICKS__ + if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) { + if(state.flag & PATH_RAY_CAMERA) { + state.flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY); + state.catcher_object = sd.object; + if(!kernel_data.background.transparent) { + L.shadow_color = indirect_background(kg, &emission_sd, &state, &ray); + } + } + } + else { + state.flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + } +#endif /* __SHADOW_TRICKS__ */ + /* holdout */ #ifdef __HOLDOUT__ if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) { @@ -544,7 +564,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __EMISSION__ /* direct light */ if(kernel_data.integrator.use_direct_light) { - int all = kernel_data.integrator.sample_all_lights_direct; + int all = (kernel_data.integrator.sample_all_lights_direct) || + (state.flag & PATH_RAY_SHADOW_CATCHER); kernel_branched_path_surface_connect_light(kg, rng, &sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all); } @@ -581,7 +602,16 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif /* __VOLUME__ */ } - float3 L_sum = path_radiance_clamp_and_sum(kg, &L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state.flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, &L, &L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, &L); + } kernel_write_light_passes(kg, buffer, &L, sample); diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h index 7b903556bf9..596210f442e 100644 --- a/intern/cycles/kernel/kernel_path_common.h +++ b/intern/cycles/kernel/kernel_path_common.h @@ -22,7 +22,7 @@ ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int x, int y, - ccl_addr_space RNG *rng, + RNG *rng, ccl_addr_space Ray *ray) { float filter_u; diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h index 661dc52fb31..c0cd2a63120 100644 --- a/intern/cycles/kernel/kernel_path_state.h +++ b/intern/cycles/kernel/kernel_path_state.h @@ -19,7 +19,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void path_state_init(KernelGlobals *kg, ShaderData *stack_sd, ccl_addr_space PathState *state, - ccl_addr_space RNG *rng, + RNG *rng, int sample, ccl_addr_space Ray *ray) { @@ -54,6 +54,10 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, state->volume_stack[0].shader = SHADER_NONE; } #endif + +#ifdef __SHADOW_TRICKS__ + state->catcher_object = OBJECT_NONE; +#endif } ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathState *state, int label) diff --git a/intern/cycles/kernel/kernel_path_subsurface.h b/intern/cycles/kernel/kernel_path_subsurface.h index d22ec992074..10b568ac3dd 100644 --- a/intern/cycles/kernel/kernel_path_subsurface.h +++ b/intern/cycles/kernel/kernel_path_subsurface.h @@ -28,7 +28,7 @@ bool kernel_path_subsurface_scatter( ShaderData *emission_sd, PathRadiance *L, ccl_addr_space PathState *state, - ccl_addr_space RNG *rng, + RNG *rng, ccl_addr_space Ray *ray, ccl_addr_space float3 *throughput, ccl_addr_space SubsurfaceIndirectRays *ss_indirect) @@ -47,7 +47,7 @@ bool kernel_path_subsurface_scatter( */ kernel_assert(!ss_indirect->tracing); - uint lcg_state = lcg_state_init_addrspace(rng, state, 0x68bc21eb); + uint lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0x68bc21eb); SubsurfaceIntersection ss_isect; float bssrdf_u, bssrdf_v; diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index efa23038089..076c82f3853 100644 --- a/intern/cycles/kernel/kernel_path_surface.h +++ b/intern/cycles/kernel/kernel_path_surface.h @@ -16,12 +16,18 @@ CCL_NAMESPACE_BEGIN -#if (defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__)) && !defined(__SPLIT_KERNEL__) - +#if defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__) || defined(__SHADOW_TRICKS__) /* branched path tracing: connect path directly to position on one or more lights and add it to L */ -ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng, - ShaderData *sd, ShaderData *emission_sd, PathState *state, float3 throughput, - float num_samples_adjust, PathRadiance *L, int sample_all_lights) +ccl_device_noinline void kernel_branched_path_surface_connect_light( + KernelGlobals *kg, + RNG *rng, + ShaderData *sd, + ShaderData *emission_sd, + ccl_addr_space PathState *state, + float3 throughput, + float num_samples_adjust, + PathRadiance *L, + int sample_all_lights) { #ifdef __EMISSION__ /* sample illumination from lights to find path contribution */ @@ -66,6 +72,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light); + } } } } @@ -100,6 +109,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_inv, &L_light); + } } } } @@ -123,6 +135,9 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal /* accumulate */ path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput*num_samples_adjust, &L_light); + } } } } @@ -130,9 +145,17 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal } /* branched path tracing: bounce off or through surface to with new direction stored in ray */ -ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng, - ShaderData *sd, const ShaderClosure *sc, int sample, int num_samples, - float3 *throughput, PathState *state, PathRadiance *L, Ray *ray) +ccl_device bool kernel_branched_path_surface_bounce( + KernelGlobals *kg, + RNG *rng, + ShaderData *sd, + const ShaderClosure *sc, + int sample, + int num_samples, + ccl_addr_space float3 *throughput, + ccl_addr_space PathState *state, + PathRadiance *L, + Ray *ray) { /* sample BSDF */ float bsdf_pdf; @@ -189,7 +212,7 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng, #endif /* path tracing: connect path directly to position on a light and add it to L */ -ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_addr_space RNG *rng, +ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L) { @@ -197,6 +220,21 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ if(!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL))) return; +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + kernel_branched_path_surface_connect_light(kg, + rng, + sd, + emission_sd, + state, + throughput, + 1.0f, + L, + 1); + return; + } +#endif + /* sample illumination from lights to find path contribution */ float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; @@ -221,6 +259,9 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ /* accumulate */ path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp); } + else { + path_radiance_accum_total_light(L, throughput, &L_light); + } } } #endif @@ -228,7 +269,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ /* path tracing: bounce off or through surface to with new direction stored in ray */ ccl_device bool kernel_path_surface_bounce(KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h index 28e1b5ba98e..371f2c1c7cb 100644 --- a/intern/cycles/kernel/kernel_path_volume.h +++ b/intern/cycles/kernel/kernel_path_volume.h @@ -20,7 +20,7 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_path_volume_connect_light( KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ShaderData *emission_sd, float3 throughput, @@ -69,7 +69,7 @@ ccl_device #endif bool kernel_path_volume_bounce( KernelGlobals *kg, - ccl_addr_space RNG *rng, + RNG *rng, ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, @@ -117,10 +117,18 @@ bool kernel_path_volume_bounce( return true; } -#ifdef __BRANCHED_PATH__ -ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG *rng, - ShaderData *sd, ShaderData *emission_sd, float3 throughput, PathState *state, PathRadiance *L, - bool sample_all_lights, Ray *ray, const VolumeSegment *segment) +#ifndef __SPLIT_KERNEL__ +ccl_device void kernel_branched_path_volume_connect_light( + KernelGlobals *kg, + RNG *rng, + ShaderData *sd, + ShaderData *emission_sd, + float3 throughput, + ccl_addr_space PathState *state, + PathRadiance *L, + bool sample_all_lights, + Ray *ray, + const VolumeSegment *segment) { #ifdef __EMISSION__ if(!kernel_data.integrator.use_direct_light) @@ -270,7 +278,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG } #endif /* __EMISSION__ */ } -#endif /* __BRANCHED_PATH__ */ +#endif /* __SPLIT_KERNEL__ */ #endif /* __VOLUME_SCATTER__ */ diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index ad3fa32a809..485b7b84fc8 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -98,7 +98,7 @@ ccl_device uint sobol_lookup(const uint m, const uint frame, const uint ex, cons return index; } -ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension) +ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension) { #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { @@ -130,7 +130,7 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG * #endif } -ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy) +ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy) { #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { @@ -147,7 +147,7 @@ ccl_device_forceinline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *r } } -ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, ccl_addr_space RNG *rng, int x, int y, float *fx, float *fy) +ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, RNG *rng, int x, int y, float *fx, float *fy) { #ifdef __SOBOL_FULL_SCREEN__ uint px, py; @@ -259,12 +259,12 @@ ccl_device uint lcg_init(uint seed) * For branches in the path we must be careful not to reuse the same number * in a sequence and offset accordingly. */ -ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension) +ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int dimension) { return path_rng_1D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension); } -ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension) +ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int dimension) { /* the rng_offset is not increased for transparent bounces. if we do then * fully transparent objects can become subtly visible by the different @@ -277,29 +277,29 @@ ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, ccl_ad return path_rng_1D(kg, rng, state->sample, state->num_samples, rng_offset + dimension); } -ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy) +ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy) { path_rng_2D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension, fx, fy); } -ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension) +ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension) { return path_rng_1D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension); } -ccl_device_inline float path_branched_rng_1D_for_decision(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension) +ccl_device_inline float path_branched_rng_1D_for_decision(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension) { int rng_offset = state->rng_offset + state->transparent_bounce*PRNG_BOUNCE_NUM; return path_rng_1D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, rng_offset + dimension); } -ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy) +ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy) { path_rng_2D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension, fx, fy); } /* Utitility functions to get light termination value, since it might not be needed in many cases. */ -ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state) +ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state) { if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { return path_state_rng_1D_for_decision(kg, rng, state, PRNG_LIGHT_TERMINATE); @@ -307,7 +307,7 @@ ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_ return 0.0f; } -ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches) +ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, RNG *rng, const ccl_addr_space PathState *state, int branch, int num_branches) { if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { return path_branched_rng_1D_for_decision(kg, rng, state, branch, num_branches, PRNG_LIGHT_TERMINATE); @@ -315,7 +315,7 @@ ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, c return 0.0f; } -ccl_device_inline void path_state_branch(PathState *state, int branch, int num_branches) +ccl_device_inline void path_state_branch(ccl_addr_space PathState *state, int branch, int num_branches) { /* path is splitting into a branch, adjust so that each branch * still gets a unique sample from the same sequence */ @@ -324,18 +324,9 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b state->num_samples = state->num_samples*num_branches; } -ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble) -{ - return lcg_init(*rng + state->rng_offset + state->sample*scramble); -} - -/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */ - -ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng, - const ccl_addr_space PathState *state, - uint scramble) +ccl_device_inline uint lcg_state_init(RNG *rng, int rng_offset, int sample, uint scramble) { - return lcg_init(*rng + state->rng_offset + state->sample*scramble); + return lcg_init(*rng + rng_offset + sample*scramble); } ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 93a92c63a40..163777b713e 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -516,7 +516,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf); if(bsdf_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval*sc->weight); + bsdf_eval_accum(result_eval, sc->type, eval*sc->weight, 1.0f); sum_pdf += bsdf_pdf*sc->sample_weight; } @@ -544,7 +544,8 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, float mis_weight = use_mis? power_heuristic(light_pdf, bsdf_pdf): 1.0f; bsdf_eval_accum(result_eval, sc->type, - eval * sc->weight * mis_weight); + eval * sc->weight, + mis_weight); } } } @@ -576,7 +577,7 @@ void shader_bsdf_eval(KernelGlobals *kg, _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f); if(use_mis) { float weight = power_heuristic(light_pdf, pdf); - bsdf_eval_mul(eval, weight); + bsdf_eval_mis(eval, weight); } } } @@ -862,7 +863,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { sd->num_closure = 0; @@ -887,7 +888,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_ } if(rng && (sd->flag & SD_BSDF_NEEDS_LCG)) { - sd->lcg_state = lcg_state_init_addrspace(rng, state, 0xb4bc3953); + sd->lcg_state = lcg_state_init(rng, state->rng_offset, state->sample, 0xb4bc3953); } } @@ -944,7 +945,7 @@ ccl_device_inline void _shader_volume_phase_multi_eval(const ShaderData *sd, con float3 eval = volume_phase_eval(sd, sc, omega_in, &phase_pdf); if(phase_pdf != 0.0f) { - bsdf_eval_accum(result_eval, sc->type, eval); + bsdf_eval_accum(result_eval, sc->type, eval, 1.0f); sum_pdf += phase_pdf*sc->sample_weight; } diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 4efc6c8118d..0426e0a62c9 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -128,6 +128,7 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *hits, uint max_hits, @@ -140,6 +141,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, const bool blocked = scene_intersect_shadow_all(kg, ray, hits, + skip_object, max_hits, &num_hits); /* If no opaque surface found but we did find transparent hits, @@ -216,6 +218,7 @@ ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, uint max_hits, float3 *shadow) @@ -250,6 +253,7 @@ ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, return shadow_blocked_transparent_all_loop(kg, shadow_sd, state, + skip_object, ray, hits, max_hits, @@ -274,13 +278,14 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *isect, const bool blocked, const bool is_transparent_isect, float3 *shadow) { - if(blocked && is_transparent_isect) { + if((blocked && is_transparent_isect) || skip_object != OBJECT_NONE) { float3 throughput = make_float3(1.0f, 1.0f, 1.0f); float3 Pend = ray->P + ray->D*ray->t; int bounce = state->transparent_bounce; @@ -306,6 +311,23 @@ ccl_device bool shadow_blocked_transparent_stepped_loop( { break; } +#ifdef __SHADOW_TRICKS__ + if(skip_object != OBJECT_NONE) { + const int isect_object = (isect->object == PRIM_NONE) + ? kernel_tex_fetch(__prim_object, isect->prim) + : isect->object; + if(isect_object == skip_object) { + shader_setup_from_ray(kg, shadow_sd, isect, ray); + /* Move ray forward. */ + ray->P = ray_offset(shadow_sd->P, -shadow_sd->Ng); + if(ray->t != FLT_MAX) { + ray->D = normalize_len(Pend - ray->P, &ray->t); + } + bounce++; + continue; + } + } +#endif if(!shader_transparent_shadow(kg, isect)) { return true; } @@ -351,22 +373,31 @@ ccl_device bool shadow_blocked_transparent_stepped( KernelGlobals *kg, ShaderData *shadow_sd, ccl_addr_space PathState *state, + const int skip_object, Ray *ray, Intersection *isect, float3 *shadow) { - const bool blocked = scene_intersect(kg, - *ray, - PATH_RAY_SHADOW_OPAQUE, - isect, - NULL, - 0.0f, 0.0f); - const bool is_transparent_isect = blocked - ? shader_transparent_shadow(kg, isect) - : false; + bool blocked, is_transparent_isect; + if (skip_object == OBJECT_NONE) { + blocked = scene_intersect(kg, + *ray, + PATH_RAY_SHADOW_OPAQUE, + isect, + NULL, + 0.0f, 0.0f); + is_transparent_isect = blocked + ? shader_transparent_shadow(kg, isect) + : false; + } + else { + blocked = false; + is_transparent_isect = false; + } return shadow_blocked_transparent_stepped_loop(kg, shadow_sd, state, + skip_object, ray, isect, blocked, @@ -390,12 +421,21 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, if(ray->t == 0.0f) { return false; } +#ifdef __SHADOW_TRICKS__ + const int skip_object = state->catcher_object; +#else + const int skip_object = OBJECT_NONE; +#endif /* Do actual shadow shading. */ /* First of all, we check if integrator requires transparent shadows. * if not, we use simplest and fastest ever way to calculate occlusion. + * + * NOTE: We can't do quick opaque test here if we are on shadow-catcher + * path because we don't want catcher object to be casting shadow here. */ #ifdef __TRANSPARENT_SHADOWS__ - if(!kernel_data.integrator.transparent_shadows) + if(!kernel_data.integrator.transparent_shadows && + skip_object == OBJECT_NONE) #endif { return shadow_blocked_opaque(kg, @@ -440,6 +480,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_stepped_loop(kg, shadow_sd, state, + skip_object, ray, &isect, blocked, @@ -450,6 +491,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_all(kg, shadow_sd, state, + skip_object, ray, max_hits, shadow); @@ -458,6 +500,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, return shadow_blocked_transparent_stepped(kg, shadow_sd, state, + skip_object, ray, &isect, shadow); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 64d240d779d..f75e9337bdb 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -223,7 +223,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect( SubsurfaceIntersection *ss_isect, ShaderData *sd, ShaderClosure *sc, - uint *lcg_state, + RNG *lcg_state, float disk_u, float disk_v, bool all) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 245832ae163..1ae624e06c5 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -157,6 +157,7 @@ CCL_NAMESPACE_BEGIN #define __INTERSECTION_REFINE__ #define __CLAMP_SAMPLE__ #define __PATCH_EVAL__ +#define __SHADOW_TRICKS__ #ifdef __KERNEL_SHADING__ # define __SVM__ @@ -212,6 +213,9 @@ CCL_NAMESPACE_BEGIN #ifdef __NO_TRANSPARENT__ # undef __TRANSPARENT_SHADOWS__ #endif +#ifdef __NO_SHADOW_TRICKS__ +#undef __SHADOW_TRICKS__ +#endif /* Random Numbers */ @@ -316,6 +320,8 @@ enum PathRayFlag { PATH_RAY_MIS_SKIP = 4096, PATH_RAY_DIFFUSE_ANCESTOR = 8192, PATH_RAY_SINGLE_PASS_DONE = 16384, + PATH_RAY_SHADOW_CATCHER = 32768, + PATH_RAY_SHADOW_CATCHER_ONLY = 65536, }; /* Closure Label */ @@ -445,6 +451,20 @@ typedef ccl_addr_space struct PathRadiance { float4 shadow; float mist; #endif + +#ifdef __SHADOW_TRICKS__ + /* Total light reachable across the path, ignoring shadow blocked queries. */ + float3 path_total; + /* Total light reachable across the path with shadow blocked queries + * applied here. + * + * Dividing this figure by path_total will give estimate of shadow pass. + */ + float3 path_total_shaded; + + /* Color of the background on which shadow is alpha-overed. */ + float3 shadow_color; +#endif } PathRadiance; typedef struct BsdfEval { @@ -460,6 +480,9 @@ typedef struct BsdfEval { float3 subsurface; float3 scatter; #endif +#ifdef __SHADOW_TRICKS__ + float3 sum_no_mis; +#endif } BsdfEval; /* Shader Flag */ @@ -805,13 +828,16 @@ enum ShaderDataObjectFlag { SD_OBJECT_INTERSECTS_VOLUME = (1 << 5), /* Has position for motion vertices. */ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6), + /* object is used to catch shadows */ + SD_OBJECT_SHADOW_CATCHER = (1 << 7), SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED | SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME | - SD_OBJECT_INTERSECTS_VOLUME) + SD_OBJECT_INTERSECTS_VOLUME | + SD_OBJECT_SHADOW_CATCHER) }; typedef ccl_addr_space struct ShaderData { @@ -930,6 +956,10 @@ typedef struct PathState { RNG rng_congruential; VolumeStack volume_stack[VOLUME_STACK_SIZE]; #endif + +#ifdef __SHADOW_TRICKS__ + int catcher_object; +#endif } PathState; /* Subsurface */ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index dcab138dc84..9c0878249d4 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -360,7 +360,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( ShaderData *sd, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng, + RNG *rng, bool probalistic_scatter) { VolumeShaderCoefficients coeff; @@ -469,7 +469,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( ShaderData *sd, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng) + RNG *rng) { float3 tp = *throughput; const float tp_eps = 1e-6f; /* todo: this is likely not the right value */ @@ -610,7 +610,7 @@ ccl_device_noinline VolumeIntegrateResult kernel_volume_integrate( Ray *ray, PathRadiance *L, ccl_addr_space float3 *throughput, - ccl_addr_space RNG *rng, + RNG *rng, bool heterogeneous) { shader_setup_from_volume(kg, sd, ray); diff --git a/intern/cycles/kernel/split/kernel_buffer_update.h b/intern/cycles/kernel/split/kernel_buffer_update.h index f36899b884a..859c221d976 100644 --- a/intern/cycles/kernel/split/kernel_buffer_update.h +++ b/intern/cycles/kernel/split/kernel_buffer_update.h @@ -87,7 +87,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global float *L_transparent = &kernel_split_state.L_transparent[ray_index]; - ccl_global uint *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global float *buffer = kernel_split_params.buffer; unsigned int work_index; @@ -111,7 +111,16 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride; if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) { - float3 L_sum = path_radiance_clamp_and_sum(kg, L); + float3 L_sum; +#ifdef __SHADOW_TRICKS__ + if(state->flag & PATH_RAY_SHADOW_CATCHER) { + L_sum = path_radiance_sum_shadowcatcher(kg, L, L_transparent); + } + else +#endif /* __SHADOW_TRICKS__ */ + { + L_sum = path_radiance_clamp_and_sum(kg, L); + } kernel_write_light_passes(kg, buffer, L, sample); #ifdef __KERNEL_DEBUG__ kernel_write_debug_passes(kg, buffer, state, debug_data, sample); @@ -120,7 +129,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, /* accumulate result in output buffer */ kernel_write_pass_float4(buffer, sample, L_rad); - path_rng_end(kg, rng_state, *rng); + path_rng_end(kg, rng_state, rng); ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE); } @@ -146,7 +155,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride; /* Initialize random numbers and ray. */ - kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, rng, ray); + kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, &rng, ray); if(ray->t != 0.0f) { /* Initialize throughput, L_transparent, Ray, PathState; @@ -155,7 +164,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, *throughput = make_float3(1.0f, 1.0f, 1.0f); *L_transparent = 0.0f; path_radiance_init(L, kernel_data.film.use_light_pass); - path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, rng, sample, ray); + path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, &rng, sample, ray); #ifdef __SUBSURFACE__ kernel_path_subsurface_init_indirect(&kernel_split_state.ss_rays[ray_index]); #endif @@ -170,12 +179,13 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg, float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f); /* Accumulate result in output buffer. */ kernel_write_pass_float4(buffer, sample, L_rad); - path_rng_end(kg, rng_state, *rng); + path_rng_end(kg, rng_state, rng); ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE); } } } + kernel_split_state.rng[ray_index] = rng; #ifndef __COMPUTE_DEVICE_GPU__ } diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h index 3d062cf0e2b..bdbf7387b95 100644 --- a/intern/cycles/kernel/split/kernel_direct_lighting.h +++ b/intern/cycles/kernel/split/kernel_direct_lighting.h @@ -79,15 +79,32 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, /* direct lighting */ #ifdef __EMISSION__ - if((kernel_data.integrator.use_direct_light && - (sd->flag & SD_BSDF_HAS_EVAL))) - { + RNG rng = kernel_split_state.rng[ray_index]; + bool flag = (kernel_data.integrator.use_direct_light && + (sd->flag & SD_BSDF_HAS_EVAL)); +# ifdef __SHADOW_TRICKS__ + if(flag && state->flag & PATH_RAY_SHADOW_CATCHER) { + flag = false; + ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index]; + float3 throughput = kernel_split_state.throughput[ray_index]; + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; + kernel_branched_path_surface_connect_light(kg, + &rng, + sd, + emission_sd, + state, + throughput, + 1.0f, + L, + 1); + } +# endif /* __SHADOW_TRICKS__ */ + if(flag) { /* Sample illumination from lights to find path contribution. */ - ccl_global RNG* rng = &kernel_split_state.rng[ray_index]; - float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); + float light_t = path_state_rng_1D(kg, &rng, state, PRNG_LIGHT); float light_u, light_v; - path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); - float terminate = path_state_rng_light_termination(kg, rng, state); + path_state_rng_2D(kg, &rng, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, &rng, state); LightSample ls; if(light_sample(kg, @@ -98,9 +115,9 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, &ls)) { Ray light_ray; -#ifdef __OBJECT_MOTION__ +# ifdef __OBJECT_MOTION__ light_ray.time = sd->time; -#endif +# endif BsdfEval L_light; bool is_lamp; @@ -117,6 +134,7 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg, } } } + kernel_split_state.rng[ray_index] = rng; #endif /* __EMISSION__ */ } diff --git a/intern/cycles/kernel/split/kernel_do_volume.h b/intern/cycles/kernel/split/kernel_do_volume.h index b1df45d6bb2..47d3c280831 100644 --- a/intern/cycles/kernel/split/kernel_do_volume.h +++ b/intern/cycles/kernel/split/kernel_do_volume.h @@ -50,7 +50,7 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global Intersection *isect = &kernel_split_state.isect[ray_index]; ShaderData *sd = &kernel_split_state.sd[ray_index]; ShaderData *sd_input = &kernel_split_state.sd_DL_shadow[ray_index]; @@ -69,15 +69,15 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( - kg, state, sd, &volume_ray, L, throughput, rng, heterogeneous); + kg, state, sd, &volume_ray, L, throughput, &rng, heterogeneous); # ifdef __VOLUME_SCATTER__ if(result == VOLUME_PATH_SCATTERED) { /* direct lighting */ - kernel_path_volume_connect_light(kg, rng, sd, sd_input, *throughput, state, L); + kernel_path_volume_connect_light(kg, &rng, sd, sd_input, *throughput, state, L); /* indirect light bounce */ - if(kernel_path_volume_bounce(kg, rng, sd, throughput, state, L, ray)) + if(kernel_path_volume_bounce(kg, &rng, sd, throughput, state, L, ray)) ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_REGENERATED); else ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_UPDATE_BUFFER); @@ -85,6 +85,7 @@ ccl_device void kernel_do_volume(KernelGlobals *kg) # endif } } + kernel_split_state.rng[ray_index] = rng; } #endif diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index 1834a791b91..9fc853a84bf 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -98,7 +98,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( unsigned int tile_y; unsigned int sample; - ccl_global RNG *rng = 0x0; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = 0x0; float3 throughput; @@ -110,7 +110,6 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( throughput = kernel_split_state.throughput[ray_index]; state = &kernel_split_state.path_state[ray_index]; - rng = &kernel_split_state.rng[ray_index]; work_index = kernel_split_state.work_array[ray_index]; sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample; @@ -121,6 +120,23 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( buffer += (kernel_split_params.offset + pixel_x + pixel_y * stride) * kernel_data.film.pass_stride; +#ifdef __SHADOW_TRICKS__ + if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) { + if (state->flag & PATH_RAY_CAMERA) { + state->flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY); + state->catcher_object = sd->object; + if(!kernel_data.background.transparent) { + PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; + ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; + L->shadow_color = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray); + } + } + } + else { + state->flag &= ~PATH_RAY_SHADOW_CATCHER_ONLY; + } +#endif /* __SHADOW_TRICKS__ */ + /* holdout */ #ifdef __HOLDOUT__ if(((sd->flag & SD_HOLDOUT) || @@ -194,7 +210,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { if(probability != 1.0f) { - float terminate = path_state_rng_1D_for_decision(kg, rng, state, PRNG_TERMINATE); + float terminate = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_TERMINATE); if(terminate >= probability) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); enqueue_flag = 1; @@ -214,7 +230,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( { /* todo: solve correlation */ float bsdf_u, bsdf_v; - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + path_state_rng_2D(kg, &rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); float ao_factor = kernel_data.background.ao_factor; float3 ao_N; @@ -243,6 +259,8 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( } } #endif /* __AO__ */ + kernel_split_state.rng[ray_index] = rng; + #ifndef __COMPUTE_DEVICE_GPU__ } diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h index 100f5996f83..8192528622e 100644 --- a/intern/cycles/kernel/split/kernel_indirect_background.h +++ b/intern/cycles/kernel/split/kernel_indirect_background.h @@ -70,7 +70,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg) #ifdef __BACKGROUND__ /* sample background shader */ float3 L_background = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray); - path_radiance_accum_background(L, (*throughput), L_background, state->bounce); + path_radiance_accum_background(L, state, (*throughput), L_background); #endif ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); } diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h index 056fb1d8c08..1bebc16e25b 100644 --- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h +++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h @@ -117,6 +117,9 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, shadow, state->bounce); } + else { + path_radiance_accum_total_ao(L, _throughput, kernel_split_state.ao_bsdf[ray_index]); + } REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO); } @@ -124,8 +127,8 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, float3 shadow = kernel_split_state.light_ray[ray_index].P; // TODO(mai): investigate correctness here char update_path_radiance = (char)kernel_split_state.light_ray[ray_index].t; + BsdfEval L_light = kernel_split_state.bsdf_eval[ray_index]; if(update_path_radiance) { - BsdfEval L_light = kernel_split_state.bsdf_eval[ray_index]; path_radiance_accum_light(L, _throughput, &L_light, @@ -134,6 +137,9 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, state->bounce, kernel_split_state.is_lamp[ray_index]); } + else { + path_radiance_accum_total_light(L, _throughput, &L_light); + } REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL); } } @@ -141,15 +147,16 @@ ccl_device void kernel_next_iteration_setup(KernelGlobals *kg, if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; state = &kernel_split_state.path_state[ray_index]; L = &kernel_split_state.path_radiance[ray_index]; /* Compute direct lighting and next bounce. */ - if(!kernel_path_surface_bounce(kg, rng, &kernel_split_state.sd[ray_index], throughput, state, L, ray)) { + if(!kernel_path_surface_bounce(kg, &rng, &kernel_split_state.sd[ray_index], throughput, state, L, ray)) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); enqueue_flag = 1; } + kernel_split_state.rng[ray_index] = rng; } #ifndef __COMPUTE_DEVICE_GPU__ diff --git a/intern/cycles/kernel/split/kernel_path_init.h b/intern/cycles/kernel/split/kernel_path_init.h index f879fca5009..a7ecde7c80d 100644 --- a/intern/cycles/kernel/split/kernel_path_init.h +++ b/intern/cycles/kernel/split/kernel_path_init.h @@ -60,12 +60,14 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { ccl_global float *buffer = kernel_split_params.buffer; buffer += (kernel_split_params.offset + pixel_x + pixel_y * kernel_split_params.stride) * kernel_data.film.pass_stride; + RNG rng = kernel_split_state.rng[ray_index]; + /* Initialize random numbers and ray. */ kernel_path_trace_setup(kg, rng_state, my_sample, pixel_x, pixel_y, - &kernel_split_state.rng[ray_index], + &rng, &kernel_split_state.ray[ray_index]); if(kernel_split_state.ray[ray_index].t != 0.0f) { @@ -78,7 +80,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { path_state_init(kg, &kernel_split_state.sd_DL_shadow[ray_index], &kernel_split_state.path_state[ray_index], - &kernel_split_state.rng[ray_index], + &rng, my_sample, &kernel_split_state.ray[ray_index]); #ifdef __SUBSURFACE__ @@ -97,6 +99,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg) { path_rng_end(kg, rng_state, kernel_split_state.rng[ray_index]); ASSIGN_RAY_STATE(kernel_split_state.ray_state, ray_index, RAY_TO_REGENERATE); } + kernel_split_state.rng[ray_index] = rng; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h index 66f549f59b7..684760eedee 100644 --- a/intern/cycles/kernel/split/kernel_scene_intersect.h +++ b/intern/cycles/kernel/split/kernel_scene_intersect.h @@ -72,7 +72,7 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg) } extmax = kernel_data.curve.maximum_width; - lcg_state = lcg_state_init(&rng, &state, 0x51633e2d); + lcg_state = lcg_state_init(&rng, state.rng_offset, state.sample, 0x51633e2d); } if(state.bounce > kernel_data.integrator.ao_bounces) { diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index b739f86338c..0f1696e34a0 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -54,7 +54,7 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg, /* Continue on with shader evaluation. */ if((ray_index != QUEUE_EMPTY_SLOT) && IS_STATE(kernel_split_state.ray_state, ray_index, RAY_ACTIVE)) { Intersection isect = kernel_split_state.isect[ray_index]; - ccl_global uint *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; Ray ray = kernel_split_state.ray[ray_index]; @@ -62,8 +62,9 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg, &kernel_split_state.sd[ray_index], &isect, &ray); - float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, &kernel_split_state.sd[ray_index], rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + float rbsdf = path_state_rng_1D_for_decision(kg, &rng, state, PRNG_BSDF); + shader_eval_surface(kg, &kernel_split_state.sd[ray_index], &rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + kernel_split_state.rng[ray_index] = rng; } } diff --git a/intern/cycles/kernel/split/kernel_subsurface_scatter.h b/intern/cycles/kernel/split/kernel_subsurface_scatter.h index 4eaa7f56332..0b4d50c70ee 100644 --- a/intern/cycles/kernel/split/kernel_subsurface_scatter.h +++ b/intern/cycles/kernel/split/kernel_subsurface_scatter.h @@ -55,7 +55,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, ccl_global char *ray_state = kernel_split_state.ray_state; ccl_global PathState *state = &kernel_split_state.path_state[ray_index]; PathRadiance *L = &kernel_split_state.path_radiance[ray_index]; - ccl_global RNG *rng = &kernel_split_state.rng[ray_index]; + RNG rng = kernel_split_state.rng[ray_index]; ccl_global Ray *ray = &kernel_split_state.ray[ray_index]; ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index]; ccl_global SubsurfaceIndirectRays *ss_indirect = &kernel_split_state.ss_rays[ray_index]; @@ -69,7 +69,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, emission_sd, L, state, - rng, + &rng, ray, throughput, ss_indirect)) { @@ -77,6 +77,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg, enqueue_flag = 1; } } + kernel_split_state.rng[ray_index] = rng; } #ifndef __COMPUTE_DEVICE_GPU__ diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h index a8b3604a8a7..9e826c8c23f 100644 --- a/intern/cycles/kernel/svm/svm_voxel.h +++ b/intern/cycles/kernel/svm/svm_voxel.h @@ -46,7 +46,7 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg, # if defined(__KERNEL_CUDA__) # if __CUDA_ARCH__ >= 300 CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id); - if(id < 2048) /* TODO(dingto): Make this a variable */ + if(id < TEX_START_HALF4_CUDA_KEPLER) r = kernel_tex_image_interp_3d_float4(tex, co.x, co.y, co.z); else { float f = kernel_tex_image_interp_3d_float(tex, co.x, co.y, co.z); diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index f6c83fb5c7e..0cfd08090c2 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -17,6 +17,7 @@ #include "attribute.h" #include "graph.h" #include "nodes.h" +#include "scene.h" #include "shader.h" #include "constant_fold.h" @@ -195,6 +196,7 @@ bool ShaderNode::equals(const ShaderNode& other) ShaderGraph::ShaderGraph() { finalized = false; + simplified = false; num_node_ids = 0; add(new OutputNode()); } @@ -207,6 +209,8 @@ ShaderGraph::~ShaderGraph() ShaderNode *ShaderGraph::add(ShaderNode *node) { assert(!finalized); + simplified = false; + node->id = num_node_ids++; nodes.push_back(node); return node; @@ -241,6 +245,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) { assert(!finalized); assert(from && to); + simplified = false; if(to->link) { fprintf(stderr, "Cycles shader graph connect: input already connected.\n"); @@ -273,6 +278,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) void ShaderGraph::disconnect(ShaderOutput *from) { assert(!finalized); + simplified = false; foreach(ShaderInput *sock, from->links) { sock->link = NULL; @@ -285,6 +291,7 @@ void ShaderGraph::disconnect(ShaderInput *to) { assert(!finalized); assert(to->link); + simplified = false; ShaderOutput *from = to->link; @@ -294,6 +301,8 @@ void ShaderGraph::disconnect(ShaderInput *to) void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to) { + simplified = false; + /* Copy because disconnect modifies this list */ vector<ShaderInput*> outputs = from->links; @@ -310,9 +319,19 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to) } } +void ShaderGraph::simplify(Scene *scene) +{ + if(!simplified) { + default_inputs(scene->shader_manager->use_osl()); + clean(scene); + refine_bump_nodes(); + + simplified = true; + } +} + void ShaderGraph::finalize(Scene *scene, bool do_bump, - bool do_osl, bool do_simplify, bool bump_in_object_space) { @@ -322,9 +341,7 @@ void ShaderGraph::finalize(Scene *scene, * modified afterwards. */ if(!finalized) { - default_inputs(do_osl); - clean(scene); - refine_bump_nodes(); + simplify(scene); if(do_bump) bump_from_displacement(bump_in_object_space); diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 06524d3fa13..d22193d4e51 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -240,6 +240,7 @@ public: list<ShaderNode*> nodes; size_t num_node_ids; bool finalized; + bool simplified; ShaderGraph(); ~ShaderGraph(); @@ -255,9 +256,9 @@ public: void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); void remove_proxy_nodes(); + void simplify(Scene *scene); void finalize(Scene *scene, bool do_bump = false, - bool do_osl = false, bool do_simplify = false, bool bump_in_object_space = false); diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 8342f376836..a3a8c6d68e4 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -49,6 +49,8 @@ NODE_DEFINE(Object) SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); + SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); + return type; } @@ -597,6 +599,12 @@ void ObjectManager::device_update_flags(Device *device, else { object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME; } + if(object->is_shadow_catcher) { + object_flag[object_index] |= SD_OBJECT_SHADOW_CATCHER; + } + else { + object_flag[object_index] &= ~SD_OBJECT_SHADOW_CATCHER; + } if(bounds_valid) { foreach(Object *volume_object, volume_objects) { diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 3495849d149..dabe0f71662 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -53,6 +53,7 @@ public: bool use_motion; bool hide_on_missing_motion; bool use_holdout; + bool is_shadow_catcher; float3 dupli_generated; float2 dupli_uv; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 67b68e63cb2..68bd8d96bf9 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -1096,12 +1096,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) /* finalize */ shader->graph->finalize(scene, false, - true, shader->has_integrator_dependency); if(shader->graph_bump) { shader->graph_bump->finalize(scene, true, - true, shader->has_integrator_dependency, shader->displacement_method == DISPLACE_BOTH); } diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index e7050f9ef37..bd664b35e19 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -637,6 +637,9 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_patch_evaluation = true; } #endif + if(object->is_shadow_catcher) { + requested_features.use_shadow_tricks = true; + } } BakeManager *bake_manager = scene->bake_manager; diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 955b892f4c3..bbf14c24b56 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -813,7 +813,6 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL); shader->graph->finalize(scene, false, - false, shader->has_integrator_dependency); } @@ -821,7 +820,6 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL); shader->graph_bump->finalize(scene, true, - false, shader->has_integrator_dependency, shader->displacement_method == DISPLACE_BOTH); } diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 2af0e56325f..84a5c800357 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -774,6 +774,7 @@ template<size_t index_0, size_t index_1, size_t index_2, size_t index_3> __force return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(index_3, index_2, index_1, index_0))); } +#if defined(__KERNEL_SSE3__) template<> __forceinline const float4 shuffle<0, 0, 2, 2>(const float4& b) { return _mm_moveldup_ps(b); @@ -783,6 +784,7 @@ template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4& b) { return _mm_movehdup_ps(b); } +#endif template<> __forceinline const float4 shuffle<0, 1, 0, 1>(const float4& b) { diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index ff1922af4f3..6887063eae9 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -908,6 +908,11 @@ extern int GHOST_UseNativePixels(void); extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle); /** + * Returns the suggested DPI for this window. + */ +extern GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle); + +/** * Enable IME attached to the given window, i.e. allows user-input * events to be dispatched to the IME. * \param windowhandle Window handle of the caller diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 688ebecf557..4a4d6be5ced 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -332,6 +332,12 @@ public: virtual float getNativePixelSize(void) = 0; + /** + * Returns the recommended DPI for this window. + * \return The recommended DPI for this window. + */ + virtual GHOST_TUns16 getDPIHint() = 0; + #ifdef WITH_INPUT_IME /** * Enable IME attached to the given window, i.e. allows user-input diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 9ee4599a4a6..02b5063e515 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -189,6 +189,7 @@ typedef enum { GHOST_kEventWindowUpdate, GHOST_kEventWindowSize, GHOST_kEventWindowMove, + GHOST_kEventWindowDPIHintChanged, GHOST_kEventDraggingEntered, GHOST_kEventDraggingUpdated, diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 41bc735e1e2..ce653188760 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -914,6 +914,12 @@ float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle) return 1.0f; } +GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + return window->getDPIHint(); +} + #ifdef WITH_INPUT_IME void GHOST_BeginIME(GHOST_WindowHandle windowhandle, diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 7d55a973f91..240d7ccd2fe 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -111,6 +111,11 @@ #define VK_MEDIA_PLAY_PAUSE 0xB3 #endif // VK_MEDIA_PLAY_PAUSE +// Window message newer than Windows 7 +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif // WM_DPICHANGED + /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives * the message, but PeekMessage doesn't pick those messages for @@ -152,6 +157,27 @@ static void initRawInput() #undef DEVICE_COUNT } +#ifndef DPI_ENUMS_DECLARED +typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#define USER_DEFAULT_SCREEN_DPI 96 + +#define DPI_ENUMS_DECLARED +#endif +typedef HRESULT(API * GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); +typedef BOOL(API * GHOST_WIN32_EnableNonClientDpiScaling)(HWND); + GHOST_SystemWin32::GHOST_SystemWin32() : m_hasPerformanceCounter(false), m_freq(0), m_start(0) { @@ -161,6 +187,18 @@ GHOST_SystemWin32::GHOST_SystemWin32() m_consoleStatus = 1; + // Tell Windows we are per monitor DPI aware. This disables the default + // blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. + HMODULE m_shcore = ::LoadLibrary("Shcore.dll"); + if (m_shcore) { + GHOST_WIN32_SetProcessDpiAwareness fpSetProcessDpiAwareness = + (GHOST_WIN32_SetProcessDpiAwareness) ::GetProcAddress(m_shcore, "SetProcessDpiAwareness"); + + if (fpSetProcessDpiAwareness) { + fpSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + } + } + // Check if current keyboard layout uses AltGr and save keylayout ID for // specialized handling if keys like VK_OEM_*. I.e. french keylayout // generates VK_OEM_8 for their exclamation key (key left of right shift) @@ -922,6 +960,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized"); if (hwnd) { + if(msg == WM_NCCREATE) { + // Tell Windows to automatically handle scaling of non-client areas + // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 + HMODULE m_user32 = ::LoadLibrary("User32.dll"); + if (m_user32) { + GHOST_WIN32_EnableNonClientDpiScaling fpEnableNonClientDpiScaling = + (GHOST_WIN32_EnableNonClientDpiScaling) ::GetProcAddress(m_user32, "EnableNonClientDpiScaling"); + + if (fpEnableNonClientDpiScaling) { + fpEnableNonClientDpiScaling(hwnd); + } + } + } + GHOST_WindowWin32 *window = (GHOST_WindowWin32 *)::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (window) { switch (msg) { @@ -1294,6 +1346,32 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; + case WM_DPICHANGED: + /* The WM_DPICHANGED message is sent when the effective dots per inch (dpi) for a window has changed. + * The DPI is the scale factor for a window. There are multiple events that can cause the DPI to + * change such as when the window is moved to a monitor with a different DPI. + */ + { + WORD newYAxisDPI = HIWORD(wParam); + WORD newXAxisDPI = LOWORD(wParam); + // The suggested new size and position of the window. + RECT* const suggestedWindowRect = (RECT*)lParam; + + // Push DPI change event first + system->pushEvent(processWindowEvent(GHOST_kEventWindowDPIHintChanged, window)); + system->dispatchEvents(); + eventHandled = true; + + // Then move and resize window + SetWindowPos(hwnd, + NULL, + suggestedWindowRect->left, + suggestedWindowRect->top, + suggestedWindowRect->right - suggestedWindowRect->left, + suggestedWindowRect->bottom - suggestedWindowRect->top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + break; //////////////////////////////////////////////////////////////////////// // Window events, ignored //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index d778628ea37..2798bdf72f3 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -295,6 +295,15 @@ public: return 1.0f; } + /** + * Returns the recommended DPI for this window. + * \return The recommended DPI for this window. + */ + virtual inline GHOST_TUns16 getDPIHint() + { + return 96; + } + #ifdef WITH_INPUT_IME virtual void beginIME(GHOST_TInt32 x, GHOST_TInt32 y, diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp index 1335c38d977..aeb6188daef 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.cpp +++ b/intern/ghost/intern/GHOST_WindowSDL.cpp @@ -563,3 +563,19 @@ GHOST_WindowSDL::setWindowCursorVisibility(bool visible) SDL_ShowCursor(visible); return GHOST_kSuccess; } + +GHOST_TUns16 +GHOST_WindowSDL::getDPIHint() +{ + int displayIndex = SDL_GetWindowDisplayIndex(m_sdl_win); + if (displayIndex < 0) { + return 96; + } + + float ddpi; + if (SDL_GetDisplayDPI(displayIndex, &ddpi, NULL, NULL) != 0) { + return 96; + } + + return (int)ddpi; +} diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h index 5f658e8ad01..96104ec28b4 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.h +++ b/intern/ghost/intern/GHOST_WindowSDL.h @@ -168,6 +168,8 @@ protected: GHOST_TSuccess beginFullScreen() const { return GHOST_kFailure; } GHOST_TSuccess endFullScreen() const { return GHOST_kFailure; } + + GHOST_TUns16 getDPIHint(); }; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 58aa0b87045..2c82e3a3f71 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -92,6 +92,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_tablet(0), m_maxPressure(0), m_normal_state(GHOST_kWindowStateNormal), + m_user32(NULL), m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { @@ -905,6 +906,23 @@ void GHOST_WindowWin32::bringTabletContextToFront() } } +GHOST_TUns16 GHOST_WindowWin32::getDPIHint() +{ + if (!m_user32) { + m_user32 = ::LoadLibrary("user32.dll"); + } + + if (m_user32) { + GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow) ::GetProcAddress(m_user32, "GetDpiForWindow"); + + if (fpGetDpiForWindow) { + return fpGetDpiForWindow(this->m_hWnd); + } + } + + return USER_DEFAULT_SCREEN_DPI; +} + /** Reverse the bits in a GHOST_TUns8 */ static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) { diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index a1cf58c9ceb..75a33951ff4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -58,6 +58,12 @@ typedef BOOL (API * GHOST_WIN32_WTClose)(HCTX); typedef BOOL (API * GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID); typedef BOOL (API * GHOST_WIN32_WTOverlap)(HCTX, BOOL); +// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions +typedef UINT(API * GHOST_WIN32_GetDpiForWindow)(HWND); +#ifndef USER_DEFAULT_SCREEN_DPI +#define USER_DEFAULT_SCREEN_DPI 96 +#endif // USER_DEFAULT_SCREEN_DPI + /** * GHOST window on M$ Windows OSs. * \author Maarten Gribnau @@ -251,6 +257,8 @@ public: GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;} + GHOST_TUns16 getDPIHint() override; + /** if the window currently resizing */ bool m_inLiveResize; @@ -351,6 +359,9 @@ private: GHOST_TWindowState m_normal_state; + /** user32 dll handle*/ + HMODULE m_user32; + /** Hwnd to parent window */ GHOST_TEmbedderWindowID m_parentWindowHwnd; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 8cee785cdf6..f39f4f52289 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -56,6 +56,9 @@ # include <X11/extensions/XInput2.h> #endif +//For DPI value +#include <X11/Xresource.h> + #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) # include <strings.h> #endif @@ -68,6 +71,7 @@ #include <algorithm> #include <string> +#include <math.h> /* For obscure full screen mode stuff * lifted verbatim from blut. */ @@ -1661,3 +1665,44 @@ endFullScreen() const return GHOST_kSuccess; } + +GHOST_TUns16 +GHOST_WindowX11:: +getDPIHint() +{ + /* Try to read DPI setting set using xrdb */ + char* resMan = XResourceManagerString(m_display); + if (resMan) { + XrmDatabase xrdb = XrmGetStringDatabase(resMan); + if (xrdb) { + char* type = NULL; + XrmValue val; + + int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val); + if (success && type) { + if (strcmp(type, "String") == 0) { + return atoi((char*)val.addr); + } + } + } + } + + /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */ + XWindowAttributes attr; + if (!XGetWindowAttributes(m_display, m_window, &attr)) { + /* Failed to get window attributes, return X11 default DPI */ + return 96; + } + + Screen* screen = attr.screen; + int pixelWidth = WidthOfScreen(screen); + int pixelHeight = HeightOfScreen(screen); + int mmWidth = WidthMMOfScreen(screen); + int mmHeight = HeightMMOfScreen(screen); + + double pixelDiagonal = sqrt((pixelWidth * pixelWidth) + (pixelHeight * pixelHeight)); + double mmDiagonal = sqrt((mmWidth * mmWidth) + (mmHeight * mmHeight)); + float inchDiagonal = mmDiagonal * 0.039f; + int dpi = pixelDiagonal / inchDiagonal; + return dpi; +} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 9380aa9d631..5c54c1e8162 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -235,6 +235,8 @@ public: GHOST_TSuccess endFullScreen() const; + GHOST_TUns16 getDPIHint(); + protected: /** * \param type The type of rendering context create. |