Cycles: Expose image image extension mapping to the image manager

Currently only two mappings are supported by API, which is Repeat (old behavior)
and new Clip behavior. Internally this extension is being converted to periodic
flag which was already supported but wasn't exposed.

There's no support for OpenCL yet because of the way how we pack images into a
single texture.

Those settings are not exposed to UI or anywhere else and there should be no
functional changes so far.
This commit is contained in:
Sergey Sharybin 2015-07-21 21:58:19 +02:00
parent dc3563ff48
commit f2c54df625
12 changed files with 276 additions and 64 deletions

View File

@ -242,8 +242,16 @@ static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManag
bool animated = false;
volume_data->manager = image_manager;
volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true);
volume_data->slot = image_manager->add_image(
Attribute::standard_name(std),
b_ob.ptr.data,
animated,
frame,
is_float,
is_linear,
INTERPOLATION_LINEAR,
EXTENSION_REPEAT,
true);
}
static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)

View File

@ -590,14 +590,17 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Does not work properly when we change builtin type. */
if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(image->filename,
image->builtin_data,
(InterpolationType)b_image_node.interpolation());
scene->image_manager->tag_reload_image(
image->filename,
image->builtin_data,
(InterpolationType)b_image_node.interpolation(),
EXTENSION_REPEAT);
}
}
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
image->interpolation = (InterpolationType)b_image_node.interpolation();
image->extension = EXTENSION_REPEAT;
image->projection_blend = b_image_node.projection_blend();
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
node = image;
@ -630,7 +633,8 @@ static ShaderNode *add_node(Scene *scene,
if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(env->filename,
env->builtin_data,
INTERPOLATION_LINEAR);
INTERPOLATION_LINEAR,
EXTENSION_REPEAT);
}
}
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
@ -759,9 +763,11 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Use more proper update flag. */
if(true) {
scene->image_manager->tag_reload_image(point_density->filename,
point_density->builtin_data,
point_density->interpolation);
scene->image_manager->tag_reload_image(
point_density->filename,
point_density->builtin_data,
point_density->interpolation,
EXTENSION_CLIP);
}
node = point_density;
}

View File

@ -123,10 +123,20 @@ public:
kernel_const_copy(&kernel_globals, name, host, size);
}
void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool /*periodic*/)
void tex_alloc(const char *name,
device_memory& mem,
InterpolationType interpolation,
bool periodic)
{
VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height, mem.data_depth, interpolation);
kernel_tex_copy(&kernel_globals,
name,
mem.data_pointer,
mem.data_width,
mem.data_height,
mem.data_depth,
interpolation,
periodic);
mem.device_pointer = mem.data_pointer;
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);

View File

@ -32,7 +32,14 @@ void *kernel_osl_memory(KernelGlobals *kg);
bool kernel_osl_use(KernelGlobals *kg);
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, size_t depth, InterpolationType interpolation=INTERPOLATION_LINEAR);
void kernel_tex_copy(KernelGlobals *kg,
const char *name,
device_ptr mem,
size_t width,
size_t height,
size_t depth,
InterpolationType interpolation=INTERPOLATION_LINEAR,
bool periodic = true);
void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
int sample, int x, int y, int offset, int stride);

View File

@ -128,7 +128,7 @@ template<typename T> struct texture_image {
return x - (float)i;
}
ccl_always_inline float4 interp(float x, float y, bool periodic = true)
ccl_always_inline float4 interp(float x, float y)
{
if(UNLIKELY(!data))
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@ -233,14 +233,13 @@ template<typename T> struct texture_image {
}
}
ccl_always_inline float4 interp_3d(float x, float y, float z, bool periodic = false)
ccl_always_inline float4 interp_3d(float x, float y, float z)
{
return interp_3d_ex(x, y, z, interpolation, periodic);
return interp_3d_ex(x, y, z, interpolation);
}
ccl_always_inline float4 interp_3d_ex(float x, float y, float z,
int interpolation = INTERPOLATION_LINEAR,
bool periodic = false)
int interpolation = INTERPOLATION_LINEAR)
{
if(UNLIKELY(!data))
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@ -393,6 +392,7 @@ template<typename T> struct texture_image {
T *data;
int interpolation;
bool periodic;
int width, height, depth;
#undef SET_CUBIC_SPLINE_WEIGHTS
};

View File

@ -38,7 +38,14 @@ void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t s
assert(0);
}
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, size_t depth, InterpolationType interpolation)
void kernel_tex_copy(KernelGlobals *kg,
const char *name,
device_ptr mem,
size_t width,
size_t height,
size_t depth,
InterpolationType interpolation,
bool periodic)
{
if(0) {
}
@ -64,6 +71,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
tex->data = (float4*)mem;
tex->dimensions_set(width, height, depth);
tex->interpolation = interpolation;
tex->periodic = periodic;
}
}
else if(strstr(name, "__tex_image")) {
@ -79,6 +87,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
tex->data = (uchar4*)mem;
tex->dimensions_set(width, height, depth);
tex->interpolation = interpolation;
tex->periodic = periodic;
}
}
else

