diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index a50da3634f3..95a6e302cc5 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1345,8 +1345,9 @@ class CyclesPreferences(bpy.types.AddonPreferences): cuda_devices = [] opencl_devices = [] + cpu_devices = [] for device in device_list: - if not device[1] in {'CUDA', 'OPENCL'}: + if not device[1] in {'CUDA', 'OPENCL', 'CPU'}: continue entry = None @@ -1355,18 +1356,28 @@ class CyclesPreferences(bpy.types.AddonPreferences): if dev.id == device[2] and dev.type == device[1]: entry = dev break - # Create new entry if no existing one was found if not entry: + # Create new entry if no existing one was found entry = self.devices.add() entry.id = device[2] entry.name = device[0] entry.type = device[1] + entry.use = entry.type != 'CPU' + elif entry.name != device[0]: + # Update name in case it changed + entry.name = device[0] # Sort entries into lists if entry.type == 'CUDA': cuda_devices.append(entry) elif entry.type == 'OPENCL': opencl_devices.append(entry) + else: + cpu_devices.append(entry) + + cuda_devices.extend(cpu_devices) + opencl_devices.extend(cpu_devices) + return cuda_devices, opencl_devices diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 33b80b5695a..9c8855d0165 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -405,7 +405,12 @@ class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel): sub.prop(rd, "tile_x", text="X") sub.prop(rd, "tile_y", text="Y") - sub.prop(cscene, "use_progressive_refine") + subsub = sub.column() + subsub.active = not rd.use_save_buffers + for rl in rd.layers: + if rl.cycles.use_denoising: + subsub.active = False + subsub.prop(cscene, "use_progressive_refine") col = split.column() @@ -595,7 +600,6 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): cscene = context.scene.cycles layout = self.layout - layout.active = not cscene.use_progressive_refine layout.prop(crl, "use_denoising", text="") def draw(self, context): @@ -607,7 +611,7 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): rl = rd.layers.active crl = rl.cycles - layout.active = crl.use_denoising and not cscene.use_progressive_refine + layout.active = crl.use_denoising split = layout.split() diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 75cc06ecd82..cac662d837e 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -311,11 +311,10 @@ static void end_render_result(BL::RenderEngine& b_engine, void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_update_only, bool highlight) { - BufferParams& params = rtile.buffers->params; - int x = params.full_x - session->tile_manager.params.full_x; - int y = params.full_y - session->tile_manager.params.full_y; - int w = params.width; - int h = params.height; + int x = rtile.x - session->tile_manager.params.full_x; + int y = rtile.y - session->tile_manager.params.full_y; + int w = rtile.w; + int h = rtile.h; /* get render result */ BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str()); @@ -407,7 +406,7 @@ void BlenderSession::render() buffer_params.passes = passes; PointerRNA crl = RNA_pointer_get(&b_layer_iter->ptr, "cycles"); - bool use_denoising = !session_params.progressive_refine && get_boolean(crl, "use_denoising"); + bool use_denoising = get_boolean(crl, "use_denoising"); buffer_params.denoising_data_pass = use_denoising; session->tile_manager.schedule_denoising = use_denoising; session->params.use_denoising = use_denoising; @@ -665,10 +664,9 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr, if(!buffers->copy_from_device()) return; - BufferParams& params = buffers->params; float exposure = scene->film->exposure; - vector pixels(params.width*params.height*4); + vector pixels(rtile.w*rtile.h*4); /* Adjust absolute sample number to the range. */ int sample = rtile.sample; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index c1783045f66..3636c28ee99 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -558,8 +558,7 @@ array BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, PointerRNA crp = RNA_pointer_get(&b_srlay.ptr, "cycles"); if(get_boolean(crp, "denoising_store_passes") && - get_boolean(crp, "use_denoising") && - !session_params.progressive_refine) { + get_boolean(crp, "use_denoising")) { b_engine.add_pass("Denoising Normal", 3, "XYZ", b_srlay.name().c_str()); b_engine.add_pass("Denoising Normal Variance", 3, "XYZ", b_srlay.name().c_str()); b_engine.add_pass("Denoising Albedo", 3, "RGB", b_srlay.name().c_str()); @@ -660,6 +659,16 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, /* feature set */ params.experimental = (get_enum(cscene, "feature_set") != 0); + /* threads */ + BL::RenderSettings b_r = b_scene.render(); + if(b_r.threads_mode() == BL::RenderSettings::threads_mode_FIXED) + params.threads = b_r.threads(); + else + params.threads = 0; + + /* Background */ + params.background = background; + /* device type */ vector& devices = Device::available_devices(); @@ -688,12 +697,28 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, } } - int compute_device = get_enum(b_preferences, "compute_device_type"); + enum ComputeDevice { + COMPUTE_DEVICE_CPU = 0, + COMPUTE_DEVICE_CUDA = 1, + COMPUTE_DEVICE_OPENCL = 2, + COMPUTE_DEVICE_NUM = 3, + }; - if(compute_device != 0) { + ComputeDevice compute_device = (ComputeDevice)get_enum(b_preferences, + "compute_device_type", + COMPUTE_DEVICE_NUM, + COMPUTE_DEVICE_CPU); + + if(compute_device != COMPUTE_DEVICE_CPU) { vector used_devices; RNA_BEGIN(&b_preferences, device, "devices") { - if(get_enum(device, "type") == compute_device && get_boolean(device, "use")) { + ComputeDevice device_type = (ComputeDevice)get_enum(device, + "type", + COMPUTE_DEVICE_NUM, + COMPUTE_DEVICE_CPU); + + if(get_boolean(device, "use") && + (device_type == compute_device || device_type == COMPUTE_DEVICE_CPU)) { string id = get_string(device, "id"); foreach(DeviceInfo& info, devices) { if(info.id == id) { @@ -708,15 +733,14 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.device = used_devices[0]; } else if(used_devices.size() > 1) { - params.device = Device::get_multi_device(used_devices); + params.device = Device::get_multi_device(used_devices, + params.threads, + params.background); } /* Else keep using the CPU device that was set before. */ } } - /* Background */ - params.background = background; - /* samples */ int samples = get_int(cscene, "samples"); int aa_samples = get_int(cscene, "aa_samples"); @@ -776,20 +800,28 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.tile_order = TILE_BOTTOM_TO_TOP; } + /* other parameters */ params.start_resolution = get_int(cscene, "preview_start_resolution"); params.pixel_size = b_engine.get_preview_pixel_size(b_scene); /* other parameters */ - if(b_scene.render().threads_mode() == BL::RenderSettings::threads_mode_FIXED) - params.threads = b_scene.render().threads(); - else - params.threads = 0; - params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout"); params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout"); params.text_timeout = (double)get_float(cscene, "debug_text_timeout"); - params.progressive_refine = get_boolean(cscene, "use_progressive_refine"); + /* progressive refine */ + params.progressive_refine = get_boolean(cscene, "use_progressive_refine") && + !b_r.use_save_buffers(); + + if(params.progressive_refine) { + BL::RenderSettings::layers_iterator b_rlay; + for(b_r.layers.begin(b_rlay); b_rlay != b_r.layers.end(); ++b_rlay) { + PointerRNA crl = RNA_pointer_get(&b_rlay->ptr, "cycles"); + if(get_boolean(crl, "use_denoising")) { + params.progressive_refine = false; + } + } + } if(background) { if(params.progressive_refine) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 19c4bec55a8..5f01bd535d0 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -27,6 +27,7 @@ #include "util/util_math.h" #include "util/util_opengl.h" #include "util/util_time.h" +#include "util/util_system.h" #include "util/util_types.h" #include "util/util_vector.h" #include "util/util_string.h" @@ -512,7 +513,7 @@ string Device::device_capabilities() return capabilities; } -DeviceInfo Device::get_multi_device(vector subdevices) +DeviceInfo Device::get_multi_device(const vector& subdevices, int threads, bool background) { assert(subdevices.size() > 1); @@ -520,18 +521,38 @@ DeviceInfo Device::get_multi_device(vector subdevices) info.type = DEVICE_MULTI; info.id = "MULTI"; info.description = "Multi Device"; - info.multi_devices = subdevices; info.num = 0; info.has_bindless_textures = true; info.has_volume_decoupled = true; info.has_qbvh = true; - foreach(DeviceInfo &device, subdevices) { - assert(device.type == info.multi_devices[0].type); - + foreach(const DeviceInfo &device, subdevices) { info.has_bindless_textures &= device.has_bindless_textures; info.has_volume_decoupled &= device.has_volume_decoupled; info.has_qbvh &= device.has_qbvh; + + if(device.type == DEVICE_CPU && subdevices.size() > 1) { + if(background) { + int orig_cpu_threads = (threads)? threads: system_cpu_thread_count(); + int cpu_threads = max(orig_cpu_threads - (subdevices.size() - 1), 0); + + if(cpu_threads >= 1) { + DeviceInfo cpu_device = device; + cpu_device.cpu_threads = cpu_threads; + info.multi_devices.push_back(cpu_device); + } + + VLOG(1) << "CPU render threads reduced from " + << orig_cpu_threads << " to " << cpu_threads + << ", to dedicate to GPU."; + } + else { + VLOG(1) << "CPU render threads disabled for interactive render."; + } + } + else { + info.multi_devices.push_back(device); + } } return info; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 29803abd153..47332f52ace 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -58,6 +58,7 @@ public: bool has_volume_decoupled; bool has_qbvh; bool use_split_kernel; /* Denotes if the device is going to run cycles using split-kernel */ + int cpu_threads; vector multi_devices; DeviceInfo() @@ -65,6 +66,7 @@ public: type = DEVICE_CPU; id = "CPU"; num = 0; + cpu_threads = 0; display_device = false; advanced_shading = true; has_bindless_textures = false; @@ -359,7 +361,9 @@ public: static vector& available_types(); static vector& available_devices(); static string device_capabilities(); - static DeviceInfo get_multi_device(vector subdevices); + static DeviceInfo get_multi_device(const vector& subdevices, + int threads, + bool background); /* Tag devices lists for update. */ static void tag_update(); diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index a17caabc850..0ba00da16a6 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -207,8 +207,8 @@ public: KERNEL_NAME_EVAL(cpu_avx, name), \ KERNEL_NAME_EVAL(cpu_avx2, name) - CPUDevice(DeviceInfo& info, Stats &stats, bool background) - : Device(info, stats, background), + CPUDevice(DeviceInfo& info_, Stats &stats_, bool background_) + : Device(info_, stats_, background_), #define REGISTER_KERNEL(name) name ## _kernel(KERNEL_FUNCTIONS(name)) REGISTER_KERNEL(path_trace), REGISTER_KERNEL(convert_to_half_float), @@ -229,6 +229,9 @@ public: REGISTER_KERNEL(data_init) #undef REGISTER_KERNEL { + if(info.cpu_threads == 0) { + info.cpu_threads = TaskScheduler::num_threads(); + } #ifdef WITH_OSL kernel_globals.osl = &osl_globals; @@ -237,7 +240,6 @@ public: if(use_split_kernel) { VLOG(1) << "Will be using split kernel."; } - need_texture_info = false; #define REGISTER_SPLIT_KERNEL(name) split_kernels[#name] = KernelFunctions(KERNEL_FUNCTIONS(name)) @@ -271,7 +273,7 @@ public: virtual bool show_samples() const { - return (TaskScheduler::num_threads() == 1); + return (info.cpu_threads == 1); } void load_texture_info() @@ -377,7 +379,7 @@ public: texture_info.resize(flat_slot + 128); } - TextureInfo& info = texture_info.get_data()[flat_slot]; + TextureInfo& info = texture_info[flat_slot]; info.data = (uint64_t)mem.data_pointer; info.cl_buffer = 0; info.interpolation = interpolation; @@ -826,9 +828,9 @@ public: int get_split_task_count(DeviceTask& task) { if(task.type == DeviceTask::SHADER) - return task.get_subtask_count(TaskScheduler::num_threads(), 256); + return task.get_subtask_count(info.cpu_threads, 256); else - return task.get_subtask_count(TaskScheduler::num_threads()); + return task.get_subtask_count(info.cpu_threads); } void task_add(DeviceTask& task) @@ -840,9 +842,9 @@ public: list tasks; if(task.type == DeviceTask::SHADER) - task.split(tasks, TaskScheduler::num_threads(), 256); + task.split(tasks, info.cpu_threads, 256); else - task.split(tasks, TaskScheduler::num_threads()); + task.split(tasks, info.cpu_threads); foreach(DeviceTask& task, tasks) task_pool.push(new CPUDeviceTask(this, task)); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 44f9077188b..0f057e9966f 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -840,7 +840,7 @@ public: } /* Set Mapping and tag that we need to (re-)upload to device */ - TextureInfo& info = texture_info.get_data()[flat_slot]; + TextureInfo& info = texture_info[flat_slot]; info.data = (uint64_t)tex; info.cl_buffer = 0; info.interpolation = interpolation; @@ -1932,9 +1932,10 @@ uint64_t CUDASplitKernel::state_buffer_size(device_memory& /*kg*/, device_memory 0, 0, (void**)&args, 0)); device->mem_copy_from(size_buffer, 0, 1, 1, sizeof(uint64_t)); + size_t size = size_buffer[0]; device->mem_free(size_buffer); - return *size_buffer.get_data(); + return size; } bool CUDASplitKernel::enqueue_split_kernel_data_init(const KernelDimensions& dim, diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 20707ad04c9..eeeca61496e 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -270,31 +270,14 @@ public: return &data[0]; } - T *copy(T *ptr, size_t width, size_t height = 0, size_t depth = 0) + void steal_data(array& from) { - T *mem = resize(width, height, depth); - if(mem != NULL) { - memcpy(mem, ptr, memory_size()); - } - return mem; - } - - void copy_at(T *ptr, size_t offset, size_t size) - { - if(size > 0) { - size_t mem_size = size*data_elements*datatype_size(data_type); - memcpy(&data[0] + offset, ptr, mem_size); - } - } - - void reference(T *ptr, size_t width, size_t height = 0, size_t depth = 0) - { - data.clear(); - data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth); - data_pointer = (device_ptr)ptr; - data_width = width; - data_height = height; - data_depth = depth; + data.steal_data(from); + data_size = data.size(); + data_pointer = (data_size)? (device_ptr)&data[0]: 0; + data_width = data_size; + data_height = 0; + data_depth = 0; } void clear() @@ -318,6 +301,11 @@ public: return &data[0]; } + T& operator[](size_t i) + { + return data[i]; + } + private: array data; }; diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index 6747a8a83ac..48c32a9dc5c 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -494,20 +494,21 @@ void OpenCLDeviceBase::mem_free_sub_ptr(device_ptr device_pointer) void OpenCLDeviceBase::const_copy_to(const char *name, void *host, size_t size) { ConstMemMap::iterator i = const_mem_map.find(name); + device_vector *data; if(i == const_mem_map.end()) { - device_vector *data = new device_vector(); - data->copy((uchar*)host, size); + data = new device_vector(); + data->resize(size); mem_alloc(name, *data, MEM_READ_ONLY); - i = const_mem_map.insert(ConstMemMap::value_type(name, data)).first; + const_mem_map.insert(ConstMemMap::value_type(name, data)); } else { - device_vector *data = i->second; - data->copy((uchar*)host, size); + data = i->second; } - mem_copy_to(*i->second); + memcpy(data->get_data(), host, size); + mem_copy_to(*data); } void OpenCLDeviceBase::tex_alloc(const char *name, diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp index b4e9419ebbd..920106f92d4 100644 --- a/intern/cycles/device/opencl/opencl_split.cpp +++ b/intern/cycles/device/opencl/opencl_split.cpp @@ -309,6 +309,7 @@ public: device->opencl_assert_err(device->ciErr, "clEnqueueNDRangeKernel"); device->mem_copy_from(size_buffer, 0, 1, 1, sizeof(uint64_t)); + size_t size = size_buffer[0]; device->mem_free(size_buffer); if(device->ciErr != CL_SUCCESS) { @@ -318,7 +319,7 @@ public: return 0; } - return *size_buffer.get_data(); + return size; } virtual bool enqueue_split_kernel_data_init(const KernelDimensions& dim, diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 7d5173a5f1d..459d512172f 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -1080,6 +1080,7 @@ cl_device_type OpenCLInfo::get_device_type(cl_device_id device_id) string OpenCLInfo::get_readable_device_name(cl_device_id device_id) { + string name = ""; char board_name[1024]; size_t length = 0; if(clGetDeviceInfo(device_id, @@ -1089,11 +1090,21 @@ string OpenCLInfo::get_readable_device_name(cl_device_id device_id) &length) == CL_SUCCESS) { if(length != 0 && board_name[0] != '\0') { - return board_name; + name = board_name; } } + /* Fallback to standard device name API. */ - return get_device_name(device_id); + if(name.empty()) { + name = get_device_name(device_id); + } + + /* Distinguish from our native CPU device. */ + if(get_device_type(device_id) & CL_DEVICE_TYPE_CPU) { + name += " (OpenCL)"; + } + + return name; } bool OpenCLInfo::get_driver_version(cl_device_id device_id, diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index bb94b9bb82a..c9fbd237010 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -364,6 +364,7 @@ int ImageManager::add_image(const string& filename, img->extension = extension; img->users = 1; img->use_alpha = use_alpha; + img->mem = NULL; images[type][slot] = img; @@ -696,7 +697,6 @@ bool ImageManager::file_load_image(Image *img, } void ImageManager::device_load_image(Device *device, - DeviceScene *dscene, Scene *scene, ImageDataType type, int slot, @@ -717,26 +717,27 @@ void ImageManager::device_load_image(Device *device, /* Slot assignment */ int flat_slot = type_index_to_flattened_slot(slot, type); - string name = string_printf("__tex_image_%s_%03d", name_from_type(type).c_str(), flat_slot); - if(type == IMAGE_DATA_TYPE_FLOAT4) { - if(dscene->tex_float4_image[slot] == NULL) - dscene->tex_float4_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_float4_image[slot]; + /* Free previous texture in slot. */ + if(img->mem) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(*img->mem); + delete img->mem; + img->mem = NULL; + } - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + /* Create new texture. */ + if(type == IMAGE_DATA_TYPE_FLOAT4) { + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - float *pixels = (float*)tex_img.resize(1, 1); + float *pixels = (float*)tex_img->resize(1, 1); pixels[0] = TEX_IMAGE_MISSING_R; pixels[1] = TEX_IMAGE_MISSING_G; @@ -744,60 +745,34 @@ void ImageManager::device_load_image(Device *device, pixels[3] = TEX_IMAGE_MISSING_A; } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } else if(type == IMAGE_DATA_TYPE_FLOAT) { - if(dscene->tex_float_image[slot] == NULL) - dscene->tex_float_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_float_image[slot]; - - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - float *pixels = (float*)tex_img.resize(1, 1); + float *pixels = (float*)tex_img->resize(1, 1); pixels[0] = TEX_IMAGE_MISSING_R; } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } else if(type == IMAGE_DATA_TYPE_BYTE4) { - if(dscene->tex_byte4_image[slot] == NULL) - dscene->tex_byte4_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_byte4_image[slot]; - - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - uchar *pixels = (uchar*)tex_img.resize(1, 1); + uchar *pixels = (uchar*)tex_img->resize(1, 1); pixels[0] = (TEX_IMAGE_MISSING_R * 255); pixels[1] = (TEX_IMAGE_MISSING_G * 255); @@ -805,58 +780,32 @@ void ImageManager::device_load_image(Device *device, pixels[3] = (TEX_IMAGE_MISSING_A * 255); } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } - else if(type == IMAGE_DATA_TYPE_BYTE){ - if(dscene->tex_byte_image[slot] == NULL) - dscene->tex_byte_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_byte_image[slot]; - - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + else if(type == IMAGE_DATA_TYPE_BYTE) { + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) { + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - uchar *pixels = (uchar*)tex_img.resize(1, 1); + uchar *pixels = (uchar*)tex_img->resize(1, 1); pixels[0] = (TEX_IMAGE_MISSING_R * 255); } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } - else if(type == IMAGE_DATA_TYPE_HALF4){ - if(dscene->tex_half4_image[slot] == NULL) - dscene->tex_half4_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_half4_image[slot]; - - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + else if(type == IMAGE_DATA_TYPE_HALF4) { + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) { + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - half *pixels = (half*)tex_img.resize(1, 1); + half *pixels = (half*)tex_img->resize(1, 1); pixels[0] = TEX_IMAGE_MISSING_R; pixels[1] = TEX_IMAGE_MISSING_G; @@ -864,47 +813,38 @@ void ImageManager::device_load_image(Device *device, pixels[3] = TEX_IMAGE_MISSING_A; } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } - else if(type == IMAGE_DATA_TYPE_HALF){ - if(dscene->tex_half_image[slot] == NULL) - dscene->tex_half_image[slot] = new device_vector(); - device_vector& tex_img = *dscene->tex_half_image[slot]; - - if(tex_img.device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(tex_img); - } + else if(type == IMAGE_DATA_TYPE_HALF) { + device_vector *tex_img = new device_vector(); if(!file_load_image(img, type, texture_limit, - tex_img)) { + *tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ - half *pixels = (half*)tex_img.resize(1, 1); + half *pixels = (half*)tex_img->resize(1, 1); pixels[0] = TEX_IMAGE_MISSING_R; } - { - thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), - tex_img, - img->interpolation, - img->extension); - } + img->mem = tex_img; } + /* Copy to device. */ + if(img->mem) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + *img->mem, + img->interpolation, + img->extension); + } + + img->need_load = false; } -void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot) +void ImageManager::device_free_image(Device *device, ImageDataType type, int slot) { Image *img = images[type][slot]; @@ -915,105 +855,20 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD ((OSL::TextureSystem*)osl_texture_system)->invalidate(filename); #endif } - else { - device_memory *tex_img = NULL; - switch(type) { - case IMAGE_DATA_TYPE_FLOAT4: - if(slot >= dscene->tex_float4_image.size()) { - break; - } - tex_img = dscene->tex_float4_image[slot]; - dscene->tex_float4_image[slot] = NULL; - break; - case IMAGE_DATA_TYPE_BYTE4: - if(slot >= dscene->tex_byte4_image.size()) { - break; - } - tex_img = dscene->tex_byte4_image[slot]; - dscene->tex_byte4_image[slot]= NULL; - break; - case IMAGE_DATA_TYPE_HALF4: - if(slot >= dscene->tex_half4_image.size()) { - break; - } - tex_img = dscene->tex_half4_image[slot]; - dscene->tex_half4_image[slot]= NULL; - break; - case IMAGE_DATA_TYPE_FLOAT: - if(slot >= dscene->tex_float_image.size()) { - break; - } - tex_img = dscene->tex_float_image[slot]; - dscene->tex_float_image[slot] = NULL; - break; - case IMAGE_DATA_TYPE_BYTE: - if(slot >= dscene->tex_byte_image.size()) { - break; - } - tex_img = dscene->tex_byte_image[slot]; - dscene->tex_byte_image[slot]= NULL; - break; - case IMAGE_DATA_TYPE_HALF: - if(slot >= dscene->tex_half_image.size()) { - break; - } - tex_img = dscene->tex_half_image[slot]; - dscene->tex_half_image[slot]= NULL; - break; - default: - assert(0); - tex_img = NULL; - } - if(tex_img) { - if(tex_img->device_pointer) { - thread_scoped_lock device_lock(device_mutex); - device->tex_free(*tex_img); - } - delete tex_img; - } + if(img->mem) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(*img->mem); + delete img->mem; } - delete images[type][slot]; + delete img; images[type][slot] = NULL; --tex_num_images[type]; } } -void ImageManager::device_prepare_update(DeviceScene *dscene) -{ - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - switch(type) { - case IMAGE_DATA_TYPE_FLOAT4: - if(dscene->tex_float4_image.size() <= tex_num_images[IMAGE_DATA_TYPE_FLOAT4]) - dscene->tex_float4_image.resize(tex_num_images[IMAGE_DATA_TYPE_FLOAT4]); - break; - case IMAGE_DATA_TYPE_BYTE4: - if(dscene->tex_byte4_image.size() <= tex_num_images[IMAGE_DATA_TYPE_BYTE4]) - dscene->tex_byte4_image.resize(tex_num_images[IMAGE_DATA_TYPE_BYTE4]); - break; - case IMAGE_DATA_TYPE_HALF4: - if(dscene->tex_half4_image.size() <= tex_num_images[IMAGE_DATA_TYPE_HALF4]) - dscene->tex_half4_image.resize(tex_num_images[IMAGE_DATA_TYPE_HALF4]); - break; - case IMAGE_DATA_TYPE_BYTE: - if(dscene->tex_byte_image.size() <= tex_num_images[IMAGE_DATA_TYPE_BYTE]) - dscene->tex_byte_image.resize(tex_num_images[IMAGE_DATA_TYPE_BYTE]); - break; - case IMAGE_DATA_TYPE_FLOAT: - if(dscene->tex_float_image.size() <= tex_num_images[IMAGE_DATA_TYPE_FLOAT]) - dscene->tex_float_image.resize(tex_num_images[IMAGE_DATA_TYPE_FLOAT]); - break; - case IMAGE_DATA_TYPE_HALF: - if(dscene->tex_half_image.size() <= tex_num_images[IMAGE_DATA_TYPE_HALF]) - dscene->tex_half_image.resize(tex_num_images[IMAGE_DATA_TYPE_HALF]); - break; - } - } -} - void ImageManager::device_update(Device *device, - DeviceScene *dscene, Scene *scene, Progress& progress) { @@ -1021,9 +876,6 @@ void ImageManager::device_update(Device *device, return; } - /* Make sure arrays are proper size. */ - device_prepare_update(dscene); - TaskPool pool; for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { for(size_t slot = 0; slot < images[type].size(); slot++) { @@ -1031,14 +883,13 @@ void ImageManager::device_update(Device *device, continue; if(images[type][slot]->users == 0) { - device_free_image(device, dscene, (ImageDataType)type, slot); + device_free_image(device, (ImageDataType)type, slot); } else if(images[type][slot]->need_load) { if(!osl_texture_system || images[type][slot]->builtin_data) pool.push(function_bind(&ImageManager::device_load_image, this, device, - dscene, scene, (ImageDataType)type, slot, @@ -1053,7 +904,6 @@ void ImageManager::device_update(Device *device, } void ImageManager::device_update_slot(Device *device, - DeviceScene *dscene, Scene *scene, int flat_slot, Progress *progress) @@ -1065,12 +915,11 @@ void ImageManager::device_update_slot(Device *device, assert(image != NULL); if(image->users == 0) { - device_free_image(device, dscene, type, slot); + device_free_image(device, type, slot); } else if(image->need_load) { if(!osl_texture_system || image->builtin_data) device_load_image(device, - dscene, scene, type, slot, @@ -1078,31 +927,24 @@ void ImageManager::device_update_slot(Device *device, } } -void ImageManager::device_free_builtin(Device *device, DeviceScene *dscene) +void ImageManager::device_free_builtin(Device *device) { for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { for(size_t slot = 0; slot < images[type].size(); slot++) { if(images[type][slot] && images[type][slot]->builtin_data) - device_free_image(device, dscene, (ImageDataType)type, slot); + device_free_image(device, (ImageDataType)type, slot); } } } -void ImageManager::device_free(Device *device, DeviceScene *dscene) +void ImageManager::device_free(Device *device) { for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { for(size_t slot = 0; slot < images[type].size(); slot++) { - device_free_image(device, dscene, (ImageDataType)type, slot); + device_free_image(device, (ImageDataType)type, slot); } images[type].clear(); } - - dscene->tex_float4_image.clear(); - dscene->tex_byte4_image.clear(); - dscene->tex_half4_image.clear(); - dscene->tex_float_image.clear(); - dscene->tex_byte_image.clear(); - dscene->tex_half_image.clear(); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index c86d1cbedbf..cc7c8544bed 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -28,7 +28,6 @@ CCL_NAMESPACE_BEGIN class Device; -class DeviceScene; class Progress; class Scene; @@ -62,18 +61,15 @@ public: bool& is_linear, bool& builtin_free_cache); - void device_prepare_update(DeviceScene *dscene); void device_update(Device *device, - DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_slot(Device *device, - DeviceScene *dscene, Scene *scene, int flat_slot, Progress *progress); - void device_free(Device *device, DeviceScene *dscene); - void device_free_builtin(Device *device, DeviceScene *dscene); + void device_free(Device *device); + void device_free_builtin(Device *device); void set_osl_texture_system(void *texture_system); bool set_animation_frame_update(int frame); @@ -115,6 +111,8 @@ public: InterpolationType interpolation; ExtensionType extension; + device_memory *mem; + int users; }; @@ -151,13 +149,11 @@ private: string name_from_type(int type); void device_load_image(Device *device, - DeviceScene *dscene, Scene *scene, ImageDataType type, int slot, Progress *progess); void device_free_image(Device *device, - DeviceScene *dscene, ImageDataType type, int slot); }; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 6470b3b1075..69c21fc3cb3 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1127,14 +1127,12 @@ bool Mesh::is_instanced() const MeshManager::MeshManager() { - bvh = NULL; need_update = true; need_flags_update = true; } MeshManager::~MeshManager() { - delete bvh; } void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector& mesh_attributes) @@ -1393,11 +1391,11 @@ static void update_attribute_element_size(Mesh *mesh, } static void update_attribute_element_offset(Mesh *mesh, - vector& attr_float, + device_vector& attr_float, size_t& attr_float_offset, - vector& attr_float3, + device_vector& attr_float3, size_t& attr_float3_offset, - vector& attr_uchar4, + device_vector& attr_uchar4, size_t& attr_uchar4_offset, Attribute *mattr, AttributePrimitive prim, @@ -1425,7 +1423,7 @@ static void update_attribute_element_offset(Mesh *mesh, uchar4 *data = mattr->data_uchar4(); offset = attr_uchar4_offset; - assert(attr_uchar4.capacity() >= offset + size); + assert(attr_uchar4.size() >= offset + size); for(size_t k = 0; k < size; k++) { attr_uchar4[offset+k] = data[k]; } @@ -1435,7 +1433,7 @@ static void update_attribute_element_offset(Mesh *mesh, float *data = mattr->data_float(); offset = attr_float_offset; - assert(attr_float.capacity() >= offset + size); + assert(attr_float.size() >= offset + size); for(size_t k = 0; k < size; k++) { attr_float[offset+k] = data[k]; } @@ -1445,7 +1443,7 @@ static void update_attribute_element_offset(Mesh *mesh, Transform *tfm = mattr->data_transform(); offset = attr_float3_offset; - assert(attr_float3.capacity() >= offset + size * 4); + assert(attr_float3.size() >= offset + size * 4); for(size_t k = 0; k < size*4; k++) { attr_float3[offset+k] = (&tfm->x)[k]; } @@ -1455,7 +1453,7 @@ static void update_attribute_element_offset(Mesh *mesh, float4 *data = mattr->data_float4(); offset = attr_float3_offset; - assert(attr_float3.capacity() >= offset + size); + assert(attr_float3.size() >= offset + size); for(size_t k = 0; k < size; k++) { attr_float3[offset+k] = data[k]; } @@ -1556,9 +1554,9 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, } } - vector attr_float(attr_float_size); - vector attr_float3(attr_float3_size); - vector attr_uchar4(attr_uchar4_size); + dscene->attributes_float.resize(attr_float_size); + dscene->attributes_float3.resize(attr_float3_size); + dscene->attributes_uchar4.resize(attr_uchar4_size); size_t attr_float_offset = 0; size_t attr_float3_offset = 0; @@ -1577,27 +1575,27 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Attribute *subd_mattr = mesh->subd_attributes.find(req); update_attribute_element_offset(mesh, - attr_float, attr_float_offset, - attr_float3, attr_float3_offset, - attr_uchar4, attr_uchar4_offset, + dscene->attributes_float, attr_float_offset, + dscene->attributes_float3, attr_float3_offset, + dscene->attributes_uchar4, attr_uchar4_offset, triangle_mattr, ATTR_PRIM_TRIANGLE, req.triangle_type, req.triangle_desc); update_attribute_element_offset(mesh, - attr_float, attr_float_offset, - attr_float3, attr_float3_offset, - attr_uchar4, attr_uchar4_offset, + dscene->attributes_float, attr_float_offset, + dscene->attributes_float3, attr_float3_offset, + dscene->attributes_uchar4, attr_uchar4_offset, curve_mattr, ATTR_PRIM_CURVE, req.curve_type, req.curve_desc); update_attribute_element_offset(mesh, - attr_float, attr_float_offset, - attr_float3, attr_float3_offset, - attr_uchar4, attr_uchar4_offset, + dscene->attributes_float, attr_float_offset, + dscene->attributes_float3, attr_float3_offset, + dscene->attributes_uchar4, attr_uchar4_offset, subd_mattr, ATTR_PRIM_SUBD, req.subd_type, @@ -1618,16 +1616,13 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, /* copy to device */ progress.set_status("Updating Mesh", "Copying Attributes to device"); - if(attr_float.size()) { - dscene->attributes_float.copy(&attr_float[0], attr_float.size()); + if(dscene->attributes_float.size()) { device->tex_alloc("__attributes_float", dscene->attributes_float); } - if(attr_float3.size()) { - dscene->attributes_float3.copy(&attr_float3[0], attr_float3.size()); + if(dscene->attributes_float3.size()) { device->tex_alloc("__attributes_float3", dscene->attributes_float3); } - if(attr_uchar4.size()) { - dscene->attributes_uchar4.copy(&attr_uchar4[0], attr_uchar4.size()); + if(dscene->attributes_uchar4.size()) { device->tex_alloc("__attributes_uchar4", dscene->attributes_uchar4); } } @@ -1725,10 +1720,9 @@ void MeshManager::device_update_mesh(Device *device, } } else { - PackedBVH& pack = bvh->pack; - for(size_t i = 0; i < pack.prim_index.size(); ++i) { - if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { - tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i]; + for(size_t i = 0; i < dscene->prim_index.size(); ++i) { + if((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i]; } } } @@ -1832,11 +1826,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * VLOG(1) << (bparams.use_qbvh ? "Using QBVH optimization structure" : "Using regular BVH optimization structure"); - delete bvh; - bvh = BVH::create(bparams, scene->objects); + BVH *bvh = BVH::create(bparams, scene->objects); bvh->build(progress); - if(progress.get_cancel()) return; + if(progress.get_cancel()) { + delete bvh; + return; + } /* copy to device */ progress.set_status("Updating Scene BVH", "Copying BVH to device"); @@ -1844,49 +1840,51 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * PackedBVH& pack = bvh->pack; if(pack.nodes.size()) { - dscene->bvh_nodes.reference((float4*)&pack.nodes[0], pack.nodes.size()); + dscene->bvh_nodes.steal_data(pack.nodes); device->tex_alloc("__bvh_nodes", dscene->bvh_nodes); } if(pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.reference((float4*)&pack.leaf_nodes[0], pack.leaf_nodes.size()); + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); device->tex_alloc("__bvh_leaf_nodes", dscene->bvh_leaf_nodes); } if(pack.object_node.size()) { - dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size()); + dscene->object_node.steal_data(pack.object_node); device->tex_alloc("__object_node", dscene->object_node); } if(pack.prim_tri_index.size()) { - dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size()); + dscene->prim_tri_index.steal_data(pack.prim_tri_index); device->tex_alloc("__prim_tri_index", dscene->prim_tri_index); } if(pack.prim_tri_verts.size()) { - dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size()); + dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts); } if(pack.prim_type.size()) { - dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size()); + dscene->prim_type.steal_data(pack.prim_type); device->tex_alloc("__prim_type", dscene->prim_type); } if(pack.prim_visibility.size()) { - dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size()); + dscene->prim_visibility.steal_data(pack.prim_visibility); device->tex_alloc("__prim_visibility", dscene->prim_visibility); } if(pack.prim_index.size()) { - dscene->prim_index.reference((uint*)&pack.prim_index[0], pack.prim_index.size()); + dscene->prim_index.steal_data(pack.prim_index); device->tex_alloc("__prim_index", dscene->prim_index); } if(pack.prim_object.size()) { - dscene->prim_object.reference((uint*)&pack.prim_object[0], pack.prim_object.size()); + dscene->prim_object.steal_data(pack.prim_object); device->tex_alloc("__prim_object", dscene->prim_object); } if(pack.prim_time.size()) { - dscene->prim_time.reference((float2*)&pack.prim_time[0], pack.prim_time.size()); + dscene->prim_time.steal_data(pack.prim_time); device->tex_alloc("__prim_time", dscene->prim_time); } dscene->data.bvh.root = pack.root_index; dscene->data.bvh.use_qbvh = bparams.use_qbvh; dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); + + delete bvh; } void MeshManager::device_update_flags(Device * /*device*/, @@ -1913,7 +1911,6 @@ void MeshManager::device_update_flags(Device * /*device*/, } void MeshManager::device_update_displacement_images(Device *device, - DeviceScene *dscene, Scene *scene, Progress& progress) { @@ -1941,12 +1938,10 @@ void MeshManager::device_update_displacement_images(Device *device, } } } - image_manager->device_prepare_update(dscene); foreach(int slot, bump_images) { pool.push(function_bind(&ImageManager::device_update_slot, image_manager, device, - dscene, scene, slot, &progress)); @@ -2029,7 +2024,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } if(true_displacement_used) { VLOG(1) << "Updating images used for true displacement."; - device_update_displacement_images(device, dscene, scene, progress); + device_update_displacement_images(device, scene, progress); old_need_object_flags_update = scene->object_manager->need_flags_update; scene->object_manager->device_update_flags(device, dscene, @@ -2171,6 +2166,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->attributes_uchar4); dscene->bvh_nodes.clear(); + dscene->bvh_leaf_nodes.clear(); dscene->object_node.clear(); dscene->prim_tri_verts.clear(); dscene->prim_tri_index.clear(); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index ed7cb881e91..30f5e9063e6 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -321,8 +321,6 @@ public: class MeshManager { public: - BVH *bvh; - bool need_update; bool need_flags_update; @@ -368,7 +366,6 @@ protected: Progress& progress); void device_update_displacement_images(Device *device, - DeviceScene *dscene, Scene *scene, Progress& progress); }; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index c59a5d97df5..cf89385a33d 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -107,9 +107,9 @@ void Scene::free_memory(bool final) bake_manager->device_free(device, &dscene); if(!params.persistent_data || final) - image_manager->device_free(device, &dscene); + image_manager->device_free(device); else - image_manager->device_free_builtin(device, &dscene); + image_manager->device_free_builtin(device); lookup_tables->device_free(device, &dscene); } @@ -185,7 +185,7 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel() || device->have_error()) return; progress.set_status("Updating Images"); - image_manager->device_update(device, &dscene, this, progress); + image_manager->device_update(device, this, progress); if(progress.get_cancel() || device->have_error()) return; diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index a1966afd23b..d4ec7d90ff5 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -60,15 +60,15 @@ class BakeData; class DeviceScene { public: /* BVH */ - device_vector bvh_nodes; - device_vector bvh_leaf_nodes; - device_vector object_node; + device_vector bvh_nodes; + device_vector bvh_leaf_nodes; + device_vector object_node; device_vector prim_tri_index; device_vector prim_tri_verts; - device_vector prim_type; + device_vector prim_type; device_vector prim_visibility; - device_vector prim_index; - device_vector prim_object; + device_vector prim_index; + device_vector prim_object; device_vector prim_time; /* mesh */ @@ -103,7 +103,7 @@ public: device_vector particles; /* shaders */ - device_vector svm_nodes; + device_vector svm_nodes; device_vector shader_flag; device_vector object_flag; @@ -113,14 +113,6 @@ public: /* integrator */ device_vector sobol_directions; - /* cpu images */ - vector* > tex_float4_image; - vector* > tex_byte4_image; - vector* > tex_half4_image; - vector* > tex_float_image; - vector* > tex_byte_image; - vector* > tex_half_image; - KernelData data; }; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index f1ff6b49b71..4642dcfa9a1 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -114,9 +114,7 @@ Session::~Session() } /* clean up */ - foreach(RenderTile &rtile, render_tiles) - delete rtile.buffers; - tile_manager.free_device(); + tile_manager.device_free(); delete buffers; delete display; @@ -380,19 +378,17 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) /* in case of a permanent buffer, return it, otherwise we will allocate * a new temporary buffer */ - if(!(params.background && params.output_path.empty())) { + if(buffers) { tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); rtile.buffer = buffers->buffer.device_pointer; rtile.buffers = buffers; - tile->buffers = buffers; device->map_tile(tile_device, rtile); return true; } - bool store_rtile = false; if(tile->buffers == NULL) { /* fill buffer parameters */ BufferParams buffer_params = tile_manager.params; @@ -402,52 +398,15 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) buffer_params.height = rtile.h; /* allocate buffers */ - if(params.progressive_refine) { - tile_lock.lock(); - - if(render_tiles.size() == 0) { - RenderTile nulltile; - nulltile.buffers = NULL; - render_tiles.resize(tile_manager.state.num_tiles, nulltile); - } - - /* In certain circumstances number of tiles in the tile manager could - * be changed. This is not supported by the progressive refine feature. - */ - assert(render_tiles.size() == tile_manager.state.num_tiles); - - RenderTile &stored_rtile = render_tiles[tile->index]; - if(stored_rtile.buffers == NULL) { - tile->buffers = new RenderBuffers(tile_device); - tile->buffers->reset(tile_device, buffer_params); - store_rtile = true; - } - else { - assert(rtile.x == stored_rtile.x && - rtile.y == stored_rtile.y && - rtile.w == stored_rtile.w && - rtile.h == stored_rtile.h); - tile_lock.unlock(); - tile->buffers = stored_rtile.buffers; - } - } - else { - tile->buffers = new RenderBuffers(tile_device); - - tile->buffers->reset(tile_device, buffer_params); - } + tile->buffers = new RenderBuffers(tile_device); + tile->buffers->reset(tile_device, buffer_params); } tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride); rtile.buffer = tile->buffers->buffer.device_pointer; rtile.buffers = tile->buffers; - rtile.sample = 0; - - if(store_rtile) { - render_tiles[tile->index] = rtile; - tile_lock.unlock(); - } + rtile.sample = tile_manager.state.sample; /* this will tag tile as IN PROGRESS in blender-side render pipeline, * which is needed to highlight currently rendering tile before first @@ -484,10 +443,11 @@ void Session::release_tile(RenderTile& rtile) if(tile_manager.finish_tile(rtile.tile_index, delete_tile)) { if(write_render_tile_cb && params.progressive_refine == false) { write_render_tile_cb(rtile); - if(delete_tile) { - delete rtile.buffers; - tile_manager.state.tiles[rtile.tile_index].buffers = NULL; - } + } + + if(delete_tile) { + delete rtile.buffers; + tile_manager.state.tiles[rtile.tile_index].buffers = NULL; } } else { @@ -794,10 +754,10 @@ bool Session::draw(BufferParams& buffer_params, DeviceDrawParams &draw_params) void Session::reset_(BufferParams& buffer_params, int samples) { - if(buffers) { - if(buffer_params.modified(buffers->params)) { - gpu_draw_ready = false; - buffers->reset(device, buffer_params); + if(buffers && buffer_params.modified(tile_manager.params)) { + gpu_draw_ready = false; + buffers->reset(device, buffer_params); + if(display) { display->reset(device, buffer_params); } } @@ -819,15 +779,6 @@ void Session::reset(BufferParams& buffer_params, int samples) reset_gpu(buffer_params, samples); else reset_cpu(buffer_params, samples); - - if(params.progressive_refine) { - thread_scoped_lock buffers_lock(buffers_mutex); - - foreach(RenderTile &rtile, render_tiles) - delete rtile.buffers; - - render_tiles.clear(); - } } void Session::set_samples(int samples) @@ -971,7 +922,7 @@ void Session::update_status_time(bool show_pause, bool show_done) void Session::render() { /* Clear buffers. */ - if(buffers && tile_manager.state.sample == 0) { + if(buffers && tile_manager.state.sample == tile_manager.range_start_sample) { buffers->zero(device); } @@ -1045,8 +996,18 @@ bool Session::update_progressive_refine(bool cancel) } if(params.progressive_refine) { - foreach(RenderTile &rtile, render_tiles) { + foreach(Tile& tile, tile_manager.state.tiles) { + if(!tile.buffers) { + continue; + } + + RenderTile rtile; + rtile.x = tile_manager.state.buffer.full_x + tile.x; + rtile.y = tile_manager.state.buffer.full_y + tile.y; + rtile.w = tile.w; + rtile.h = tile.h; rtile.sample = sample; + rtile.buffers = tile.buffers; if(write) { if(write_render_tile_cb) @@ -1068,11 +1029,7 @@ void Session::device_free() { scene->device_free(); - foreach(RenderTile &tile, render_tiles) - delete tile.buffers; - tile_manager.free_device(); - - render_tiles.clear(); + tile_manager.device_free(); /* used from background render only, so no need to * re-create render/display buffers here diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 980eda0876d..8495d95666b 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -221,8 +221,6 @@ protected: double last_update_time; bool update_progressive_refine(bool cancel); - vector render_tiles; - DeviceRequestedFeatures get_requested_device_features(); /* ** Split kernel routines ** */ diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 32f89897970..278a8a87b20 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -48,15 +48,15 @@ void SVMShaderManager::reset(Scene * /*scene*/) void SVMShaderManager::device_update_shader(Scene *scene, Shader *shader, Progress *progress, - vector *global_svm_nodes) + array *global_svm_nodes) { if(progress->get_cancel()) { return; } assert(shader->graph); - vector svm_nodes; - svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); + array svm_nodes; + svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); SVMCompiler::Summary summary; SVMCompiler compiler(scene->shader_manager, scene->image_manager); @@ -79,12 +79,12 @@ void SVMShaderManager::device_update_shader(Scene *scene, global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); /* Offset local SVM nodes to a global address space. */ - int4& jump_node = global_svm_nodes->at(shader->id); + int4& jump_node = (*global_svm_nodes)[shader->id]; jump_node.y = svm_nodes[0].y + global_nodes_size - 1; jump_node.z = svm_nodes[0].z + global_nodes_size - 1; jump_node.w = svm_nodes[0].w + global_nodes_size - 1; /* Copy new nodes to global storage. */ - memcpy(&global_svm_nodes->at(global_nodes_size), + memcpy(&(*global_svm_nodes)[global_nodes_size], &svm_nodes[1], sizeof(int4) * (svm_nodes.size() - 1)); nodes_lock_.unlock(); @@ -106,11 +106,11 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene device_update_shaders_used(scene); /* svm_nodes */ - vector svm_nodes; + array svm_nodes; size_t i; for(i = 0; i < scene->shaders.size(); i++) { - svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); + svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); } TaskPool task_pool; @@ -129,7 +129,7 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene return; } - dscene->svm_nodes.copy((uint4*)&svm_nodes[0], svm_nodes.size()); + dscene->svm_nodes.steal_data(svm_nodes); device->tex_alloc("__svm_nodes", dscene->svm_nodes); for(i = 0; i < scene->shaders.size(); i++) { @@ -366,17 +366,17 @@ uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w) void SVMCompiler::add_node(int a, int b, int c, int d) { - current_svm_nodes.push_back(make_int4(a, b, c, d)); + current_svm_nodes.push_back_slow(make_int4(a, b, c, d)); } void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c) { - current_svm_nodes.push_back(make_int4(type, a, b, c)); + current_svm_nodes.push_back_slow(make_int4(type, a, b, c)); } void SVMCompiler::add_node(ShaderNodeType type, const float3& f) { - current_svm_nodes.push_back(make_int4(type, + current_svm_nodes.push_back_slow(make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z))); @@ -384,7 +384,7 @@ void SVMCompiler::add_node(ShaderNodeType type, const float3& f) void SVMCompiler::add_node(const float4& f) { - current_svm_nodes.push_back(make_int4( + current_svm_nodes.push_back_slow(make_int4( __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), @@ -627,7 +627,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, /* Add instruction to skip closure and its dependencies if mix * weight is zero. */ - current_svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, + current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0)); @@ -645,7 +645,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, /* Add instruction to skip closure and its dependencies if mix * weight is zero. */ - current_svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, + current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0)); @@ -797,7 +797,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty void SVMCompiler::compile(Scene *scene, Shader *shader, - vector& svm_nodes, + array& svm_nodes, int index, Summary *summary) { @@ -839,9 +839,7 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL); compile_type(shader, shader->graph, SHADER_TYPE_BUMP); svm_nodes[index].y = svm_nodes.size(); - svm_nodes.insert(svm_nodes.end(), - current_svm_nodes.begin(), - current_svm_nodes.end()); + svm_nodes.append(current_svm_nodes); } /* generate surface shader */ @@ -852,9 +850,7 @@ void SVMCompiler::compile(Scene *scene, if(!has_bump) { svm_nodes[index].y = svm_nodes.size(); } - svm_nodes.insert(svm_nodes.end(), - current_svm_nodes.begin(), - current_svm_nodes.end()); + svm_nodes.append(current_svm_nodes); } /* generate volume shader */ @@ -862,9 +858,7 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL); compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); svm_nodes[index].z = svm_nodes.size(); - svm_nodes.insert(svm_nodes.end(), - current_svm_nodes.begin(), - current_svm_nodes.end()); + svm_nodes.append(current_svm_nodes); } /* generate displacement shader */ @@ -872,9 +866,7 @@ void SVMCompiler::compile(Scene *scene, scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL); compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); svm_nodes[index].w = svm_nodes.size(); - svm_nodes.insert(svm_nodes.end(), - current_svm_nodes.begin(), - current_svm_nodes.end()); + svm_nodes.append(current_svm_nodes); } /* Fill in summary information. */ diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index 98ef5fa05d8..0e9905957c7 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -55,7 +55,7 @@ protected: void device_update_shader(Scene *scene, Shader *shader, Progress *progress, - vector *global_svm_nodes); + array *global_svm_nodes); }; /* Graph Compiler */ @@ -98,7 +98,7 @@ public: SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager); void compile(Scene *scene, Shader *shader, - vector& svm_nodes, + array& svm_nodes, int index, Summary *summary = NULL); @@ -207,7 +207,7 @@ protected: /* compile */ void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); - vector current_svm_nodes; + array current_svm_nodes; ShaderType current_type; Shader *current_shader; ShaderGraph *current_graph; diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp index bf1ef12d602..c08c83cfe11 100644 --- a/intern/cycles/render/tables.cpp +++ b/intern/cycles/render/tables.cpp @@ -90,7 +90,9 @@ size_t LookupTables::add_table(DeviceScene *dscene, vector& data) } /* copy table data and return offset */ - dscene->lookup_table.copy_at(&data[0], new_table.offset, data.size()); + float *dtable = dscene->lookup_table.get_data(); + memcpy(dtable + new_table.offset, &data[0], sizeof(float) * data.size()); + return new_table.offset; } diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index a9620f79fa0..a388f5dfc8b 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -17,6 +17,7 @@ #include "render/tile.h" #include "util/util_algorithm.h" +#include "util/util_foreach.h" #include "util/util_types.h" CCL_NAMESPACE_BEGIN @@ -113,14 +114,16 @@ TileManager::~TileManager() { } -void TileManager::free_device() +void TileManager::device_free() { - if(schedule_denoising) { + if(schedule_denoising || progressive) { for(int i = 0; i < state.tiles.size(); i++) { delete state.tiles[i].buffers; state.tiles[i].buffers = NULL; } } + + state.tiles.clear(); } static int get_divider(int w, int h, int start_resolution) @@ -150,7 +153,7 @@ void TileManager::reset(BufferParams& params_, int num_samples_) state.resolution_divider = get_divider(params.width, params.height, start_resolution); state.render_tiles.clear(); state.denoising_tiles.clear(); - state.tiles.clear(); + device_free(); } void TileManager::set_samples(int num_samples_) @@ -196,7 +199,7 @@ int TileManager::gen_tiles(bool sliced) int slice_num = sliced? num: 1; int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x); - state.tiles.clear(); + device_free(); state.render_tiles.clear(); state.denoising_tiles.clear(); state.render_tiles.resize(num); @@ -345,6 +348,14 @@ int TileManager::gen_tiles(bool sliced) return idx; } +void TileManager::gen_render_tiles() +{ + /* Regenerate just the render tiles for progressive render. */ + foreach(Tile& tile, state.tiles) { + state.render_tiles[tile.device].push_back(tile.index); + } +} + void TileManager::set_tiles() { int resolution = state.resolution_divider; @@ -401,6 +412,10 @@ bool TileManager::finish_tile(int index, bool &delete_tile) { delete_tile = false; + if(progressive) { + return true; + } + switch(state.tiles[index].state) { case Tile::RENDER: { @@ -501,7 +516,13 @@ bool TileManager::next() state.num_samples = range_num_samples; state.resolution_divider = pixel_size; - set_tiles(); + + if(state.sample == range_start_sample) { + set_tiles(); + } + else { + gen_render_tiles(); + } } return true; diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 4cd57b7b30c..2692c7cf9f0 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -91,7 +91,7 @@ public: bool preserve_tile_device, bool background, TileOrder tile_order, int num_devices = 1, int pixel_size = 1); ~TileManager(); - void free_device(); + void device_free(); void reset(BufferParams& params, int num_samples); void set_samples(int num_samples); bool next(); @@ -146,6 +146,7 @@ protected: /* Generate tile list, return number of tiles. */ int gen_tiles(bool sliced); + void gen_render_tiles(); int get_neighbor_index(int index, int neighbor); bool check_neighbor_state(int index, Tile::State state); diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h index 4add91a3368..9e74505b14a 100644 --- a/intern/cycles/util/util_vector.h +++ b/intern/cycles/util/util_vector.h @@ -273,6 +273,15 @@ public: push_back_slow(t); } + void append(const array& from) + { + if(from.size()) { + size_t old_size = size(); + resize(old_size + from.size()); + memcpy(data_ + old_size, from.data(), sizeof(T) * from.size()); + } + } + protected: inline T* mem_allocate(size_t N) { diff --git a/source/blender/blenlib/BLI_polyfill2d_beautify.h b/source/blender/blenlib/BLI_polyfill2d_beautify.h index 29a900200bb..278771e9611 100644 --- a/source/blender/blenlib/BLI_polyfill2d_beautify.h +++ b/source/blender/blenlib/BLI_polyfill2d_beautify.h @@ -21,7 +21,6 @@ #ifndef __BLI_POLYFILL2D_BEAUTIFY_H__ #define __BLI_POLYFILL2D_BEAUTIFY_H__ -struct EdgeHash; struct Heap; struct MemArena; @@ -31,7 +30,7 @@ void BLI_polyfill_beautify( unsigned int (*tris)[3], /* structs for reuse */ - struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh); + struct MemArena *arena, struct Heap *eheap); float BLI_polyfill_beautify_quad_rotate_calc_ex( const float v1[2], const float v2[2], const float v3[2], const float v4[2], diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c index 5f6fb8e6cd4..f2a1c194eb1 100644 --- a/source/blender/blenlib/intern/polyfill2d_beautify.c +++ b/source/blender/blenlib/intern/polyfill2d_beautify.c @@ -42,77 +42,56 @@ #include "BLI_math.h" #include "BLI_memarena.h" -#include "BLI_edgehash.h" #include "BLI_heap.h" #include "BLI_polyfill2d_beautify.h" /* own include */ #include "BLI_strict_flags.h" -struct PolyEdge { - /** ordered vert indices (smaller first) */ - unsigned int verts[2]; - /** ordered face indices (depends on winding compared to the edge verts) - * - (verts[0], verts[1]) == faces[0] - * - (verts[1], verts[0]) == faces[1] - */ - unsigned int faces[2]; - /** - * The face-index which isn't used by either of the edges verts [0 - 2]. - * could be calculated each time, but cleaner to store for reuse. - */ - unsigned int faces_other_v[2]; +/* Used to find matching edges. */ +struct OrderEdge { + uint verts[2]; + uint e_half; }; +/* Half edge used for rotating in-place. */ +struct HalfEdge { + uint v; + uint e_next; + uint e_radial; + uint base_index; +}; -#ifndef NDEBUG -/** - * Only to check for error-cases. - */ -static void polyfill_validate_tri(unsigned int (*tris)[3], unsigned int tri_index, EdgeHash *ehash) +static int oedge_cmp(const void *a1, const void *a2) { - const unsigned int *tri = tris[tri_index]; - int j_curr; - - BLI_assert(!ELEM(tri[0], tri[1], tri[2]) && - !ELEM(tri[1], tri[0], tri[2]) && - !ELEM(tri[2], tri[0], tri[1])); - - for (j_curr = 0; j_curr < 3; j_curr++) { - struct PolyEdge *e; - unsigned int e_v1 = tri[(j_curr ) ]; - unsigned int e_v2 = tri[(j_curr + 1) % 3]; - e = BLI_edgehash_lookup(ehash, e_v1, e_v2); - if (e) { - if (e->faces[0] == tri_index) { - BLI_assert(e->verts[0] == e_v1); - BLI_assert(e->verts[1] == e_v2); - } - else if (e->faces[1] == tri_index) { - BLI_assert(e->verts[0] == e_v2); - BLI_assert(e->verts[1] == e_v1); - } - else { - BLI_assert(0); - } - - BLI_assert(e->faces[0] != e->faces[1]); - BLI_assert(ELEM(e_v1, UNPACK3(tri))); - BLI_assert(ELEM(e_v2, UNPACK3(tri))); - BLI_assert(ELEM(e_v1, UNPACK2(e->verts))); - BLI_assert(ELEM(e_v2, UNPACK2(e->verts))); - BLI_assert(e_v1 != tris[e->faces[0]][e->faces_other_v[0]]); - BLI_assert(e_v1 != tris[e->faces[1]][e->faces_other_v[1]]); - BLI_assert(e_v2 != tris[e->faces[0]][e->faces_other_v[0]]); - BLI_assert(e_v2 != tris[e->faces[1]][e->faces_other_v[1]]); - - BLI_assert(ELEM(tri_index, UNPACK2(e->faces))); - } + const struct OrderEdge *x1 = a1, *x2 = a2; + if (x1->verts[0] > x2->verts[0]) { + return 1; + } + else if (x1->verts[0] < x2->verts[0]) { + return -1; } -} -#endif -BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsigned int coord_last) + if (x1->verts[1] > x2->verts[1]) { + return 1; + } + else if (x1->verts[1] < x2->verts[1]) { + return -1; + } + + /* only for pradictability */ + if (x1->e_half > x2->e_half) { + return 1; + } + else if (x1->e_half < x2->e_half) { + return -1; + } + /* Should never get here, no two edges should be the same. */ + BLI_assert(false); + return 0; +} + +BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last) { BLI_assert(i_a < i_b); return ((i_a + 1 == i_b) || UNLIKELY((i_a == 0) && (i_b == coord_last))); @@ -215,27 +194,31 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex( static float polyedge_rotate_beauty_calc( const float (*coords)[2], - const unsigned int (*tris)[3], - const struct PolyEdge *e) + const struct HalfEdge *edges, + const struct HalfEdge *e_a) { + const struct HalfEdge *e_b = &edges[e_a->e_radial]; + + const struct HalfEdge *e_a_other = &edges[edges[e_a->e_next].e_next]; + const struct HalfEdge *e_b_other = &edges[edges[e_b->e_next].e_next]; + const float *v1, *v2, *v3, *v4; - v1 = coords[tris[e->faces[0]][e->faces_other_v[0]]]; - v3 = coords[tris[e->faces[1]][e->faces_other_v[1]]]; - v2 = coords[e->verts[0]]; - v4 = coords[e->verts[1]]; + v1 = coords[e_a_other->v]; + v2 = coords[e_a->v]; + v3 = coords[e_b_other->v]; + v4 = coords[e_b->v]; return BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4); } static void polyedge_beauty_cost_update_single( const float (*coords)[2], - const unsigned int (*tris)[3], - const struct PolyEdge *edges, - struct PolyEdge *e, + const struct HalfEdge *edges, + struct HalfEdge *e, Heap *eheap, HeapNode **eheap_table) { - const unsigned int i = (unsigned int)(e - edges); + const uint i = e->base_index; if (eheap_table[i]) { BLI_heap_remove(eheap, eheap_table[i]); @@ -244,7 +227,7 @@ static void polyedge_beauty_cost_update_single( { /* recalculate edge */ - const float cost = polyedge_rotate_beauty_calc(coords, tris, e); + const float cost = polyedge_rotate_beauty_calc(coords, edges, e); /* We can get cases where both choices generate very small negative costs, which leads to infinite loop. * Anyway, costs above that are not worth recomputing, maybe we could even optimize it to a smaller limit? * Actually, FLT_EPSILON is too small in some cases, 1e-6f seems to work OK hopefully? @@ -260,39 +243,22 @@ static void polyedge_beauty_cost_update_single( static void polyedge_beauty_cost_update( const float (*coords)[2], - const unsigned int (*tris)[3], - const struct PolyEdge *edges, - struct PolyEdge *e, - Heap *eheap, HeapNode **eheap_table, - EdgeHash *ehash) + struct HalfEdge *edges, + struct HalfEdge *e, + Heap *eheap, HeapNode **eheap_table) { - const unsigned int *tri_0 = tris[e->faces[0]]; - const unsigned int *tri_1 = tris[e->faces[1]]; - unsigned int i; + struct HalfEdge *e_arr[4]; + e_arr[0] = &edges[e->e_next]; + e_arr[1] = &edges[e_arr[0]->e_next]; - struct PolyEdge *e_arr[4] = { - BLI_edgehash_lookup(ehash, - tri_0[(e->faces_other_v[0] ) % 3], - tri_0[(e->faces_other_v[0] + 1) % 3]), - BLI_edgehash_lookup(ehash, - tri_0[(e->faces_other_v[0] + 2) % 3], - tri_0[(e->faces_other_v[0] ) % 3]), - BLI_edgehash_lookup(ehash, - tri_1[(e->faces_other_v[1] ) % 3], - tri_1[(e->faces_other_v[1] + 1) % 3]), - BLI_edgehash_lookup(ehash, - tri_1[(e->faces_other_v[1] + 2) % 3], - tri_1[(e->faces_other_v[1] ) % 3]), - }; - - - for (i = 0; i < 4; i++) { - if (e_arr[i]) { - BLI_assert(!(ELEM(e_arr[i]->faces[0], UNPACK2(e->faces)) && - ELEM(e_arr[i]->faces[1], UNPACK2(e->faces)))); + e = &edges[e->e_radial]; + e_arr[2] = &edges[e->e_next]; + e_arr[3] = &edges[e_arr[2]->e_next]; + for (uint i = 0; i < 4; i++) { + if (e_arr[i] && e_arr[i]->base_index != UINT_MAX) { polyedge_beauty_cost_update_single( - coords, tris, edges, + coords, edges, e_arr[i], eheap, eheap_table); } @@ -300,91 +266,49 @@ static void polyedge_beauty_cost_update( } static void polyedge_rotate( - unsigned int (*tris)[3], - struct PolyEdge *e, - EdgeHash *ehash) + struct HalfEdge *edges, + struct HalfEdge *e) { - unsigned int e_v1_new = tris[e->faces[0]][e->faces_other_v[0]]; - unsigned int e_v2_new = tris[e->faces[1]][e->faces_other_v[1]]; + /** CCW winding, rotate internal edge to new vertical state. + *
+	 *   Before         After
+	 *      X             X
+	 *     / \           /|\
+	 *  e4/   \e5     e4/ | \e5
+	 *   / e3  \       /  |  \
+	 * X ------- X -> X e0|e3 X
+	 *   \ e0  /       \  |  /
+	 *  e2\   /e1     e2\ | /e1
+	 *     \ /           \|/
+	 *      X             X
+	 * 
+ */ + struct HalfEdge *ed[6]; + uint ed_index[6]; -#ifndef NDEBUG - polyfill_validate_tri(tris, e->faces[0], ehash); - polyfill_validate_tri(tris, e->faces[1], ehash); -#endif + ed_index[0] = (uint)(e - edges); + ed[0] = &edges[ed_index[0]]; + ed_index[1] = ed[0]->e_next; + ed[1] = &edges[ed_index[1]]; + ed_index[2] = ed[1]->e_next; + ed[2] = &edges[ed_index[2]]; - BLI_assert(e_v1_new != e_v2_new); - BLI_assert(!ELEM(e_v2_new, UNPACK3(tris[e->faces[0]]))); - BLI_assert(!ELEM(e_v1_new, UNPACK3(tris[e->faces[1]]))); + ed_index[3] = e->e_radial; + ed[3] = &edges[ed_index[3]]; + ed_index[4] = ed[3]->e_next; + ed[4] = &edges[ed_index[4]]; + ed_index[5] = ed[4]->e_next; + ed[5] = &edges[ed_index[5]]; - tris[e->faces[0]][(e->faces_other_v[0] + 1) % 3] = e_v2_new; - tris[e->faces[1]][(e->faces_other_v[1] + 1) % 3] = e_v1_new; + ed[0]->e_next = ed_index[2]; + ed[1]->e_next = ed_index[3]; + ed[2]->e_next = ed_index[4]; + ed[3]->e_next = ed_index[5]; + ed[4]->e_next = ed_index[0]; + ed[5]->e_next = ed_index[1]; - e->faces_other_v[0] = (e->faces_other_v[0] + 2) % 3; - e->faces_other_v[1] = (e->faces_other_v[1] + 2) % 3; - - BLI_assert((tris[e->faces[0]][e->faces_other_v[0]] != e_v1_new) && - (tris[e->faces[0]][e->faces_other_v[0]] != e_v2_new)); - BLI_assert((tris[e->faces[1]][e->faces_other_v[1]] != e_v1_new) && - (tris[e->faces[1]][e->faces_other_v[1]] != e_v2_new)); - - BLI_edgehash_remove(ehash, e->verts[0], e->verts[1], NULL); - BLI_edgehash_insert(ehash, e_v1_new, e_v2_new, e); - - if (e_v1_new < e_v2_new) { - e->verts[0] = e_v1_new; - e->verts[1] = e_v2_new; - } - else { - /* maintain winding info */ - e->verts[0] = e_v2_new; - e->verts[1] = e_v1_new; - - SWAP(unsigned int, e->faces[0], e->faces[1]); - SWAP(unsigned int, e->faces_other_v[0], e->faces_other_v[1]); - } - - /* update adjacent data */ - { - unsigned int e_side = 0; - - for (e_side = 0; e_side < 2; e_side++) { - /* 't_other' which we need to swap out is always the same edge-order */ - const unsigned int t_other = (((e->faces_other_v[e_side]) + 2)) % 3; - unsigned int t_index = e->faces[e_side]; - unsigned int t_index_other = e->faces[!e_side]; - unsigned int *tri = tris[t_index]; - - struct PolyEdge *e_other; - unsigned int e_v1 = tri[(t_other ) ]; - unsigned int e_v2 = tri[(t_other + 1) % 3]; - - e_other = BLI_edgehash_lookup(ehash, e_v1, e_v2); - if (e_other) { - BLI_assert(t_index != e_other->faces[0] && t_index != e_other->faces[1]); - if (t_index_other == e_other->faces[0]) { - e_other->faces[0] = t_index; - e_other->faces_other_v[0] = (t_other + 2) % 3; - BLI_assert(!ELEM(tri[e_other->faces_other_v[0]], e_v1, e_v2)); - } - else if (t_index_other == e_other->faces[1]) { - e_other->faces[1] = t_index; - e_other->faces_other_v[1] = (t_other + 2) % 3; - BLI_assert(!ELEM(tri[e_other->faces_other_v[1]], e_v1, e_v2)); - } - else { - BLI_assert(0); - } - } - } - } - -#ifndef NDEBUG - polyfill_validate_tri(tris, e->faces[0], ehash); - polyfill_validate_tri(tris, e->faces[1], ehash); -#endif - - BLI_assert(!ELEM(tris[e->faces[0]][e->faces_other_v[0]], UNPACK2(e->verts))); - BLI_assert(!ELEM(tris[e->faces[1]][e->faces_other_v[1]], UNPACK2(e->verts))); + ed[0]->v = ed[5]->v; + ed[3]->v = ed[2]->v; } /** @@ -397,108 +321,124 @@ static void polyedge_rotate( */ void BLI_polyfill_beautify( const float (*coords)[2], - const unsigned int coords_tot, - unsigned int (*tris)[3], + const uint coords_tot, + uint (*tris)[3], /* structs for reuse */ - MemArena *arena, Heap *eheap, EdgeHash *ehash) + MemArena *arena, Heap *eheap) { - const unsigned int coord_last = coords_tot - 1; - const unsigned int tris_tot = coords_tot - 2; + const uint coord_last = coords_tot - 1; + const uint tris_len = coords_tot - 2; /* internal edges only (between 2 tris) */ - const unsigned int edges_tot = tris_tot - 1; - unsigned int edges_tot_used = 0; - unsigned int i; + const uint edges_len = tris_len - 1; HeapNode **eheap_table; - struct PolyEdge *edges = BLI_memarena_alloc(arena, edges_tot * sizeof(*edges)); - - BLI_assert(BLI_heap_size(eheap) == 0); - BLI_assert(BLI_edgehash_size(ehash) == 0); + const uint half_edges_len = 3 * tris_len; + struct HalfEdge *half_edges = BLI_memarena_alloc(arena, sizeof(*half_edges) * half_edges_len); + struct OrderEdge *order_edges = BLI_memarena_alloc(arena, sizeof(struct OrderEdge) * 2 * edges_len); + uint order_edges_len = 0; /* first build edges */ - for (i = 0; i < tris_tot; i++) { - unsigned int j_prev, j_curr, j_next; - j_prev = 2; - j_next = 1; - for (j_curr = 0; j_curr < 3; j_next = j_prev, j_prev = j_curr++) { - int e_index; + for (uint i = 0; i < tris_len; i++) { + for (uint j_curr = 0, j_prev = 2; j_curr < 3; j_prev = j_curr++) { + const uint e_index_prev = (i * 3) + j_prev; + const uint e_index_curr = (i * 3) + j_curr; - unsigned int e_pair[2] = { - tris[i][j_prev], - tris[i][j_curr], - }; + half_edges[e_index_prev].v = tris[i][j_prev]; + half_edges[e_index_prev].e_next = e_index_curr; + half_edges[e_index_prev].e_radial = UINT_MAX; + half_edges[e_index_prev].base_index = UINT_MAX; + uint e_pair[2] = {tris[i][j_prev], tris[i][j_curr]}; if (e_pair[0] > e_pair[1]) { - SWAP(unsigned int, e_pair[0], e_pair[1]); - e_index = 1; - } - else { - e_index = 0; + SWAP(uint, e_pair[0], e_pair[1]); } + /* ensure internal edges. */ if (!is_boundary_edge(e_pair[0], e_pair[1], coord_last)) { - struct PolyEdge *e; - void **val_p; - - if (!BLI_edgehash_ensure_p(ehash, e_pair[0], e_pair[1], &val_p)) { - e = &edges[edges_tot_used++]; - *val_p = e; - memcpy(e->verts, e_pair, sizeof(e->verts)); -#ifndef NDEBUG - e->faces[!e_index] = (unsigned int)-1; -#endif - } - else { - e = *val_p; - /* ensure each edge only ever has 2x users */ -#ifndef NDEBUG - BLI_assert(e->faces[e_index] == (unsigned int)-1); - BLI_assert((e->verts[0] == e_pair[0]) && - (e->verts[1] == e_pair[1])); -#endif - } - - e->faces[e_index] = i; - e->faces_other_v[e_index] = j_next; + order_edges[order_edges_len].verts[0] = e_pair[0]; + order_edges[order_edges_len].verts[1] = e_pair[1]; + order_edges[order_edges_len].e_half = e_index_prev; + order_edges_len += 1; } } } + BLI_assert(edges_len * 2 == order_edges_len); - /* now perform iterative rotations */ - eheap_table = BLI_memarena_alloc(arena, sizeof(HeapNode *) * (size_t)edges_tot); + qsort(order_edges, order_edges_len, sizeof(struct OrderEdge), oedge_cmp); - // for (i = 0; i < tris_tot; i++) { polyfill_validate_tri(tris, i, eh); } + for (uint i = 0, base_index = 0; i < order_edges_len; base_index++) { + const struct OrderEdge *oe_a = &order_edges[i++]; + const struct OrderEdge *oe_b = &order_edges[i++]; + BLI_assert(oe_a->verts[0] == oe_a->verts[0] && oe_a->verts[1] == oe_a->verts[1]); + half_edges[oe_a->e_half].e_radial = oe_b->e_half; + half_edges[oe_b->e_half].e_radial = oe_a->e_half; + half_edges[oe_a->e_half].base_index = base_index; + half_edges[oe_b->e_half].base_index = base_index; + } + /* order_edges could be freed now. */ - /* build heap */ - for (i = 0; i < edges_tot; i++) { - struct PolyEdge *e = &edges[i]; - const float cost = polyedge_rotate_beauty_calc(coords, (const unsigned int (*)[3])tris, e); - if (cost < 0.0f) { - eheap_table[i] = BLI_heap_insert(eheap, cost, e); - } - else { - eheap_table[i] = NULL; + /* Now perform iterative rotations. */ +#if 0 + eheap_table = BLI_memarena_alloc(arena, sizeof(HeapNode *) * (size_t)edges_len); +#else + /* We can re-use this since its big enough. */ + eheap_table = (void *)order_edges; + order_edges = NULL; +#endif + + /* Build heap. */ + { + struct HalfEdge *e = half_edges; + for (uint i = 0; i < half_edges_len; i++, e++) { + /* Accounts for boundary edged too (UINT_MAX). */ + if (e->e_radial < i) { + const float cost = polyedge_rotate_beauty_calc(coords, half_edges, e); + if (cost < 0.0f) { + eheap_table[e->base_index] = BLI_heap_insert(eheap, cost, e); + } + else { + eheap_table[e->base_index] = NULL; + } + } } } while (BLI_heap_is_empty(eheap) == false) { - struct PolyEdge *e = BLI_heap_popmin(eheap); - i = (unsigned int)(e - edges); - eheap_table[i] = NULL; + struct HalfEdge *e = BLI_heap_popmin(eheap); + eheap_table[e->base_index] = NULL; - polyedge_rotate(tris, e, ehash); + polyedge_rotate(half_edges, e); /* recalculate faces connected on the heap */ polyedge_beauty_cost_update( - coords, (const unsigned int (*)[3])tris, edges, + coords, half_edges, e, - eheap, eheap_table, ehash); + eheap, eheap_table); } BLI_heap_clear(eheap, NULL); - BLI_edgehash_clear_ex(ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE); /* MEM_freeN(eheap_table); */ /* arena */ + + /* get tris from half edge. */ + uint tri_index = 0; + for (uint i = 0; i < half_edges_len; i++) { + struct HalfEdge *e = &half_edges[i]; + if (e->v != UINT_MAX) { + uint *tri = tris[tri_index++]; + + tri[0] = e->v; + e->v = UINT_MAX; + + e = &half_edges[e->e_next]; + tri[1] = e->v; + e->v = UINT_MAX; + + e = &half_edges[e->e_next]; + tri[2] = e->v; + e->v = UINT_MAX; + } + } } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 977ae192c79..bf5fc18935d 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -925,7 +925,7 @@ void BM_face_triangulate( MemArena *pf_arena, /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ - struct Heap *pf_heap, struct EdgeHash *pf_ehash) + struct Heap *pf_heap) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); const bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY); @@ -1041,7 +1041,7 @@ void BM_face_triangulate( if (use_beauty) { BLI_polyfill_beautify( projverts, f->len, tris, - pf_arena, pf_heap, pf_ehash); + pf_arena, pf_heap); } BLI_memarena_clear(pf_arena); @@ -1497,7 +1497,6 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_ /* use_beauty */ Heap *pf_heap = NULL; - EdgeHash *pf_ehash = NULL; BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { /* don't consider two-edged faces */ @@ -1574,7 +1573,6 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_ if (UNLIKELY(pf_arena == NULL)) { pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); } tris = BLI_memarena_alloc(pf_arena, sizeof(*tris) * totfilltri); @@ -1593,7 +1591,7 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_ BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena); - BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap, pf_ehash); + BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap); for (j = 0; j < totfilltri; j++) { BMLoop **l_ptr = looptris[i++]; @@ -1612,7 +1610,6 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_ BLI_memarena_free(pf_arena); BLI_heap_free(pf_heap, NULL); - BLI_edgehash_free(pf_ehash, NULL); } *r_looptris_tot = i; diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index 313caac1243..4ec8ea59018 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -27,7 +27,6 @@ * \ingroup bmesh */ -struct EdgeHash; struct Heap; #include "BLI_compiler_attrs.h" @@ -83,7 +82,7 @@ void BM_face_triangulate( const int quad_method, const int ngon_method, const bool use_tag, struct MemArena *pf_arena, - struct Heap *pf_heap, struct EdgeHash *pf_ehash + struct Heap *pf_heap ) ATTR_NONNULL(1, 2); void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c index 9bb67ed9341..80774323d31 100644 --- a/source/blender/bmesh/operators/bmo_connect_concave.c +++ b/source/blender/bmesh/operators/bmo_connect_concave.c @@ -41,7 +41,6 @@ #include "BLI_heap.h" #include "BLI_polyfill2d.h" #include "BLI_polyfill2d_beautify.h" -#include "BLI_edgehash.h" #include "BLI_linklist.h" #include "bmesh.h" @@ -77,7 +76,7 @@ static bool bm_face_split_by_concave( BMesh *bm, BMFace *f_base, const float eps, MemArena *pf_arena, - struct Heap *pf_heap, struct EdgeHash *pf_ehash) + struct Heap *pf_heap) { const int f_base_len = f_base->len; int faces_array_tot = f_base_len - 3; @@ -99,7 +98,7 @@ static bool bm_face_split_by_concave( &faces_double, quad_method, ngon_method, false, pf_arena, - pf_heap, pf_ehash); + pf_heap); BLI_assert(edges_array_tot <= f_base_len - 3); @@ -161,7 +160,6 @@ static bool bm_face_split_by_concave( } BLI_heap_clear(pf_heap, NULL); - BLI_edgehash_clear_ex(pf_ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE); while (faces_double) { LinkNode *next = faces_double->next; @@ -201,17 +199,15 @@ void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op) MemArena *pf_arena; Heap *pf_heap; - EdgeHash *pf_ehash; pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len > 3 && bm_face_convex_tag_verts(f)) { if (bm_face_split_by_concave( bm, f, FLT_EPSILON, - pf_arena, pf_heap, pf_ehash)) + pf_arena, pf_heap)) { changed = true; } @@ -225,5 +221,4 @@ void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op) BLI_memarena_free(pf_arena); BLI_heap_free(pf_heap, NULL); - BLI_edgehash_free(pf_ehash, NULL); } diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index 36ae7231f94..d734d9b6ae1 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -497,7 +497,7 @@ static bool bm_face_triangulate( MemArena *pf_arena, /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ - struct Heap *pf_heap, struct EdgeHash *pf_ehash) + struct Heap *pf_heap) { const int f_base_len = f_base->len; int faces_array_tot = f_base_len - 3; @@ -516,8 +516,7 @@ static bool bm_face_triangulate( edges_array, &edges_array_tot, r_faces_double, quad_method, ngon_method, false, - pf_arena, - pf_heap, pf_ehash); + pf_arena, pf_heap); for (int i = 0; i < edges_array_tot; i++) { BMLoop *l_iter, *l_first; @@ -567,19 +566,16 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) { MemArena *pf_arena; Heap *pf_heap; - EdgeHash *pf_ehash; LinkNode *faces_double = NULL; if (has_ngon) { pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); } else { pf_arena = NULL; pf_heap = NULL; - pf_ehash = NULL; } /* adding new faces as we loop over faces @@ -591,8 +587,7 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) bm, f, &faces_double, r_edges_tri_tot, - pf_arena, - pf_heap, pf_ehash); + pf_arena, pf_heap); } } @@ -606,7 +601,6 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) if (has_ngon) { BLI_memarena_free(pf_arena); BLI_heap_free(pf_heap, NULL); - BLI_edgehash_free(pf_ehash, NULL); } BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c index ce1bc46d5e8..bd201fa89bf 100644 --- a/source/blender/bmesh/tools/bmesh_triangulate.c +++ b/source/blender/bmesh/tools/bmesh_triangulate.c @@ -35,7 +35,6 @@ #include "BLI_alloca.h" #include "BLI_memarena.h" #include "BLI_heap.h" -#include "BLI_edgehash.h" #include "BLI_linklist.h" /* only for defines */ @@ -57,7 +56,7 @@ static void bm_face_triangulate_mapping( MemArena *pf_arena, /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ - struct Heap *pf_heap, struct EdgeHash *pf_ehash) + struct Heap *pf_heap) { int faces_array_tot = face->len - 3; BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); @@ -71,7 +70,7 @@ static void bm_face_triangulate_mapping( &faces_double, quad_method, ngon_method, use_tag, pf_arena, - pf_heap, pf_ehash); + pf_heap); if (faces_array_tot) { int i; @@ -98,17 +97,14 @@ void BM_mesh_triangulate( BMFace *face; MemArena *pf_arena; Heap *pf_heap; - EdgeHash *pf_ehash; pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) { pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); } else { pf_heap = NULL; - pf_ehash = NULL; } if (slot_facemap_out) { @@ -120,8 +116,7 @@ void BM_mesh_triangulate( bm, face, quad_method, ngon_method, tag_only, op, slot_facemap_out, slot_facemap_double_out, - pf_arena, - pf_heap, pf_ehash); + pf_arena, pf_heap); } } } @@ -138,8 +133,7 @@ void BM_mesh_triangulate( NULL, NULL, &faces_double, quad_method, ngon_method, tag_only, - pf_arena, - pf_heap, pf_ehash); + pf_arena, pf_heap); } } } @@ -156,6 +150,5 @@ void BM_mesh_triangulate( if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) { BLI_heap_free(pf_heap, NULL); - BLI_edgehash_free(pf_ehash, NULL); } } diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 158cc53dfb3..97f63a64aad 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -833,9 +833,9 @@ void UI_exit(void); #define UI_ITEM_R_NO_BG (1 << 7) #define UI_ITEM_R_IMMEDIATE (1 << 8) -/* uiLayoutOperatorButs flags */ -#define UI_LAYOUT_OP_SHOW_TITLE 1 -#define UI_LAYOUT_OP_SHOW_EMPTY 2 +/* uiTemplateOperatorPropertyButs flags */ +#define UI_TEMPLATE_OP_PROPS_SHOW_TITLE 1 +#define UI_TEMPLATE_OP_PROPS_SHOW_EMPTY 2 /* used for transp checkers */ #define UI_ALPHA_CHECKER_DARK 100 @@ -867,9 +867,6 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr); void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context); const char *uiLayoutIntrospect(uiLayout *layout); // XXX - testing -void uiLayoutOperatorButs(const struct bContext *C, struct uiLayout *layout, struct wmOperator *op, - bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), - const char label_align, const short flag); struct MenuType *UI_but_menutype_get(uiBut *but); void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext); @@ -954,6 +951,9 @@ void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, struct Image *ima void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C); void UI_but_func_operator_search(uiBut *but); void uiTemplateOperatorSearch(uiLayout *layout); +void uiTemplateOperatorPropertyButs(const struct bContext *C, uiLayout *layout, struct wmOperator *op, + bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), + const char label_align, const short flag); void uiTemplateHeader3D(uiLayout *layout, struct bContext *C); void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C); void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 7717cee2c46..a63c000467f 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -64,8 +64,6 @@ /************************ Structs and Defines *************************/ -// #define USE_OP_RESET_BUT // we may want to make this optional, disable for now. - #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \ if (ot == NULL) { \ ui_item_disabled(layout, _opname); \ @@ -3483,125 +3481,6 @@ const char *uiLayoutIntrospect(uiLayout *layout) return str; } -#ifdef USE_OP_RESET_BUT -static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, void *UNUSED(arg_dummy2)) -{ - WM_operator_properties_reset((wmOperator *)op_pt); -} -#endif - -/* this function does not initialize the layout, functions can be called on the layout before and after */ -void uiLayoutOperatorButs( - const bContext *C, uiLayout *layout, wmOperator *op, - bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), - const char label_align, const short flag) -{ - if (!op->properties) { - IDPropertyTemplate val = {0}; - op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); - } - - if (flag & UI_LAYOUT_OP_SHOW_TITLE) { - uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE); - } - - /* poll() on this operator may still fail, at the moment there is no nice feedback when this happens - * just fails silently */ - if (!WM_operator_repeat_check(C, op)) { - UI_block_lock_set(uiLayoutGetBlock(layout), true, "Operator can't' redo"); - - /* XXX, could give some nicer feedback or not show redo panel at all? */ - uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE); - } - else { - /* useful for macros where only one of the steps can't be re-done */ - UI_block_lock_clear(uiLayoutGetBlock(layout)); - } - - /* menu */ - if (op->type->flag & OPTYPE_PRESET) { - /* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */ - PointerRNA op_ptr; - uiLayout *row; - - uiLayoutGetBlock(layout)->ui_operator = op; - - row = uiLayoutRow(layout, true); - uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE); - - wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false); - op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); - RNA_string_set(&op_ptr, "operator", op->type->idname); - - op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); - RNA_string_set(&op_ptr, "operator", op->type->idname); - RNA_boolean_set(&op_ptr, "remove_active", true); - } - - if (op->type->ui) { - op->layout = layout; - op->type->ui((bContext *)C, op); - op->layout = NULL; - - /* UI_LAYOUT_OP_SHOW_EMPTY ignored */ - } - else { - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - int empty; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* main draw call */ - empty = uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0; - - if (empty && (flag & UI_LAYOUT_OP_SHOW_EMPTY)) { - uiItemL(layout, IFACE_("No Properties"), ICON_NONE); - } - } - -#ifdef USE_OP_RESET_BUT - /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled - * but this is not so important if this button is drawn in those cases - * (which isn't all that likely anyway) - campbell */ - if (op->properties->len) { - uiBlock *block; - uiBut *but; - uiLayout *col; /* needed to avoid alignment errors with previous buttons */ - - col = uiLayoutColumn(layout, false); - block = uiLayoutGetBlock(col); - but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults")); - UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); - } -#endif - - /* set various special settings for buttons */ - { - uiBlock *block = uiLayoutGetBlock(layout); - const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0; - uiBut *but; - - - for (but = block->buttons.first; but; but = but->next) { - /* no undo for buttons for operator redo panels */ - UI_but_flag_disable(but, UI_BUT_UNDO); - - /* only for popups, see [#36109] */ - - /* if button is operator's default property, and a text-field, enable focus for it - * - this is used for allowing operators with popups to rename stuff with fewer clicks - */ - if (is_popup) { - if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) { - UI_but_focus_on_enter_event(CTX_wm_window(C), but); - } - } - } - } -} - /* this is a bit of a hack but best keep it in one place at least */ MenuType *UI_but_menutype_get(uiBut *but) { diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a5fe840716e..d7fac303d4e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -91,6 +91,9 @@ #include "PIL_time.h" + +// #define USE_OP_RESET_BUT // we may want to make this optional, disable for now. + /* defines for templateID/TemplateSearch */ #define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 6) #define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y @@ -3646,6 +3649,129 @@ void uiTemplateOperatorSearch(uiLayout *layout) UI_but_func_operator_search(but); } +/************************* Operator Redo Properties Template **************************/ + +#ifdef USE_OP_RESET_BUT +static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, void *UNUSED(arg_dummy2)) +{ + WM_operator_properties_reset((wmOperator *)op_pt); +} +#endif + +/** + * Draw Operator property buttons for redoing execution with different settings. + * This function does not initialize the layout, functions can be called on the layout before and after. + */ +void uiTemplateOperatorPropertyButs( + const bContext *C, uiLayout *layout, wmOperator *op, + bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), + const char label_align, const short flag) +{ + if (!op->properties) { + IDPropertyTemplate val = {0}; + op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); + } + + if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) { + uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE); + } + + /* poll() on this operator may still fail, at the moment there is no nice feedback when this happens + * just fails silently */ + if (!WM_operator_repeat_check(C, op)) { + UI_block_lock_set(uiLayoutGetBlock(layout), true, "Operator can't' redo"); + + /* XXX, could give some nicer feedback or not show redo panel at all? */ + uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE); + } + else { + /* useful for macros where only one of the steps can't be re-done */ + UI_block_lock_clear(uiLayoutGetBlock(layout)); + } + + /* menu */ + if (op->type->flag & OPTYPE_PRESET) { + /* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */ + PointerRNA op_ptr; + uiLayout *row; + + uiLayoutGetBlock(layout)->ui_operator = op; + + row = uiLayoutRow(layout, true); + uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE); + + wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false); + op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&op_ptr, "operator", op->type->idname); + + op_ptr = uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&op_ptr, "operator", op->type->idname); + RNA_boolean_set(&op_ptr, "remove_active", true); + } + + if (op->type->ui) { + op->layout = layout; + op->type->ui((bContext *)C, op); + op->layout = NULL; + + /* UI_LAYOUT_OP_SHOW_EMPTY ignored */ + } + else { + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + int empty; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* main draw call */ + empty = uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0; + + if (empty && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) { + uiItemL(layout, IFACE_("No Properties"), ICON_NONE); + } + } + +#ifdef USE_OP_RESET_BUT + /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled + * but this is not so important if this button is drawn in those cases + * (which isn't all that likely anyway) - campbell */ + if (op->properties->len) { + uiBlock *block; + uiBut *but; + uiLayout *col; /* needed to avoid alignment errors with previous buttons */ + + col = uiLayoutColumn(layout, false); + block = uiLayoutGetBlock(col); + but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults")); + UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); + } +#endif + + /* set various special settings for buttons */ + { + uiBlock *block = uiLayoutGetBlock(layout); + const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0; + uiBut *but; + + for (but = block->buttons.first; but; but = but->next) { + /* no undo for buttons for operator redo panels */ + UI_but_flag_disable(but, UI_BUT_UNDO); + + /* only for popups, see [#36109] */ + + /* if button is operator's default property, and a text-field, enable focus for it + * - this is used for allowing operators with popups to rename stuff with fewer clicks + */ + if (is_popup) { + if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) { + UI_but_focus_on_enter_event(CTX_wm_window(C), but); + } + } + } + } +} + /************************* Running Jobs Template **************************/ #define B_STOPRENDER 1 diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index b042bbe8fea..1504ce1a7ba 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -193,7 +193,7 @@ void CLIP_OT_tools(wmOperatorType *ot) static void clip_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op) { - uiLayoutOperatorButs(C, pa->layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, pa->layout, op, NULL, 'V', 0); } static void clip_panel_operator_redo_header(const bContext *C, Panel *pa) diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 7acf2564fb2..1839e861518 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -88,7 +88,7 @@ static void file_panel_operator(const bContext *C, Panel *pa) UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); - uiLayoutOperatorButs(C, pa->layout, op, file_panel_check_prop, '\0', UI_LAYOUT_OP_SHOW_EMPTY); + uiTemplateOperatorPropertyButs(C, pa->layout, op, file_panel_check_prop, '\0', UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); } diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 62f605ab99c..1d99fcfdd3a 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -67,7 +67,7 @@ static void view3d_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op) { - uiLayoutOperatorButs(C, pa->layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, pa->layout, op, NULL, 'V', 0); } static void view3d_panel_operator_redo_header(const bContext *C, Panel *pa) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a5c4228cd2e..53d3cd31485 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1434,13 +1434,13 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) if (op->type->flag & OPTYPE_MACRO) { for (op = op->macro.first; op; op = op->next) { - uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); if (op->next) uiItemS(layout); } } else { - uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); } UI_block_bounds_set_popup(block, 4, 0, 0); @@ -1509,7 +1509,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); /* clear so the OK button is left alone */ UI_block_func_set(block, NULL, NULL, NULL); @@ -1548,7 +1548,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); /* since ui is defined the auto-layout args are not used */ - uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'V', 0); UI_block_func_set(block, NULL, NULL, NULL); diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc index df98ead4cb9..235bae3e5ff 100644 --- a/tests/gtests/blenlib/BLI_polyfill2d_test.cc +++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc @@ -13,7 +13,6 @@ extern "C" { #include "BLI_array_utils.h" #include "BLI_polyfill2d.h" #include "BLI_math.h" -#include "BLI_edgehash.h" #include "MEM_guardedalloc.h" #ifdef USE_OBJ_PREVIEW @@ -195,17 +194,15 @@ static void test_polyfill_template( { MemArena *pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); Heap *pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); - EdgeHash *pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); BLI_polyfill_beautify( poly, poly_tot, tris, - pf_arena, pf_heap, pf_ehash); + pf_arena, pf_heap); test_polyfill_template_check(id, is_degenerate, poly, poly_tot, tris, tris_tot); BLI_memarena_free(pf_arena); BLI_heap_free(pf_heap, NULL); - BLI_edgehash_free(pf_ehash, NULL); } #endif }