Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles')
-rw-r--r--intern/cycles/blender/blender_mesh.cpp2
-rw-r--r--intern/cycles/blender/blender_session.cpp11
-rw-r--r--intern/cycles/blender/blender_shader.cpp22
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h13
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp10
-rw-r--r--intern/cycles/kernel/svm/svm_types.h5
-rw-r--r--intern/cycles/render/image.cpp137
-rw-r--r--intern/cycles/render/image.h38
-rw-r--r--intern/cycles/render/nodes.cpp99
-rw-r--r--intern/cycles/render/nodes.h52
-rw-r--r--intern/cycles/render/osl.cpp35
-rw-r--r--intern/cycles/render/osl.h3
-rw-r--r--intern/cycles/render/shader.cpp6
13 files changed, 289 insertions, 144 deletions
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index de594f4fb6c..1b47c4123e3 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "render/colorspace.h"
#include "render/mesh.h"
#include "render/object.h"
#include "render/scene.h"
@@ -301,6 +302,7 @@ static void create_mesh_volume_attribute(
INTERPOLATION_LINEAR,
EXTENSION_CLIP,
use_alpha,
+ u_colorspace_raw,
metadata);
}
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 3a7e5f02b1d..c50dbb6ba55 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -16,12 +16,13 @@
#include <stdlib.h>
+#include "device/device.h"
#include "render/background.h"
#include "render/buffers.h"
#include "render/camera.h"
-#include "device/device.h"
-#include "render/integrator.h"
+#include "render/colorspace.h"
#include "render/film.h"
+#include "render/integrator.h"
#include "render/light.h"
#include "render/mesh.h"
#include "render/object.h"
@@ -1158,6 +1159,12 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
metadata.height = b_image.size()[1];
metadata.depth = 1;
metadata.channels = b_image.channels();
+
+ if (metadata.is_float) {
+ /* Float images are already converted on the Blender side,
+ * no need to do anything in Cycles. */
+ metadata.colorspace = u_colorspace_raw;
+ }
}
else if (b_id.is_a(&RNA_Object)) {
/* smoke volume data */
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index d1f823bc2b8..e6ec8b22d7a 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -15,6 +15,7 @@
*/
#include "render/background.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/light.h"
#include "render/nodes.h"
@@ -665,7 +666,14 @@ static ShaderNode *add_node(Scene *scene,
}
#endif
}
- image->color_space = (NodeImageColorSpace)b_image_node.color_space();
+ switch (b_image_node.color_space()) {
+ case BL::ShaderNodeTexImage::color_space_NONE:
+ image->colorspace = u_colorspace_raw;
+ break;
+ case BL::ShaderNodeTexImage::color_space_COLOR:
+ image->colorspace = u_colorspace_auto;
+ break;
+ }
image->projection = (NodeImageProjection)b_image_node.projection();
image->interpolation = get_image_interpolation(b_image_node);
image->extension = get_image_extension(b_image_node);
@@ -710,7 +718,14 @@ static ShaderNode *add_node(Scene *scene,
}
#endif
}
- env->color_space = (NodeImageColorSpace)b_env_node.color_space();
+ switch (b_env_node.color_space()) {
+ case BL::ShaderNodeTexEnvironment::color_space_NONE:
+ env->colorspace = u_colorspace_raw;
+ break;
+ case BL::ShaderNodeTexEnvironment::color_space_COLOR:
+ env->colorspace = u_colorspace_auto;
+ break;
+ }
env->interpolation = get_image_interpolation(b_env_node);
env->projection = (NodeEnvironmentProjection)b_env_node.projection();
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
@@ -861,7 +876,8 @@ static ShaderNode *add_node(Scene *scene,
point_density->builtin_data,
point_density->interpolation,
EXTENSION_CLIP,
- true);
+ true,
+ u_colorspace_raw);
}
node = point_density;
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index 414aaf891db..51bc5cf81a9 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -37,6 +37,7 @@ using std::isfinite;
CCL_NAMESPACE_BEGIN
class OSLRenderServices;
+class ColorSpaceProcessor;
/* OSL Texture Handle
*
@@ -53,21 +54,15 @@ class OSLRenderServices;
struct OSLTextureHandle : public OIIO::RefCnt {
enum Type { OIIO, SVM, IES, BEVEL, AO };
- OSLTextureHandle() : type(OIIO), svm_slot(-1), oiio_handle(NULL)
- {
- }
-
- OSLTextureHandle(Type type) : type(type), svm_slot(-1), oiio_handle(NULL)
- {
- }
-
- OSLTextureHandle(Type type, int svm_slot) : type(type), svm_slot(svm_slot), oiio_handle(NULL)
+ OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
+ : type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
{
}
Type type;
int svm_slot;
OSL::TextureSystem::TextureHandle *oiio_handle;
+ ColorSpaceProcessor *processor;
};
typedef OIIO::intrusive_ptr<OSLTextureHandle> OSLTextureHandleRef;
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 7de596a2c30..0257f569f4a 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -25,6 +25,7 @@
#include <string.h>
+#include "render/colorspace.h"
#include "render/mesh.h"
#include "render/object.h"
#include "render/scene.h"
@@ -1116,6 +1117,9 @@ bool OSLRenderServices::texture(ustring filename,
* other nasty stuff happening. */
ts->geterror();
}
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
break;
}
}
@@ -1213,6 +1217,9 @@ bool OSLRenderServices::texture3d(ustring filename,
* other nasty stuff happening. */
ts->geterror();
}
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
break;
}
case OSLTextureHandle::IES:
@@ -1287,6 +1294,9 @@ bool OSLRenderServices::environment(ustring filename,
result[3] = 1.0f;
}
}
+ else if (handle && handle->processor) {
+ ColorSpaceManager::to_scene_linear(handle->processor, result, nchannels);
+ }
return status;
}
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index d31e4f93696..2e4d0c81b95 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -373,11 +373,6 @@ typedef enum NodeNormalMapSpace {
NODE_NORMAL_MAP_BLENDER_WORLD,
} NodeNormalMapSpace;
-typedef enum NodeImageColorSpace {
- NODE_COLOR_SPACE_NONE = 0,
- NODE_COLOR_SPACE_COLOR = 1,
-} NodeImageColorSpace;
-
typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_FLAT = 0,
NODE_IMAGE_PROJ_BOX = 1,
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index ae219e912e0..dc75dca2d19 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#include "device/device.h"
#include "render/image.h"
+#include "device/device.h"
+#include "render/colorspace.h"
#include "render/scene.h"
#include "render/stats.h"
#include "util/util_foreach.h"
+#include "util/util_image_impl.h"
#include "util/util_logging.h"
#include "util/util_path.h"
#include "util/util_progress.h"
@@ -164,11 +166,36 @@ bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata)
return false;
}
+void ImageManager::metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format)
+{
+ /* Convert used specified color spaces to one we know how to handle. */
+ metadata.colorspace = ColorSpaceManager::detect_known_colorspace(
+ metadata.colorspace, file_format, metadata.is_float || metadata.is_half);
+
+ if (metadata.colorspace == u_colorspace_raw) {
+ /* Nothing to do. */
+ }
+ else if (metadata.colorspace == u_colorspace_srgb) {
+ /* Keep sRGB colorspace stored as sRGB, to save memory and/or loading time
+ * for the common case of 8bit sRGB images like PNG. */
+ metadata.compress_as_srgb = true;
+ }
+ else {
+ /* Always compress non-raw 8bit images as scene linear + sRGB, as a
+ * heuristic to keep memory usage the same without too much data loss
+ * due to quantization in common cases. */
+ metadata.compress_as_srgb = (metadata.type == IMAGE_DATA_TYPE_BYTE ||
+ metadata.type == IMAGE_DATA_TYPE_BYTE4);
+ }
+}
+
bool ImageManager::get_image_metadata(const string &filename,
void *builtin_data,
+ ustring colorspace,
ImageMetaData &metadata)
{
memset(&metadata, 0, sizeof(metadata));
+ metadata.colorspace = colorspace;
if (builtin_data) {
if (builtin_image_info_cb) {
@@ -179,13 +206,14 @@ bool ImageManager::get_image_metadata(const string &filename,
}
if (metadata.is_float) {
- metadata.is_linear = true;
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+ metadata_detect_colorspace(metadata, "");
+
return true;
}
@@ -213,20 +241,19 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.width = spec.width;
metadata.height = spec.height;
metadata.depth = spec.depth;
+ metadata.compress_as_srgb = false;
/* Check the main format, and channel formats. */
size_t channel_size = spec.format.basesize();
if (spec.format.is_floating_point()) {
metadata.is_float = true;
- metadata.is_linear = true;
}
for (size_t channel = 0; channel < spec.channelformats.size(); channel++) {
channel_size = max(channel_size, spec.channelformats[channel].basesize());
if (spec.channelformats[channel].is_floating_point()) {
metadata.is_float = true;
- metadata.is_linear = true;
}
}
@@ -235,21 +262,6 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.is_half = true;
}
- /* basic color space detection, not great but better than nothing
- * before we do OpenColorIO integration */
- if (metadata.is_float) {
- string colorspace = spec.get_string_attribute("oiio:ColorSpace");
-
- metadata.is_linear = !(
- colorspace == "sRGB" || colorspace == "GammaCorrected" ||
- (colorspace == "" &&
- (strcmp(in->format_name(), "png") == 0 || strcmp(in->format_name(), "tiff") == 0 ||
- strcmp(in->format_name(), "dpx") == 0 || strcmp(in->format_name(), "jpeg2000") == 0)));
- }
- else {
- metadata.is_linear = false;
- }
-
/* set type and channels */
metadata.channels = spec.nchannels;
@@ -266,6 +278,8 @@ bool ImageManager::get_image_metadata(const string &filename,
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
}
+ metadata_detect_colorspace(metadata, in->format_name());
+
in->close();
return true;
@@ -276,11 +290,12 @@ static bool image_equals(ImageManager::Image *image,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ bool use_alpha,
+ ustring colorspace)
{
return image->filename == filename && image->builtin_data == builtin_data &&
image->interpolation == interpolation && image->extension == extension &&
- image->use_alpha == use_alpha;
+ image->use_alpha == use_alpha && image->colorspace == colorspace;
}
int ImageManager::add_image(const string &filename,
@@ -290,12 +305,13 @@ int ImageManager::add_image(const string &filename,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha,
+ ustring colorspace,
ImageMetaData &metadata)
{
Image *img;
size_t slot;
- get_image_metadata(filename, builtin_data, metadata);
+ get_image_metadata(filename, builtin_data, colorspace, metadata);
ImageDataType type = metadata.type;
thread_scoped_lock device_lock(device_mutex);
@@ -313,7 +329,8 @@ int ImageManager::add_image(const string &filename,
/* Fnd existing image. */
for (slot = 0; slot < images[type].size(); slot++) {
img = images[type][slot];
- if (img && image_equals(img, filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (img && image_equals(
+ img, filename, builtin_data, interpolation, extension, use_alpha, colorspace)) {
if (img->frame != frame) {
img->frame = frame;
img->need_load = true;
@@ -322,6 +339,10 @@ int ImageManager::add_image(const string &filename,
img->use_alpha = use_alpha;
img->need_load = true;
}
+ if (img->colorspace != colorspace) {
+ img->colorspace = colorspace;
+ img->need_load = true;
+ }
if (!(img->metadata == metadata)) {
img->metadata = metadata;
img->need_load = true;
@@ -370,6 +391,7 @@ int ImageManager::add_image(const string &filename,
img->extension = extension;
img->users = 1;
img->use_alpha = use_alpha;
+ img->colorspace = colorspace;
img->mem = NULL;
images[type][slot] = img;
@@ -403,15 +425,20 @@ void ImageManager::remove_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ bool use_alpha,
+ ustring colorspace)
{
size_t slot;
for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for (slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] &&
- image_equals(
- images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (images[type][slot] && image_equals(images[type][slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension,
+ use_alpha,
+ colorspace)) {
remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type));
return;
}
@@ -427,13 +454,18 @@ void ImageManager::tag_reload_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha)
+ bool use_alpha,
+ ustring colorspace)
{
for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
for (size_t slot = 0; slot < images[type].size(); slot++) {
- if (images[type][slot] &&
- image_equals(
- images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) {
+ if (images[type][slot] && image_equals(images[type][slot],
+ filename,
+ builtin_data,
+ interpolation,
+ extension,
+ use_alpha,
+ colorspace)) {
images[type][slot]->need_load = true;
break;
}
@@ -502,14 +534,16 @@ bool ImageManager::file_load_image(Image *img,
int depth = img->metadata.depth;
int components = img->metadata.channels;
- /* Read RGBA pixels. */
+ /* Read pixels. */
vector<StorageType> pixels_storage;
StorageType *pixels;
const size_t max_size = max(max(width, height), depth);
if (max_size == 0) {
- /* Don't bother with invalid images. */
+ /* Don't bother with empty images. */
return false;
}
+
+ /* Allocate memory as needed, may be smaller to resize down. */
if (texture_limit > 0 && max_size > texture_limit) {
pixels_storage.resize(((size_t)width) * height * depth * 4);
pixels = &pixels_storage[0];
@@ -518,19 +552,23 @@ bool ImageManager::file_load_image(Image *img,
thread_scoped_lock device_lock(device_mutex);
pixels = (StorageType *)tex_img.alloc(width, height, depth);
}
+
if (pixels == NULL) {
/* Could be that we've run out of memory. */
return false;
}
+
bool cmyk = false;
const size_t num_pixels = ((size_t)width) * height * depth;
if (in) {
+ /* Read pixels through OpenImageIO. */
StorageType *readpixels = pixels;
vector<StorageType> tmppixels;
if (components > 4) {
tmppixels.resize(((size_t)width) * height * components);
readpixels = &tmppixels[0];
}
+
if (depth <= 1) {
size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
in->read_image(FileFormat,
@@ -542,6 +580,7 @@ bool ImageManager::file_load_image(Image *img,
else {
in->read_image(FileFormat, (uchar *)readpixels);
}
+
if (components > 4) {
size_t dimensions = ((size_t)width) * height;
for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
@@ -552,10 +591,12 @@ bool ImageManager::file_load_image(Image *img,
}
tmppixels.clear();
}
+
cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4;
in->close();
}
else {
+ /* Read pixels through callback. */
if (FileFormat == TypeDesc::FLOAT) {
builtin_image_float_pixels_cb(img->filename,
img->builtin_data,
@@ -574,16 +615,17 @@ bool ImageManager::file_load_image(Image *img,
/* TODO(dingto): Support half for ImBuf. */
}
}
- /* Check if we actually have a float4 slot, in case components == 1,
- * but device doesn't support single channel textures.
- */
+
+ /* The kernel can handle 1 and 4 channel images. Anything that is not a single
+ * channel image is converted to RGBA format. */
bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 ||
type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4);
+
if (is_rgba) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
if (cmyk) {
- /* CMYK */
+ /* CMYK to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
float c = util_image_cast_to_float(pixels[i * 4 + 0]);
float m = util_image_cast_to_float(pixels[i * 4 + 1]);
@@ -596,7 +638,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 2) {
- /* grayscale + alpha */
+ /* Grayscale + alpha to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = pixels[i * 2 + 1];
pixels[i * 4 + 2] = pixels[i * 2 + 0];
@@ -605,7 +647,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 3) {
- /* RGB */
+ /* RGB to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
pixels[i * 4 + 2] = pixels[i * 3 + 2];
@@ -614,7 +656,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
else if (components == 1) {
- /* grayscale */
+ /* Grayscale to RGBA. */
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
pixels[i * 4 + 2] = pixels[i];
@@ -622,18 +664,27 @@ bool ImageManager::file_load_image(Image *img,
pixels[i * 4 + 0] = pixels[i];
}
}
+
+ /* Disable alpha if requested by the user. */
if (img->use_alpha == false) {
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i * 4 + 3] = one;
}
}
+
+ if (img->metadata.colorspace != u_colorspace_raw &&
+ img->metadata.colorspace != u_colorspace_srgb) {
+ /* Convert to scene linear. */
+ ColorSpaceManager::to_scene_linear(
+ img->metadata.colorspace, pixels, width, height, depth, img->metadata.compress_as_srgb);
+ }
}
+
/* Make sure we don't have buggy values. */
if (FileFormat == TypeDesc::FLOAT) {
/* For RGBA buffers we put all channels to 0 if either of them is not
* finite. This way we avoid possible artifacts caused by fully changed
- * hue.
- */
+ * hue. */
if (is_rgba) {
for (size_t i = 0; i < num_pixels; i += 4) {
StorageType *pixel = &pixels[i * 4];
@@ -655,6 +706,7 @@ bool ImageManager::file_load_image(Image *img,
}
}
}
+
/* Scale image down if needed. */
if (pixels_storage.size() > 0) {
float scale_factor = 1.0f;
@@ -684,6 +736,7 @@ bool ImageManager::file_load_image(Image *img,
memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType));
}
+
return true;
}
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 34f046692f6..d5bc37e58d7 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -20,6 +20,8 @@
#include "device/device.h"
#include "device/device_memory.h"
+#include "render/colorspace.h"
+
#include "util/util_image.h"
#include "util/util_string.h"
#include "util/util_thread.h"
@@ -32,6 +34,7 @@ class Device;
class Progress;
class RenderStats;
class Scene;
+class ColorSpaceProcessor;
class ImageMetaData {
public:
@@ -43,13 +46,29 @@ class ImageMetaData {
/* Automatically set. */
ImageDataType type;
- bool is_linear;
+ ustring colorspace;
+ bool compress_as_srgb;
+
+ ImageMetaData()
+ : is_float(false),
+ is_half(false),
+ channels(0),
+ width(0),
+ height(0),
+ depth(0),
+ builtin_free_cache(NULL),
+ type(IMAGE_DATA_NUM_TYPES),
+ colorspace(u_colorspace_raw),
+ compress_as_srgb(false)
+ {
+ }
bool operator==(const ImageMetaData &other) const
{
return is_float == other.is_float && is_half == other.is_half && channels == other.channels &&
width == other.width && height == other.height && depth == other.depth &&
- type == other.type && is_linear == other.is_linear;
+ type == other.type && colorspace == other.colorspace &&
+ compress_as_srgb == other.compress_as_srgb;
}
};
@@ -65,19 +84,25 @@ class ImageManager {
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha,
+ ustring colorspace,
ImageMetaData &metadata);
void remove_image(int flat_slot);
void remove_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha);
+ bool use_alpha,
+ ustring colorspace);
void tag_reload_image(const string &filename,
void *builtin_data,
InterpolationType interpolation,
ExtensionType extension,
- bool use_alpha);
- bool get_image_metadata(const string &filename, void *builtin_data, ImageMetaData &metadata);
+ bool use_alpha,
+ ustring colorspace);
+ bool get_image_metadata(const string &filename,
+ void *builtin_data,
+ ustring colorspace,
+ ImageMetaData &metadata);
bool get_image_metadata(int flat_slot, ImageMetaData &metadata);
void device_update(Device *device, Scene *scene, Progress &progress);
@@ -120,6 +145,7 @@ class ImageManager {
void *builtin_data;
ImageMetaData metadata;
+ ustring colorspace;
bool use_alpha;
bool need_load;
bool animated;
@@ -152,6 +178,8 @@ class ImageManager {
int texture_limit,
device_vector<DeviceType> &tex_img);
+ void metadata_detect_colorspace(ImageMetaData &metadata, const char *file_format);
+
void device_load_image(
Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress);
void device_free_image(Device *device, ImageDataType type, int slot);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 35e9f8df5a8..6e86643cc2b 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "render/colorspace.h"
#include "render/film.h"
#include "render/image.h"
#include "render/integrator.h"
@@ -207,11 +208,7 @@ NODE_DEFINE(ImageTextureNode)
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
SOCKET_STRING(filename, "Filename", ustring());
-
- static NodeEnum color_space_enum;
- color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
- color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
- SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
@@ -250,7 +247,8 @@ ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
image_manager = NULL;
slot = -1;
is_float = -1;
- is_linear = false;
+ compress_as_srgb = false;
+ colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
}
@@ -259,7 +257,7 @@ ImageTextureNode::~ImageTextureNode()
{
if (image_manager) {
image_manager->remove_image(
- filename.string(), builtin_data, interpolation, extension, use_alpha);
+ filename.string(), builtin_data, interpolation, extension, use_alpha, colorspace);
}
}
@@ -269,7 +267,8 @@ ShaderNode *ImageTextureNode::clone() const
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
- node->is_linear = false;
+ node->compress_as_srgb = false;
+ node->colorspace = u_colorspace_raw;
return node;
}
@@ -304,13 +303,14 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
interpolation,
extension,
use_alpha,
+ colorspace,
metadata);
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ colorspace = metadata.colorspace;
}
if (slot != -1) {
- int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
if (projection != NODE_IMAGE_PROJ_BOX) {
@@ -319,7 +319,7 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ compress_as_srgb),
projection);
}
else {
@@ -328,7 +328,7 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ compress_as_srgb),
__float_as_int(projection_blend));
}
@@ -358,7 +358,7 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
if (is_float == -1) {
ImageMetaData metadata;
if (builtin_data == NULL) {
- image_manager->get_image_metadata(filename.string(), NULL, metadata);
+ image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
}
else {
slot = image_manager->add_image(filename.string(),
@@ -368,17 +368,22 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
interpolation,
extension,
use_alpha,
+ colorspace,
metadata);
}
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ colorspace = metadata.colorspace;
}
- compiler.parameter_texture("filename", filename, slot);
- if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
- compiler.parameter("color_space", "linear");
- else
- compiler.parameter("color_space", "sRGB");
+ if (slot == -1) {
+ compiler.parameter_texture("filename", filename, colorspace);
+ }
+ else {
+ compiler.parameter_texture("filename", slot);
+ }
+
+ compiler.parameter("color_space", (compress_as_srgb) ? "sRGB" : "linear");
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
compiler.parameter("is_float", is_float);
@@ -398,11 +403,7 @@ NODE_DEFINE(EnvironmentTextureNode)
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
SOCKET_STRING(filename, "Filename", ustring());
-
- static NodeEnum color_space_enum;
- color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
- color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
- SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
+ SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
@@ -431,7 +432,8 @@ EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_typ
image_manager = NULL;
slot = -1;
is_float = -1;
- is_linear = false;
+ compress_as_srgb = false;
+ colorspace = u_colorspace_raw;
builtin_data = NULL;
animated = false;
}
@@ -440,7 +442,7 @@ EnvironmentTextureNode::~EnvironmentTextureNode()
{
if (image_manager) {
image_manager->remove_image(
- filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, use_alpha);
+ filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, use_alpha, colorspace);
}
}
@@ -450,7 +452,8 @@ ShaderNode *EnvironmentTextureNode::clone() const
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
- node->is_linear = false;
+ node->compress_as_srgb = false;
+ node->colorspace = u_colorspace_raw;
return node;
}
@@ -483,13 +486,14 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
interpolation,
EXTENSION_REPEAT,
use_alpha,
+ colorspace,
metadata);
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ colorspace = metadata.colorspace;
}
if (slot != -1) {
- int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_ENVIRONMENT,
@@ -497,7 +501,7 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
- srgb),
+ compress_as_srgb),
projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
@@ -529,7 +533,7 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
if (is_float == -1) {
ImageMetaData metadata;
if (builtin_data == NULL) {
- image_manager->get_image_metadata(filename.string(), NULL, metadata);
+ image_manager->get_image_metadata(filename.string(), NULL, colorspace, metadata);
}
else {
slot = image_manager->add_image(filename.string(),
@@ -539,19 +543,23 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
interpolation,
EXTENSION_REPEAT,
use_alpha,
+ colorspace,
metadata);
}
is_float = metadata.is_float;
- is_linear = metadata.is_linear;
+ compress_as_srgb = metadata.compress_as_srgb;
+ colorspace = metadata.colorspace;
}
- compiler.parameter_texture("filename", filename, slot);
- compiler.parameter(this, "projection");
- if (is_linear || color_space != NODE_COLOR_SPACE_COLOR)
- compiler.parameter("color_space", "linear");
- else
- compiler.parameter("color_space", "sRGB");
+ if (slot == -1) {
+ compiler.parameter_texture("filename", filename, colorspace);
+ }
+ else {
+ compiler.parameter_texture("filename", slot);
+ }
+ compiler.parameter(this, "projection");
+ compiler.parameter("color_space", (compress_as_srgb) ? "sRGB" : "linear");
compiler.parameter(this, "interpolation");
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
@@ -1467,7 +1475,7 @@ PointDensityTextureNode::~PointDensityTextureNode()
{
if (image_manager) {
image_manager->remove_image(
- filename.string(), builtin_data, interpolation, EXTENSION_CLIP, true);
+ filename.string(), builtin_data, interpolation, EXTENSION_CLIP, true, ustring());
}
}
@@ -1491,8 +1499,15 @@ void PointDensityTextureNode::add_image()
{
if (slot == -1) {
ImageMetaData metadata;
- slot = image_manager->add_image(
- filename.string(), builtin_data, false, 0, interpolation, EXTENSION_CLIP, true, metadata);
+ slot = image_manager->add_image(filename.string(),
+ builtin_data,
+ false,
+ 0,
+ interpolation,
+ EXTENSION_CLIP,
+ true,
+ u_colorspace_raw,
+ metadata);
}
}
@@ -1551,7 +1566,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
if (use_density || use_color) {
add_image();
- compiler.parameter_texture("filename", ustring(), slot);
+ compiler.parameter_texture("filename", slot);
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 7796711115e..88fa728ecd1 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -92,13 +92,18 @@ class ImageTextureNode : public ImageSlotTextureNode {
return true;
}
- ImageManager *image_manager;
- int is_float;
- bool is_linear;
+ virtual bool equals(const ShaderNode &other)
+ {
+ const ImageTextureNode &image_node = (const ImageTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data &&
+ animated == image_node.animated;
+ }
+
+ /* Parameters. */
bool use_alpha;
ustring filename;
void *builtin_data;
- NodeImageColorSpace color_space;
+ ustring colorspace;
NodeImageProjection projection;
InterpolationType interpolation;
ExtensionType extension;
@@ -106,12 +111,11 @@ class ImageTextureNode : public ImageSlotTextureNode {
bool animated;
float3 vector;
- virtual bool equals(const ShaderNode &other)
- {
- const ImageTextureNode &image_node = (const ImageTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data &&
- animated == image_node.animated;
- }
+ /* Runtime. */
+ ImageManager *image_manager;
+ int is_float;
+ bool compress_as_srgb;
+ ustring known_colorspace;
};
class EnvironmentTextureNode : public ImageSlotTextureNode {
@@ -129,24 +133,28 @@ class EnvironmentTextureNode : public ImageSlotTextureNode {
return NODE_GROUP_LEVEL_2;
}
- ImageManager *image_manager;
- int is_float;
- bool is_linear;
+ virtual bool equals(const ShaderNode &other)
+ {
+ const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other;
+ return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data &&
+ animated == env_node.animated;
+ }
+
+ /* Parameters. */
bool use_alpha;
ustring filename;
void *builtin_data;
- NodeImageColorSpace color_space;
+ ustring colorspace;
NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
float3 vector;
- virtual bool equals(const ShaderNode &other)
- {
- const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other;
- return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data &&
- animated == env_node.animated;
- }
+ /* Runtime. */
+ ImageManager *image_manager;
+ int is_float;
+ bool compress_as_srgb;
+ ustring known_colorspace;
};
class SkyTextureNode : public TextureNode {
@@ -319,15 +327,17 @@ class PointDensityTextureNode : public ShaderNode {
void add_image();
+ /* Parameters. */
ustring filename;
NodeTexVoxelSpace space;
InterpolationType interpolation;
Transform tfm;
float3 vector;
+ void *builtin_data;
+ /* Runtime. */
ImageManager *image_manager;
int slot;
- void *builtin_data;
virtual bool equals(const ShaderNode &other)
{
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 5ee453275b9..a65c8e9f338 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -16,6 +16,7 @@
#include "device/device.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/light.h"
#include "render/osl.h"
@@ -1205,25 +1206,29 @@ void OSLCompiler::compile(Scene *scene, Shader *shader)
osl_globals->bump_state.push_back(shader->osl_surface_bump_ref);
}
-void OSLCompiler::parameter_texture(const char *name, ustring filename, int svm_slot)
+void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
{
- if (svm_slot != -1) {
- /* It's not so simple to pass custom attribute to the texture() function
- * in order to make builtin images support more clear. So we use special
- * file name which is "@i<slot_number>" and use that for lookup in
- * in OSLRenderServices::texture(). */
- filename = string_printf("@i%d", svm_slot).c_str();
- osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
- }
- else {
- osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::OIIO));
- }
+ /* Textured loaded through the OpenImageIO texture cache. For this
+ * case we need to do runtime color space conversion. */
+ OSLTextureHandle *handle = new OSLTextureHandle(OSLTextureHandle::OIIO);
+ handle->processor = ColorSpaceManager::get_processor(colorspace);
+ osl_globals->textures.insert(filename, handle);
+ parameter(name, filename);
+}
+void OSLCompiler::parameter_texture(const char *name, int svm_slot)
+{
+ /* Texture loaded through SVM image texture system. We generate a unique
+ * name, which ends up being used in OSLRenderServices::get_texture_handle
+ * to get handle again. */
+ ustring filename(string_printf("@i%d", svm_slot).c_str());
+ osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
parameter(name, filename);
}
void OSLCompiler::parameter_texture_ies(const char *name, int svm_slot)
{
+ /* IES light textures stored in SVM. */
ustring filename(string_printf("@l%d", svm_slot).c_str());
osl_globals->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
parameter(name, filename);
@@ -1285,7 +1290,11 @@ void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float
void OSLCompiler::parameter_texture(const char * /* name */,
ustring /* filename */,
- int /* svm_slot */)
+ ustring /* colorspace */)
+{
+}
+
+void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
{
}
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 773252ce9dc..ac73f1d3c24 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -153,7 +153,8 @@ class OSLCompiler {
void parameter_attribute(const char *name, ustring s);
- void parameter_texture(const char *name, ustring filename, int svm_slot);
+ void parameter_texture(const char *name, ustring filename, ustring colorspace);
+ void parameter_texture(const char *name, int svm_slot);
void parameter_texture_ies(const char *name, int svm_slot);
ShaderType output_type()
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index ac3303cbfeb..ec85e516832 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include "device/device.h"
+
#include "render/background.h"
#include "render/camera.h"
-#include "device/device.h"
+#include "render/colorspace.h"
#include "render/graph.h"
#include "render/integrator.h"
#include "render/light.h"
@@ -717,6 +719,8 @@ void ShaderManager::free_memory()
#ifdef WITH_OSL
OSLShaderManager::free_memory();
#endif
+
+ ColorSpaceManager::free_memory();
}
float ShaderManager::linear_rgb_to_gray(float3 c)