/* * Copyright 2018 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "render/coverage.h" #include "kernel/kernel_compat_cpu.h" #include "kernel/split/kernel_split_data.h" #include "kernel/kernel_globals.h" #include "kernel/kernel_id_passes.h" #include "kernel/kernel_types.h" #include "util/util_map.h" #include "util/util_vector.h" CCL_NAMESPACE_BEGIN static bool crypomatte_comp(const pair& i, const pair j) { return i.first > j.first; } void Coverage::finalize() { int pass_offset = 0; if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { finalize_buffer(coverage_object, pass_offset); pass_offset += kernel_data.film.cryptomatte_depth * 4; } if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { finalize_buffer(coverage_material, pass_offset); pass_offset += kernel_data.film.cryptomatte_depth * 4; } if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { finalize_buffer(coverage_asset, pass_offset); } } void Coverage::init_path_trace() { kg->coverage_object = kg->coverage_material = kg->coverage_asset = NULL; if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { coverage_object.clear(); coverage_object.resize(tile.w * tile.h); } if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { coverage_material.clear(); coverage_material.resize(tile.w * tile.h); } if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { coverage_asset.clear(); coverage_asset.resize(tile.w * tile.h); } } } void Coverage::init_pixel(int x, int y) { if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { const int pixel_index = tile.w * (y - tile.y) + x - tile.x; if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { kg->coverage_object = &coverage_object[pixel_index]; } if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { kg->coverage_material = &coverage_material[pixel_index]; } if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { kg->coverage_asset = &coverage_asset[pixel_index]; } } } void Coverage::finalize_buffer(vector & coverage, const int pass_offset) { if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { flatten_buffer(coverage, pass_offset); } else { sort_buffer(pass_offset); } } void Coverage::flatten_buffer(vector &coverage, const int pass_offset) { /* Sort the coverage map and write it to the output */ int pixel_index = 0; int pass_stride = tile.buffers->params.get_passes_size(); for(int y = 0; y < tile.h; ++y) { for(int x = 0; x < tile.w; ++x) { const CoverageMap& pixel = coverage[pixel_index]; if(!pixel.empty()) { /* buffer offset */ int index = x + y * tile.stride; float *buffer = (float*)tile.buffer + index*pass_stride; /* sort the cryptomatte pixel */ vector > sorted_pixel; for(CoverageMap::const_iterator it = pixel.begin(); it != pixel.end(); ++it) { sorted_pixel.push_back(std::make_pair(it->second, it->first)); } sort(sorted_pixel.begin(), sorted_pixel.end(), crypomatte_comp); int num_slots = 2 * (kernel_data.film.cryptomatte_depth); if(sorted_pixel.size() > num_slots) { float leftover = 0.0f; for(vector >::iterator it = sorted_pixel.begin()+num_slots; it != sorted_pixel.end(); ++it) { leftover += it->first; } sorted_pixel[num_slots-1].first += leftover; } int limit = min(num_slots, sorted_pixel.size()); for(int i = 0; i < limit; ++i) { kernel_write_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth), sorted_pixel[i].second, sorted_pixel[i].first); } } ++pixel_index; } } } void Coverage::sort_buffer(const int pass_offset) { /* Sort the coverage map and write it to the output */ int pass_stride = tile.buffers->params.get_passes_size(); for(int y = 0; y < tile.h; ++y) { for(int x = 0; x < tile.w; ++x) { /* buffer offset */ int index = x + y*tile.stride; float *buffer = (float*)tile.buffer + index*pass_stride; kernel_sort_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth)); } } } CCL_NAMESPACE_END