View File

@ -55,9 +55,16 @@ point map_to_sphere(vector dir)
return point(u, v, 0.0);
}
color image_texture_lookup(string filename, string color_space, float u, float v, output float Alpha, int use_alpha, int is_float, string interpolation)
color image_texture_lookup(string filename,
string color_space,
float u, float v,
output float Alpha,
int use_alpha,
int is_float,
string interpolation,
string wrap)
{
color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "interp", interpolation, "alpha", Alpha);
color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha);
if (use_alpha) {
rgb = color_unpremultiply(rgb, Alpha);
@ -81,6 +88,7 @@ shader node_image_texture(
string color_space = "sRGB",
string projection = "Flat",
string interpolation = "smartcubic",
string wrap = "periodic",
float projection_blend = 0.0,
int is_float = 1,
int use_alpha = 1,
@ -93,7 +101,14 @@ shader node_image_texture(
p = transform(mapping, p);
if (projection == "Flat") {
Color = image_texture_lookup(filename, color_space, p[0], p[1], Alpha, use_alpha, is_float, interpolation);
Color = image_texture_lookup(filename,
color_space,
p[0], p[1],
Alpha,
use_alpha,
is_float,
interpolation,
wrap);
}
else if (projection == "Box") {
/* object space normal */
@ -162,28 +177,59 @@ shader node_image_texture(
float tmp_alpha;
if (weight[0] > 0.0) {
Color += weight[0] * image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha, use_alpha, is_float, interpolation);
Color += weight[0] * image_texture_lookup(filename,
color_space,
p[1], p[2],
tmp_alpha,
use_alpha,
is_float,
interpolation,
wrap);
Alpha += weight[0] * tmp_alpha;
}
if (weight[1] > 0.0) {
Color += weight[1] * image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha, use_alpha, is_float, interpolation);
Color += weight[1] * image_texture_lookup(filename,
color_space,
p[0], p[2],
tmp_alpha,
use_alpha,
is_float,
interpolation,
wrap);
Alpha += weight[1] * tmp_alpha;
}
if (weight[2] > 0.0) {
Color += weight[2] * image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha, use_alpha, is_float, interpolation);
Color += weight[2] * image_texture_lookup(filename,
color_space,
p[1], p[0],
tmp_alpha,
use_alpha,
is_float,
interpolation,
wrap);
Alpha += weight[2] * tmp_alpha;
}
}
else if (projection == "Sphere") {
point projected = map_to_sphere(texco_remap_square(p));
Color = image_texture_lookup(filename, color_space,
Color = image_texture_lookup(filename,
color_space,
projected[0], projected[1],
Alpha, use_alpha, is_float, interpolation);
Alpha,
use_alpha,
is_float,
interpolation,
wrap);
}
else if (projection == "Tube") {
point projected = map_to_tube(texco_remap_square(p));
Color = image_texture_lookup(filename, color_space,
Color = image_texture_lookup(filename,
color_space,
projected[0], projected[1],
Alpha, use_alpha, is_float, interpolation);
Alpha,
use_alpha,
is_float,
interpolation,
wrap);
}
}

View File

