diff options
Diffstat (limited to 'intern/cycles')
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 24 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 37 | ||||
-rw-r--r-- | intern/cycles/blender/blender_sync.cpp | 14 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 108 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 31 | ||||
-rw-r--r-- | intern/cycles/render/mesh.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 5 | ||||
-rw-r--r-- | intern/cycles/util/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/util/util_image.h | 14 | ||||
-rw-r--r-- | intern/cycles/util/util_image_impl.h | 167 |
11 files changed, 365 insertions, 40 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index b53f85c3266..fed1524a816 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -129,6 +129,16 @@ enum_device_type = ( ('OPENCL', "OpenCL", "OpenCL", 2) ) +enum_texture_limit = ( + ('OFF', "No Limit", "No texture size limit", 0), + ('128', "128", "Limit texture size to 128 pixels", 1), + ('256', "256", "Limit texture size to 256 pixels", 2), + ('512', "512", "Limit texture size to 512 pixels", 3), + ('1024', "1024", "Limit texture size to 1024 pixels", 4), + ('2048', "2048", "Limit texture size to 2048 pixels", 5), + ('4096', "4096", "Limit texture size to 4096 pixels", 6), + ('8192', "8192", "Limit texture size to 8192 pixels", 7), + ) class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod @@ -608,6 +618,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): min=0.0, max=1.0, ) + cls.texture_limit = EnumProperty( + name="Viewport Texture Limit", + default='OFF', + description="Limit texture size used by viewport rendering", + items=enum_texture_limit + ) + + cls.texture_limit_render = EnumProperty( + name="Render Texture Limit", + default='OFF', + description="Limit texture size used by final rendering", + items=enum_texture_limit + ) + # Various fine-tuning debug flags def devices_update_callback(self, context): diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 1856b278c89..3f7730efbb0 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1587,29 +1587,40 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): cscene = scene.cycles layout.active = rd.use_simplify - split = layout.split() - col = split.column() - col.label(text="Viewport:") - col.prop(rd, "simplify_subdivision", text="Subdivision") - col.prop(rd, "simplify_child_particles", text="Child Particles") + col = layout.column(align=True) + col.label(text="Subdivision") + row = col.row(align=True) + row.prop(rd, "simplify_subdivision", text="Viewport") + row.prop(rd, "simplify_subdivision_render", text="Render") - col = split.column() - col.label(text="Render:") - col.prop(rd, "simplify_subdivision_render", text="Subdivision") - col.prop(rd, "simplify_child_particles_render", text="Child Particles") + col = layout.column(align=True) + col.label(text="Child Particles") + row = col.row(align=True) + row.prop(rd, "simplify_child_particles", text="Viewport") + row.prop(rd, "simplify_child_particles_render", text="Render") - layout.separator() + col = layout.column(align=True) + split = col.split() + sub = split.column() + sub.label(text="Texture Limit Viewport") + sub.prop(cscene, "texture_limit", text="") + sub = split.column() + sub.label(text="Texture Limit Render") + sub.prop(cscene, "texture_limit_render", text="") split = layout.split() - col = split.column() col.prop(cscene, "use_camera_cull") - col.prop(cscene, "camera_cull_margin", text="Margin") + row = col.row() + row.active = cscene.use_camera_cull + row.prop(cscene, "camera_cull_margin") col = split.column() col.prop(cscene, "use_distance_cull") - col.prop(cscene, "distance_cull_margin", text="Distance") + row = col.row() + row.active = cscene.use_distance_cull + row.prop(cscene, "distance_cull_margin", text="Distance") def draw_device(self, context): scene = context.scene diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 6118cc72239..38b2ce19e8a 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -504,6 +504,20 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, else params.persistent_data = false; + int texture_limit; + if(background) { + texture_limit = RNA_enum_get(&cscene, "texture_limit_render"); + } + else { + texture_limit = RNA_enum_get(&cscene, "texture_limit"); + } + if(texture_limit > 0 && b_scene.render().use_simplify()) { + params.texture_limit = 1 << (texture_limit + 6); + } + else { + params.texture_limit = 0; + } + #if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) if(is_cpu) { params.use_qbvh = DebugFlags().cpu.qbvh && system_cpu_support_sse2(); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 7465fbd43a7..11193bf4974 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -19,6 +19,7 @@ #include "scene.h" #include "util_foreach.h" +#include "util_logging.h" #include "util_path.h" #include "util_progress.h" #include "util_texture.h" @@ -476,6 +477,7 @@ template<TypeDesc::BASETYPE FileFormat, typename DeviceType> bool ImageManager::file_load_image(Image *img, ImageDataType type, + int texture_limit, device_vector<DeviceType>& tex_img) { const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; @@ -485,9 +487,15 @@ bool ImageManager::file_load_image(Image *img, return false; } /* Read RGBA pixels. */ - StorageType *pixels = (StorageType*)tex_img.resize(width, height, depth); - if(pixels == NULL) { - return false; + vector<StorageType> pixels_storage; + StorageType *pixels; + const size_t max_size = max(max(width, height), depth); + if(texture_limit > 0 && max_size > texture_limit) { + pixels_storage.resize(((size_t)width)*height*depth*4); + pixels = &pixels_storage[0]; + } + else { + pixels = (StorageType*)tex_img.resize(width, height, depth); } bool cmyk = false; if(in) { @@ -526,12 +534,12 @@ bool ImageManager::file_load_image(Image *img, if(FileFormat == TypeDesc::FLOAT) { builtin_image_float_pixels_cb(img->filename, img->builtin_data, - (float*)pixels); + (float*)&pixels[0]); } else if(FileFormat == TypeDesc::UINT8) { builtin_image_pixels_cb(img->filename, img->builtin_data, - (uchar*)pixels); + (uchar*)&pixels[0]); } else { /* TODO(dingto): Support half for ImBuf. */ @@ -540,10 +548,10 @@ bool ImageManager::file_load_image(Image *img, /* Check if we actually have a float4 slot, in case components == 1, * but device doesn't support single channel textures. */ - if(type == IMAGE_DATA_TYPE_FLOAT4 || - type == IMAGE_DATA_TYPE_HALF4 || - type == IMAGE_DATA_TYPE_BYTE4) - { + bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_BYTE4); + if(is_rgba) { size_t num_pixels = ((size_t)width) * height * depth; if(cmyk) { /* CMYK */ @@ -587,14 +595,41 @@ bool ImageManager::file_load_image(Image *img, } } } + if(pixels_storage.size() > 0) { + float scale_factor = 1.0f; + while(max_size * scale_factor > texture_limit) { + scale_factor *= 0.5f; + } + VLOG(1) << "Scaling image " << img->filename + << " by a factor of " << scale_factor << "."; + vector<StorageType> scaled_pixels; + size_t scaled_width, scaled_height, scaled_depth; + util_image_resize_pixels(pixels_storage, + width, height, depth, + is_rgba ? 4 : 1, + scale_factor, + &scaled_pixels, + &scaled_width, &scaled_height, &scaled_depth); + StorageType *texture_pixels = (StorageType*)tex_img.resize(scaled_width, + scaled_height, + scaled_depth); + memcpy(texture_pixels, + &scaled_pixels[0], + scaled_pixels.size() * sizeof(StorageType)); + } return true; } -void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) +void ImageManager::device_load_image(Device *device, + DeviceScene *dscene, + Scene *scene, + ImageDataType type, + int slot, + Progress *progress) { if(progress->get_cancel()) return; - + Image *img = images[type][slot]; if(osl_texture_system && !img->builtin_data) @@ -603,6 +638,8 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD string filename = path_filename(images[type][slot]->filename); progress->set_status("Updating Images", "Loading " + filename); + const int texture_limit = scene->params.texture_limit; + /* Slot assignment */ int flat_slot = type_index_to_flattened_slot(slot, type); @@ -622,7 +659,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::FLOAT, float>(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -648,7 +689,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::FLOAT, float>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::FLOAT, float>(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -671,7 +716,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::UINT8, uchar>(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -697,7 +746,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::UINT8, uchar>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::UINT8, uchar>(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -720,7 +772,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::HALF, half>(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); @@ -746,7 +801,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image<TypeDesc::HALF, half>(img, type, tex_img)) { + if(!file_load_image<TypeDesc::HALF, half>(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); @@ -842,7 +900,10 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD } } -void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress) +void ImageManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress) { if(!need_update) return; @@ -859,7 +920,14 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& } 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, (ImageDataType)type, slot, &progress)); + pool.push(function_bind(&ImageManager::device_load_image, + this, + device, + dscene, + scene, + (ImageDataType)type, + slot, + &progress)); } } } @@ -874,6 +942,7 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& void ImageManager::device_update_slot(Device *device, DeviceScene *dscene, + Scene *scene, int flat_slot, Progress *progress) { @@ -890,6 +959,7 @@ void ImageManager::device_update_slot(Device *device, if(!osl_texture_system || image->builtin_data) device_load_image(device, dscene, + scene, type, slot, progress); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 1dc4bf180f8..3da7338985c 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -30,6 +30,7 @@ CCL_NAMESPACE_BEGIN class Device; class DeviceScene; class Progress; +class Scene; class ImageManager { public: @@ -67,8 +68,15 @@ public: ExtensionType extension); ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear); - void device_update(Device *device, DeviceScene *dscene, Progress& progress); - void device_update_slot(Device *device, DeviceScene *dscene, int flat_slot, Progress *progress); + 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); @@ -114,6 +122,7 @@ private: typename DeviceType> bool file_load_image(Image *img, ImageDataType type, + int texture_limit, device_vector<DeviceType>& tex_img); int type_index_to_flattened_slot(int slot, ImageDataType type); @@ -122,10 +131,20 @@ private: uint8_t pack_image_options(ImageDataType type, size_t slot); - void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); - void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); - - void device_pack_images(Device *device, DeviceScene *dscene, Progress& progess); + 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); + + void device_pack_images(Device *device, + DeviceScene *dscene, + Progress& progess); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 32dba532f2b..df4327d021a 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1665,6 +1665,7 @@ void MeshManager::device_update_displacement_images(Device *device, */ image_manager->device_update(device, dscene, + scene, progress); return; } @@ -1682,6 +1683,7 @@ void MeshManager::device_update_displacement_images(Device *device, image_manager, device, dscene, + scene, slot, &progress)); } diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b341837b7e8..68124e78cb5 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -187,7 +187,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, progress); + image_manager->device_update(device, &dscene, 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 8fec171b6fb..df9363cc768 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -145,6 +145,7 @@ public: bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; + int texture_limit; SceneParams() { @@ -154,6 +155,7 @@ public: use_bvh_unaligned_nodes = true; use_qbvh = false; persistent_data = false; + texture_limit = 0; } bool modified(const SceneParams& params) @@ -162,7 +164,8 @@ public: && use_bvh_spatial_split == params.use_bvh_spatial_split && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_qbvh == params.use_qbvh - && persistent_data == params.persistent_data); } + && persistent_data == params.persistent_data + && texture_limit == params.texture_limit); } }; /* Scene */ diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 02ee4cd6774..d8abf671bd6 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRC_HEADERS util_half.h util_hash.h util_image.h + util_image_impl.h util_list.h util_logging.h util_map.h diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h index bb8a31c6fec..c8efc551d97 100644 --- a/intern/cycles/util/util_image.h +++ b/intern/cycles/util/util_image.h @@ -21,11 +21,25 @@ #include <OpenImageIO/imageio.h> +#include "util_vector.h" + CCL_NAMESPACE_BEGIN OIIO_NAMESPACE_USING +template<typename T> +void util_image_resize_pixels(const vector<T>& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + vector<T> *output_pixels, + size_t *output_width, + size_t *output_height, + size_t *output_depth); + CCL_NAMESPACE_END #endif /* __UTIL_IMAGE_H__ */ +#include "util_image_impl.h" diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h new file mode 100644 index 00000000000..3429ee46e94 --- /dev/null +++ b/intern/cycles/util/util_image_impl.h @@ -0,0 +1,167 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_IMAGE_IMPL_H__ +#define __UTIL_IMAGE_IMPL_H__ + +#include "util_debug.h" +#include "util_image.h" + +CCL_NAMESPACE_BEGIN + +namespace { + +template<typename T> +const T *util_image_read(const vector<T>& pixels, + const size_t width, + const size_t height, + const size_t /*depth*/, + const size_t components, + const size_t x, const size_t y, const size_t z) { + const size_t index = ((size_t)z * (width * height) + + (size_t)y * width + + (size_t)x) * components; + return &pixels[index]; +} + +template<typename T> +void util_image_downscale_sample(const vector<T>& pixels, + const size_t width, + const size_t height, + const size_t depth, + const size_t components, + const size_t kernel_size, + const float x, + const float y, + const float z, + T *result) +{ + assert(components <= 4); + const size_t ix = (size_t)x, + iy = (size_t)y, + iz = (size_t)z; + /* TODO(sergey): Support something smarter than box filer. */ + float accum[4] = {0}; + size_t count = 0; + for(size_t dz = 0; dz < kernel_size; ++dz) { + for(size_t dy = 0; dy < kernel_size; ++dy) { + for(size_t dx = 0; dx < kernel_size; ++dx) { + const size_t nx = ix + dx, + ny = iy + dy, + nz = iz + dz; + if(nx >= width || ny >= height || nz >= depth) { + continue; + } + const T *pixel = util_image_read(pixels, + width, height, depth, + components, + nx, ny, nz); + for(size_t k = 0; k < components; ++k) { + accum[k] += pixel[k]; + } + ++count; + } + } + } + const float inv_count = 1.0f / (float)count; + for(size_t k = 0; k < components; ++k) { + result[k] = T(accum[k] * inv_count); + } +} + +template<typename T> +void util_image_downscale_pixels(const vector<T>& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + const float inv_scale_factor, + const size_t output_width, + const size_t output_height, + const size_t output_depth, + vector<T> *output_pixels) +{ + const size_t kernel_size = (size_t)(inv_scale_factor + 0.5f); + for(size_t z = 0; z < output_depth; ++z) { + for(size_t y = 0; y < output_height; ++y) { + for(size_t x = 0; x < output_width; ++x) { + const float input_x = (float)x * inv_scale_factor, + input_y = (float)y * inv_scale_factor, + input_z = (float)z * inv_scale_factor; + const size_t output_index = + (z * output_width * output_height + + y * output_width + x) * components; + util_image_downscale_sample(input_pixels, + input_width, input_height, input_depth, + components, + kernel_size, + input_x, input_y, input_z, + &output_pixels->at(output_index)); + } + } + } +} + +} /* namespace */ + +template<typename T> +void util_image_resize_pixels(const vector<T>& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + const float scale_factor, + vector<T> *output_pixels, + size_t *output_width, + size_t *output_height, + size_t *output_depth) +{ + /* Early output for case when no scaling is applied. */ + if(scale_factor == 1.0f) { + *output_width = input_width; + *output_height = input_height; + *output_depth = input_depth; + *output_pixels = input_pixels; + return; + } + /* First of all, we calculate output image dimensions. + * We clamp them to be 1 pixel at least so we do not generate degenerate + * image. + */ + *output_width = max((size_t)((float)input_width * scale_factor), 1); + *output_height = max((size_t)((float)input_height * scale_factor), 1); + *output_depth = max((size_t)((float)input_depth * scale_factor), 1); + /* Prepare pixel storage for the result. */ + const size_t num_output_pixels = ((*output_width) * + (*output_height) * + (*output_depth)) * components; + output_pixels->resize(num_output_pixels); + if(scale_factor < 1.0f) { + const float inv_scale_factor = 1.0f / scale_factor; + util_image_downscale_pixels(input_pixels, + input_width, input_height, input_depth, + components, + inv_scale_factor, + *output_width, *output_height, *output_depth, + output_pixels); + } else { + /* TODO(sergey): Needs implementation. */ + } +} + +CCL_NAMESPACE_END + +#endif /* __UTIL_IMAGE_IMPL_H__ */ |