diff options
Diffstat (limited to 'intern/cycles/render/light.cpp')
-rw-r--r-- | intern/cycles/render/light.cpp | 112 |
1 files changed, 77 insertions, 35 deletions
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 1f006637e67..56bec4053d5 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ #include "background.h" @@ -26,6 +26,7 @@ #include "util_foreach.h" #include "util_progress.h" +#include "util_logging.h" CCL_NAMESPACE_BEGIN @@ -82,6 +83,8 @@ static void shade_background_pixels(Device *device, DeviceScene *dscene, int res device->mem_free(d_input); device->mem_free(d_output); + d_input.clear(); + float4 *d_output_data = reinterpret_cast<float4*>(d_output.data_pointer); pixels.resize(width*height); @@ -125,6 +128,7 @@ Light::Light() shader = 0; samples = 1; + max_bounces = 1024; } void Light::tag_update(Scene *scene) @@ -374,6 +378,45 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen } } +static void background_cdf(int start, + int end, + int res, + int cdf_count, + const vector<float3> *pixels, + float2 *cond_cdf) +{ + /* Conditional CDFs (rows, U direction). */ + for(int i = start; i < end; i++) { + float sin_theta = sinf(M_PI_F * (i + 0.5f) / res); + float3 env_color = (*pixels)[i * res]; + float ave_luminamce = average(env_color); + + cond_cdf[i * cdf_count].x = ave_luminamce * sin_theta; + cond_cdf[i * cdf_count].y = 0.0f; + + for(int j = 1; j < res; j++) { + env_color = (*pixels)[i * res + j]; + ave_luminamce = average(env_color); + + cond_cdf[i * cdf_count + j].x = ave_luminamce * sin_theta; + cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res; + } + + float cdf_total = cond_cdf[i * cdf_count + res - 1].y + cond_cdf[i * cdf_count + res - 1].x / res; + float cdf_total_inv = 1.0f / cdf_total; + + /* stuff the total into the brightness value for the last entry, because + * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */ + cond_cdf[i * cdf_count + res].x = cdf_total; + + if(cdf_total > 0.0f) + for(int j = 1; j < res; j++) + cond_cdf[i * cdf_count + j].y *= cdf_total_inv; + + cond_cdf[i * cdf_count + res].y = 1.0f; + } +} + void LightManager::device_update_background(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { KernelIntegrator *kintegrator = &dscene->data.integrator; @@ -414,34 +457,28 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene, float2 *marg_cdf = dscene->light_background_marginal_cdf.resize(cdf_count); float2 *cond_cdf = dscene->light_background_conditional_cdf.resize(cdf_count * cdf_count); - /* conditional CDFs (rows, U direction) */ - for(int i = 0; i < res; i++) { - float sin_theta = sinf(M_PI_F * (i + 0.5f) / res); - float3 env_color = pixels[i * res]; - float ave_luminamce = average(env_color); - - cond_cdf[i * cdf_count].x = ave_luminamce * sin_theta; - cond_cdf[i * cdf_count].y = 0.0f; - - for(int j = 1; j < res; j++) { - env_color = pixels[i * res + j]; - ave_luminamce = average(env_color); - - cond_cdf[i * cdf_count + j].x = ave_luminamce * sin_theta; - cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res; + double time_start = time_dt(); + if(res < 512) { + /* Small enough resolution, faster to do single-threaded. */ + background_cdf(0, res, res, cdf_count, &pixels, cond_cdf); + } + else { + /* Threaded evaluation for large resolution. */ + const int num_blocks = TaskScheduler::num_threads(); + const int chunk_size = res / num_blocks; + TaskPool pool; + for(int i = 0; i < num_blocks; ++i) { + const int current_chunk_size = + (i != num_blocks - 1) ? chunk_size + : (res - i * chunk_size); + pool.push(function_bind(&background_cdf, + i, i + current_chunk_size, + res, + cdf_count, + &pixels, + cond_cdf)); } - - float cdf_total = cond_cdf[i * cdf_count + res - 1].y + cond_cdf[i * cdf_count + res - 1].x / res; - - /* stuff the total into the brightness value for the last entry, because - * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */ - cond_cdf[i * cdf_count + res].x = cdf_total; - - if(cdf_total > 0.0f) - for(int j = 1; j < res; j++) - cond_cdf[i * cdf_count + j].y /= cdf_total; - - cond_cdf[i * cdf_count + res].y = 1.0f; + pool.wait_work(); } /* marginal CDFs (column, V direction, sum of rows) */ @@ -462,6 +499,8 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene, marg_cdf[res].y = 1.0f; + VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n"; + /* update device */ device->tex_alloc("__light_background_marginal_cdf", dscene->light_background_marginal_cdf); device->tex_alloc("__light_background_conditional_cdf", dscene->light_background_conditional_cdf); @@ -489,6 +528,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce float3 co = light->co; int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader); float samples = __int_as_float(light->samples); + float max_bounces = __int_as_float(light->max_bounces); if(!light->cast_shadow) shader_id &= ~SHADER_CAST_SHADOW; @@ -523,6 +563,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f); light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f); + light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); } else if(light->type == LIGHT_DISTANT) { shader_id &= ~SHADER_AREA_LIGHT; @@ -533,9 +574,8 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce float area = M_PI_F*radius*radius; float invarea = (area > 0.0f)? 1.0f/area: 1.0f; float3 dir = light->dir; - - if(len(dir) > 0.0f) - dir = normalize(dir); + + dir = safe_normalize(dir); if(light->use_mis && area > 0.0f) shader_id |= SHADER_USE_MIS; @@ -544,6 +584,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea); light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f); + light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); } else if(light->type == LIGHT_BACKGROUND) { uint visibility = scene->background->visibility; @@ -572,6 +613,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f); + light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); } else if(light->type == LIGHT_AREA) { float3 axisu = light->axisu*(light->sizeu*light->size); @@ -580,8 +622,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce float invarea = (area > 0.0f)? 1.0f/area: 1.0f; float3 dir = light->dir; - if(len(dir) > 0.0f) - dir = normalize(dir); + dir = safe_normalize(dir); if(light->use_mis && area > 0.0f) shader_id |= SHADER_USE_MIS; @@ -590,6 +631,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z); light_data[i*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z); light_data[i*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z); + light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); } else if(light->type == LIGHT_SPOT) { shader_id &= ~SHADER_AREA_LIGHT; @@ -600,8 +642,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce float spot_smooth = (1.0f - spot_angle)*light->spot_smooth; float3 dir = light->dir; - if(len(dir) > 0.0f) - dir = normalize(dir); + dir = safe_normalize(dir); if(light->use_mis && radius > 0.0f) shader_id |= SHADER_USE_MIS; @@ -610,6 +651,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle); light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z); light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f); + light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); } } |