@ -151,15 +151,27 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo
return is_float;
}
static bool image_equals(ImageManager::Image *image, const string& filename, void *builtin_data, InterpolationType interpolation)
static bool image_equals(ImageManager::Image *image,
const string& filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension)
{
return image->filename == filename &&
image->builtin_data == builtin_data &&
image->interpolation == interpolation;
image->interpolation == interpolation &&
image->extension == extension;
}
int ImageManager::add_image(const string& filename, void *builtin_data, bool animated, float frame,
bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha)
int ImageManager::add_image(const string& filename,
void *builtin_data,
bool animated,
float frame,
bool& is_float,
bool& is_linear,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha)
{
Image *img;
size_t slot;
@ -171,7 +183,12 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
/* find existing image */
for(slot = 0; slot < float_images.size(); slot++) {
img = float_images[slot];
if(img && image_equals(img, filename, builtin_data, interpolation)) {
if(img && image_equals(img,
filename,
builtin_data,
interpolation,
extension))
{
if(img->frame != frame) {
img->frame = frame;
img->need_load = true;
@ -210,6 +227,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
img->animated = animated;
img->frame = frame;
img->interpolation = interpolation;
img->extension = extension;
img->users = 1;
img->use_alpha = use_alpha;
@ -218,7 +236,12 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
else {
for(slot = 0; slot < images.size(); slot++) {
img = images[slot];
if(img && image_equals(img, filename, builtin_data, interpolation)) {
if(img && image_equals(img,
filename,
builtin_data,
interpolation,
extension))
{
if(img->frame != frame) {
img->frame = frame;
img->need_load = true;
@ -257,6 +280,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
img->animated = animated;
img->frame = frame;
img->interpolation = interpolation;
img->extension = extension;
img->users = 1;
img->use_alpha = use_alpha;
@ -300,12 +324,20 @@ void ImageManager::remove_image(int slot)
}
}
void ImageManager::remove_image(const string& filename, void *builtin_data, InterpolationType interpolation)
void ImageManager::remove_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension)
{
size_t slot;
for(slot = 0; slot < images.size(); slot++) {
if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) {
if(images[slot] && image_equals(images[slot],
filename,
builtin_data,
interpolation,
extension))
{
remove_image(slot+tex_image_byte_start);
break;
}
@ -314,7 +346,11 @@ void ImageManager::remove_image(const string& filename, void *builtin_data, Inte
if(slot == images.size()) {
/* see if it's in a float texture slot */
for(slot = 0; slot < float_images.size(); slot++) {
if(float_images[slot] && image_equals(float_images[slot], filename, builtin_data, interpolation)) {
if(float_images[slot] && image_equals(float_images[slot],
filename,
builtin_data,
interpolation,
extension)) {
remove_image(slot);
break;
}
@ -326,12 +362,19 @@ void ImageManager::remove_image(const string& filename, void *builtin_data, Inte
* without bunch of arguments passing around making code readability even
* more cluttered.
*/
void ImageManager::tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation)
void ImageManager::tag_reload_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension)
{
size_t slot;
for(slot = 0; slot < images.size(); slot++) {
if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) {
if(images[slot] && image_equals(images[slot],
filename,
builtin_data,
interpolation,
extension)) {
images[slot]->need_load = true;
break;
}
@ -340,7 +383,11 @@ void ImageManager::tag_reload_image(const string& filename, void *builtin_data,
if(slot == images.size()) {
/* see if it's in a float texture slot */
for(slot = 0; slot < float_images.size(); slot++) {
if(float_images[slot] && image_equals(float_images[slot], filename, builtin_data, interpolation)) {
if(float_images[slot] && image_equals(float_images[slot],
filename,
builtin_data,
interpolation,
extension)) {
float_images[slot]->need_load = true;
break;
}
@ -664,7 +711,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
device->tex_alloc(name.c_str(),
tex_img,
img->interpolation,
img->extension == EXTENSION_REPEAT);
}
}
else {
@ -696,7 +746,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl
if(!pack_images) {
thread_scoped_lock device_lock(device_mutex);
device->tex_alloc(name.c_str(), tex_img, img->interpolation, true);
device->tex_alloc(name.c_str(),
tex_img,
img->interpolation,
img->extension == EXTENSION_REPEAT);
}
}

View File

@ -55,11 +55,24 @@ public:
ImageManager();
~ImageManager();
int add_image(const string& filename, void *builtin_data, bool animated, float frame,
bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha);
int add_image(const string& filename,
void *builtin_data,
bool animated,
float frame,
bool& is_float,
bool& is_linear,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha);
void remove_image(int slot);
void remove_image(const string& filename, void *builtin_data, InterpolationType interpolation);
void tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation);
void remove_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension);
void tag_reload_image(const string& filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension);
bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
@ -87,6 +100,7 @@ public:
bool animated;
float frame;
InterpolationType interpolation;
ExtensionType extension;
int users;
};

View File

@ -198,6 +198,7 @@ ImageTextureNode::ImageTextureNode()
color_space = ustring("Color");
projection = ustring("Flat");
interpolation = INTERPOLATION_LINEAR;
extension = EXTENSION_REPEAT;
projection_blend = 0.0f;
animated = false;
@ -208,8 +209,12 @@ ImageTextureNode::ImageTextureNode()
ImageTextureNode::~ImageTextureNode()
{
if(image_manager)
image_manager->remove_image(filename, builtin_data, interpolation);
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
interpolation,
extension);
}
}
ShaderNode *ImageTextureNode::clone() const
@ -246,9 +251,15 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
slot = image_manager->add_image(filename, builtin_data,
animated, 0, is_float_bool, is_linear,
interpolation, use_alpha);
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
extension,
use_alpha);
is_float = (int)is_float_bool;
}
@ -318,9 +329,15 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
}
else {
bool is_float_bool;
slot = image_manager->add_image(filename, builtin_data,
animated, 0, is_float_bool, is_linear,
interpolation, use_alpha);
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
interpolation,
extension,
use_alpha);
is_float = (int)is_float_bool;
}
}
@ -361,6 +378,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
compiler.parameter("interpolation", "linear");
break;
}
if (extension == EXTENSION_REPEAT) {
compiler.parameter("wrap", "periodic");
}
else {
compiler.parameter("wrap", "clamp");
}
compiler.add(this, "node_image_texture");
}
@ -400,8 +425,12 @@ EnvironmentTextureNode::EnvironmentTextureNode()
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager)
image_manager->remove_image(filename, builtin_data, INTERPOLATION_LINEAR);
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
INTERPOLATION_LINEAR,
EXTENSION_REPEAT);
}
}
ShaderNode *EnvironmentTextureNode::clone() const
@ -436,9 +465,15 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
slot = image_manager->add_image(filename, builtin_data,
animated, 0, is_float_bool, is_linear,
INTERPOLATION_LINEAR, use_alpha);
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
INTERPOLATION_LINEAR,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
}
@ -499,9 +534,15 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
}
else {
bool is_float_bool;
slot = image_manager->add_image(filename, builtin_data,
animated, 0, is_float_bool, is_linear,
INTERPOLATION_LINEAR, use_alpha);
slot = image_manager->add_image(filename,
builtin_data,
animated,
0,
is_float_bool,
is_linear,
INTERPOLATION_LINEAR,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
}
}
@ -1330,8 +1371,12 @@ PointDensityTextureNode::PointDensityTextureNode()
PointDensityTextureNode::~PointDensityTextureNode()
{
if(image_manager)
image_manager->remove_image(filename, builtin_data, interpolation);
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
interpolation,
EXTENSION_CLIP);
}
}
ShaderNode *PointDensityTextureNode::clone() const
@ -1374,6 +1419,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
false, 0,
is_float, is_linear,
interpolation,
EXTENSION_CLIP,
true);
}
@ -1421,6 +1467,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
false, 0,
is_float, is_linear,
interpolation,
EXTENSION_CLIP,
true);
}

View File

@ -92,6 +92,7 @@ public:
ustring color_space;
ustring projection;
InterpolationType interpolation;
ExtensionType extension;
float projection_blend;
bool animated;

View File

@ -470,6 +470,17 @@ enum InterpolationType {
INTERPOLATION_SMART = 3,
};
/* Extension types for textures.
*
* Defines how the image is extrapolated past its original bounds.
*/
enum ExtensionType {
/* Cause the image to repeat horizontally and vertically. */
EXTENSION_REPEAT = 0,
/* Clip to image size and set exterior pixels as transparent. */
EXTENSION_CLIP = 1,
};
/* macros */
/* hints for branch prediction, only use in code that runs a _lot_ */