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:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2019-04-23 14:56:30 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2019-05-13 16:56:10 +0300
commit7ad802cf3ae500bc72863b6dba0f28a488fce3d1 (patch)
treea1dd8b96c21a8ba51434933163b5792564006d55 /source/blender
parente9d2ec46c413718cd058abba84e2badd48542781 (diff)
Cycles/Eevee: unified and improved texture image color space handling
Cycles now uses the color space on the image datablock, and uses OpenColorIO to convert to scene linear as needed. Byte images do not take extra memory, they are compressed in scene linear + sRGB transfer function which in common cases is a no-op. Eevee and workbench were changed to work similar. Float images are stored as scene linear. Byte images are compressed as scene linear + sRGB and stored in a GL_SRGB8_ALPHA8 texture. From the GLSL shader side this means they are read as scene linear, simplifying the code and taking advantage of hardware support. Further, OpenGL image textures are now all stored with premultiplied alpha. Eevee texture sampling looks a little different now because interpolation happens premultiplied and in scene linear space. Overlays and grease pencil work in sRGB space so those now have an extra conversion to sRGB after reading from image textures. This is not particularly elegant but as long as engines use different conventions, one or the other needs to do conversion. This change breaks compatibility for cases where multiple image texture nodes were using the same image with different color space node settings. However it gives more predictable behavior for baking and texture painting if save, load and image editing operations have a single color space to handle. Differential Revision: https://developer.blender.org/D4807
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c35
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c6
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl25
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl27
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl25
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl30
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl3
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c3
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c9
-rw-r--r--source/blender/draw/intern/draw_manager_data.c3
-rw-r--r--source/blender/draw/modes/object_mode.c2
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c6
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl23
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_frag.glsl23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c16
-rw-r--r--source/blender/editors/space_node/drawnode.c12
-rw-r--r--source/blender/gpu/GPU_draw.h2
-rw-r--r--source/blender/gpu/GPU_material.h3
-rw-r--r--source/blender/gpu/GPU_texture.h5
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h2
-rw-r--r--source/blender/gpu/intern/gpu_draw.c472
-rw-r--r--source/blender/gpu/intern/gpu_material.c9
-rw-r--r--source/blender/gpu/intern/gpu_texture.c2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl47
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h13
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h7
-rw-r--r--source/blender/imbuf/intern/colormanagement.c91
-rw-r--r--source/blender/makesdna/DNA_image_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_color.c28
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c95
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c27
-rw-r--r--source/blender/nodes/shader/node_shader_util.h1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c23
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c47
38 files changed, 619 insertions, 522 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 16275c96eec..74d33a9c275 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 62
+#define BLENDER_SUBVERSION 63
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index 023bd685352..2bd379c6f19 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -38,6 +38,8 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "IMB_colormanagement.h"
+
#include "BLO_readfile.h"
#include "readfile.h"
@@ -262,6 +264,33 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
}
}
+static void image_node_colorspace(bNode *node)
+{
+ if (node->id == NULL) {
+ return;
+ }
+
+ int color_space;
+ if (node->type == SH_NODE_TEX_IMAGE) {
+ NodeTexImage *tex = node->storage;
+ color_space = tex->color_space;
+ }
+ else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
+ NodeTexEnvironment *tex = node->storage;
+ color_space = tex->color_space;
+ }
+ else {
+ return;
+ }
+
+ const int SHD_COLORSPACE_NONE = 0;
+ Image *image = (Image *)node->id;
+ if (color_space == SHD_COLORSPACE_NONE) {
+ STRNCPY(image->colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA));
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -326,6 +355,12 @@ void do_versions_after_linking_cycles(Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 279, 5)) {
ambient_occlusion_node_relink(ntree);
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 63)) {
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ image_node_colorspace(node);
+ }
+ }
}
FOREACH_NODETREE_END;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index c23b4c254e4..d57c43ab375 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -465,7 +465,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D, true);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0;
@@ -631,7 +631,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
BKE_image_release_ibuf(image, ibuf, NULL);
@@ -787,7 +787,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
BKE_image_release_ibuf(image, ibuf, NULL);
}
else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true);
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "myTexture", texture);
BKE_image_release_ibuf(image, ibuf, NULL);
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
index acf60fc2d59..80fae9ab518 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -89,6 +89,27 @@ void set_color(in vec4 color,
ocolor.a *= layer_opacity;
}
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308) {
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ }
+ else {
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+ }
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, vec2 co)
+{
+ /* By convention image textures return scene linear colors, but
+ * grease pencil still works in srgb. */
+ vec4 color = texture2D(tex, co);
+ color.r = linearrgb_to_srgb(color.r);
+ color.g = linearrgb_to_srgb(color.g);
+ color.b = linearrgb_to_srgb(color.b);
+ return color;
+}
+
void main()
{
vec2 t_center = vec2(0.5, 0.5);
@@ -97,8 +118,8 @@ void main()
vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset;
vec4 tmp_color;
tmp_color = (texture_clamp == 0) ?
- texture2D(myTexture, rot_tex * texture_scale) :
- texture2D(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0));
+ texture_read_as_srgb(myTexture, rot_tex * texture_scale) :
+ texture_read_as_srgb(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0));
vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity);
vec4 chesscolor;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
index cc47e12b303..98c47b1f1f0 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
@@ -47,6 +47,27 @@ vec2 check_box_point(vec2 pt, vec2 radius)
return rtn;
}
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308) {
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ }
+ else {
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+ }
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, vec2 co)
+{
+ /* By convention image textures return scene linear colors, but
+ * grease pencil still works in srgb. */
+ vec4 color = texture2D(tex, co);
+ color.r = linearrgb_to_srgb(color.r);
+ color.g = linearrgb_to_srgb(color.g);
+ color.b = linearrgb_to_srgb(color.b);
+ return color;
+}
+
void main()
{
vec2 centered = mTexCoord - vec2(0.5);
@@ -65,7 +86,7 @@ void main()
}
}
- vec4 tmp_color = texture2D(myTexture, mTexCoord);
+ vec4 tmp_color = texture_read_as_srgb(myTexture, mTexCoord);
/* Solid */
if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) {
@@ -73,7 +94,7 @@ void main()
}
/* texture */
if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) {
- vec4 text_color = texture2D(myTexture, mTexCoord);
+ vec4 text_color = texture_read_as_srgb(myTexture, mTexCoord);
if (mix_stroke_factor > 0.0) {
fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor);
fragColor.a = text_color.a;
@@ -87,7 +108,7 @@ void main()
}
/* pattern */
if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) {
- vec4 text_color = texture2D(myTexture, mTexCoord);
+ vec4 text_color = texture_read_as_srgb(myTexture, mTexCoord);
fragColor = mColor;
/* mult both alpha factor to use strength factor with color alpha limit */
fragColor.a = min(text_color.a * mColor.a, mColor.a);
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
index 6b7cee888ea..6b3fcad1240 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
@@ -27,6 +27,27 @@ out vec4 fragColor;
bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308) {
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ }
+ else {
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+ }
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, vec2 co)
+{
+ /* By convention image textures return scene linear colors, but
+ * grease pencil still works in srgb. */
+ vec4 color = texture2D(tex, co);
+ color.r = linearrgb_to_srgb(color.r);
+ color.g = linearrgb_to_srgb(color.g);
+ color.b = linearrgb_to_srgb(color.b);
+ return color;
+}
+
void main()
{
@@ -47,10 +68,10 @@ void main()
/* texture for endcaps */
vec4 text_color;
if (uvfac[1] == ENDCAP) {
- text_color = texture2D(myTexture, vec2(mTexCoord.x, mTexCoord.y));
+ text_color = texture_read_as_srgb(myTexture, vec2(mTexCoord.x, mTexCoord.y));
}
else {
- text_color = texture2D(myTexture, mTexCoord);
+ text_color = texture_read_as_srgb(myTexture, mTexCoord);
}
/* texture */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index c76ad8c1d7b..96f8f6e4c7a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -140,32 +140,18 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
return matcap_uv * 0.496 + 0.5;
}
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045) {
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- }
- else {
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
- }
-}
-
-vec4 srgb_to_linearrgb(vec4 col_from)
-{
- vec4 col_to;
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
- col_to.a = col_from.a;
- return col_to;
-}
-
-vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool srgb, bool nearest_sampling)
+vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
{
vec2 tex_size = vec2(textureSize(image, 0).xy);
/* TODO(fclem) We could do the same with sampler objects.
* But this is a quick workaround instead of messing with the GPUTexture itself. */
vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
vec4 color = texture(image, uv);
- return (srgb) ? srgb_to_linearrgb(color) : color;
+
+ /* Unpremultiply, ideally shaders would be added so this is not needed. */
+ if (!(color.a == 0.0 || color.a == 1.0)) {
+ color.rgb = color.rgb / color.a;
+ }
+
+ return color;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index 32243787401..51bce639b63 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -1,7 +1,6 @@
uniform float ImageTransparencyCutoff = 0.1;
uniform sampler2D image;
-uniform bool imageSrgb;
uniform bool imageNearest;
uniform float alpha = 0.5;
@@ -44,7 +43,7 @@ void main()
vec4 diffuse_color;
#if defined(V3D_SHADING_TEXTURE_COLOR)
- diffuse_color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest);
+ diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest);
if (diffuse_color.a < ImageTransparencyCutoff) {
discard;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index 2596fc4cf88..af9f1d14f4a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -6,7 +6,6 @@ uniform float materialRoughness;
uniform sampler2D image;
uniform float ImageTransparencyCutoff = 0.1;
-uniform bool imageSrgb;
uniform bool imageNearest;
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
@@ -41,7 +40,7 @@ void main()
vec4 color;
# if defined(V3D_SHADING_TEXTURE_COLOR)
- color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest);
+ color = workbench_sample_texture(image, uv_interp, imageNearest);
if (color.a < ImageTransparencyCutoff) {
discard;
}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 25f95f0d4bc..13bd6fe9e4d 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -202,8 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
V3D_SHADING_TEXTURE_COLOR) {
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh,
psl->object_outline_pass);
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, GL_TEXTURE_2D, false);
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
}
else {
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index c403e358d6a..b280b6fd01a 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -294,15 +294,8 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
if (workbench_material_determine_color_type(wpd, material->ima, ob, false) ==
V3D_SHADING_TEXTURE_COLOR) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(material->ima, material->iuser, NULL);
- const bool do_color_correction = wpd->use_color_management &&
- (ibuf &&
- (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0);
- BKE_image_release_ibuf(material->ima, ibuf, NULL);
- GPUTexture *tex = GPU_texture_from_blender(
- material->ima, material->iuser, GL_TEXTURE_2D, false);
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "image", tex);
- DRW_shgroup_uniform_bool_copy(grp, "imageSrgb", do_color_correction);
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
}
else {
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 1f48129116d..0375db12255 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1009,8 +1009,7 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp,
if (input->ima) {
GPUTexture **tex_ref = BLI_memblock_alloc(DST.vmempool->images);
- *tex_ref = tex = GPU_texture_from_blender(
- input->ima, input->iuser, GL_TEXTURE_2D, input->image_isdata);
+ *tex_ref = tex = GPU_texture_from_blender(input->ima, input->iuser, GL_TEXTURE_2D);
GPU_texture_ref(tex);
}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index cc313620a11..9d6732fbcab 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -988,7 +988,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data,
GPUTexture *tex = NULL;
if (ob->data != NULL) {
- tex = GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false);
+ tex = GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D);
if (tex) {
size[0] = GPU_texture_width(tex);
size[1] = GPU_texture_height(tex);
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
index 123dc7fca88..da32744b9ea 100644
--- a/source/blender/draw/modes/paint_texture_mode.c
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -182,7 +182,7 @@ static DRWShadingGroup *create_texture_paint_shading_group(PAINT_TEXTURE_PassLis
if (masking_enabled) {
const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0;
- GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D, false);
+ GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
DRW_shgroup_uniform_texture(grp, "maskingImage", stencil);
DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1);
DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted);
@@ -236,7 +236,7 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
NULL;
int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp :
0;
- GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false);
+ GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D);
if (tex) {
DRWShadingGroup *grp = create_texture_paint_shading_group(
@@ -250,7 +250,7 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
}
else {
Image *ima = imapaint->canvas;
- GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false);
+ GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D);
if (tex) {
DRWShadingGroup *grp = create_texture_paint_shading_group(
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
index 386d05636f9..dbc403dc39b 100644
--- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -14,12 +14,33 @@ uniform sampler2D image;
uniform int depthMode;
uniform bool useAlphaTest;
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308) {
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ }
+ else {
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+ }
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, vec2 co)
+{
+ /* By convention image textures return scene linear colors, but
+ * overlays still assume srgb. */
+ vec4 color = texture2D(tex, co);
+ color.r = linearrgb_to_srgb(color.r);
+ color.g = linearrgb_to_srgb(color.g);
+ color.b = linearrgb_to_srgb(color.b);
+ return color;
+}
+
void main()
{
#ifdef USE_WIRE
fragColor = finalColor;
#else
- vec4 tex_col = texture(image, texCoord_interp);
+ vec4 tex_col = texture_read_as_srgb(image, texCoord_interp);
fragColor = finalColor * tex_col;
if (useAlphaTest) {
diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
index c7e110122c5..5d74213a445 100644
--- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl
+++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
@@ -16,6 +16,27 @@ uniform vec3 maskingColor;
uniform bool maskingInvertStencil;
#endif
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308) {
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ }
+ else {
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+ }
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, vec2 co)
+{
+ /* By convention image textures return scene linear colors, but
+ * overlays still assume srgb. */
+ vec4 color = texture2D(tex, co);
+ color.r = linearrgb_to_srgb(color.r);
+ color.g = linearrgb_to_srgb(color.g);
+ color.b = linearrgb_to_srgb(color.b);
+ return color;
+}
+
void main()
{
vec2 uv = uv_interp;
@@ -24,7 +45,7 @@ void main()
uv = (floor(uv_interp * tex_size) + 0.5) / tex_size;
}
- vec4 color = texture(image, uv);
+ vec4 color = texture_read_as_srgb(image, uv);
color.a *= alpha;
#ifdef TEXTURE_PAINT_MASK
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 0340a4989e1..9cc12b41a63 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -6394,7 +6394,7 @@ static const EnumPropertyItem layer_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
-static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
+static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
{
Image *ima;
float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
@@ -6417,6 +6417,11 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
ima = BKE_image_add_generated(
bmain, width, height, imagename, alpha ? 32 : 24, use_float, gen_type, color, false);
+ if (is_data) {
+ STRNCPY(ima->colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA));
+ }
+
return ima;
}
@@ -6487,6 +6492,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
if (ma) {
Main *bmain = CTX_data_main(C);
int type = RNA_enum_get(op->ptr, "type");
+ bool is_data = (type > LAYER_BASE_COLOR);
bNode *imanode;
bNodeTree *ntree = ma->nodetree;
@@ -6501,7 +6507,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
/* try to add an image node */
imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
- ima = proj_paint_image_create(op, bmain);
+ ima = proj_paint_image_create(op, bmain, is_data);
imanode->id = &ima->id;
nodeSetActive(ntree, imanode);
@@ -6553,12 +6559,6 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- if (type > LAYER_BASE_COLOR) {
- /* This is a "non color data" image */
- NodeTexImage *tex = imanode->storage;
- tex->color_space = SHD_COLORSPACE_NONE;
- }
-
/* Check if the socket in already connected to something */
bNodeLink *link = in_sock ? in_sock->link : NULL;
if (in_sock != NULL && link == NULL) {
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 447fea8098c..bf6ec961a5d 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -708,6 +708,11 @@ static void node_buts_image_user(uiLayout *layout,
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
}
+
+ uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
+ PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
+ uiItemL(split, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
}
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -782,7 +787,6 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
NULL,
UI_TEMPLATE_ID_FILTER_ALL,
false);
- uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -820,11 +824,10 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
UI_TEMPLATE_ID_FILTER_ALL,
false);
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
-
- uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
}
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -875,7 +878,6 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiTemplateImageInfo(layout, C, ima, iuserptr.data);
}
- uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
}
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 300fc7c65a2..eb54ff127d8 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -84,7 +84,7 @@ void GPU_create_gl_tex(unsigned int *bind,
int recth,
int textarget,
bool mipmap,
- bool use_hight_bit_depth,
+ bool use_srgb,
struct Image *ima);
void GPU_create_gl_tex_compressed(unsigned int *bind,
unsigned int *pix,
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 1640209c717..86c9764a68f 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -145,7 +145,7 @@ typedef enum eGPUMaterialStatus {
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_constant(float *num);
GPUNodeLink *GPU_uniform(float *num);
-GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
+GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
@@ -202,7 +202,6 @@ struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void);
void GPU_material_vertex_attrs(GPUMaterial *material, struct GPUVertAttrLayers *attrs);
-bool GPU_material_do_color_management(GPUMaterial *mat);
bool GPU_material_use_domain_surface(GPUMaterial *mat);
bool GPU_material_use_domain_volume(GPUMaterial *mat);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 3527398a396..3fb7dfc6331 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -186,10 +186,7 @@ GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert);
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer);
GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
-GPUTexture *GPU_texture_from_blender(struct Image *ima,
- struct ImageUser *iuser,
- int textarget,
- bool is_data);
+GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
void GPU_texture_add_mipmap(GPUTexture *tex,
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index a2c1a01a82c..6259780c261 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1503,7 +1503,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->source = GPU_SOURCE_TEX;
input->ima = link->ima;
input->iuser = link->iuser;
- input->image_isdata = link->image_isdata;
break;
case GPU_NODE_LINK_ATTR:
input->source = GPU_SOURCE_ATTR;
@@ -1748,13 +1747,12 @@ GPUNodeLink *GPU_uniform(float *num)
return link;
}
-GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
+GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser)
{
GPUNodeLink *link = GPU_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE_BLENDER;
link->ima = ima;
link->iuser = iuser;
- link->image_isdata = is_data;
return link;
}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 73155c3aafa..d1bb3f26920 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -99,7 +99,6 @@ struct GPUNodeLink {
struct {
struct Image *ima;
struct ImageUser *iuser;
- bool image_isdata;
};
};
};
@@ -137,7 +136,6 @@ typedef struct GPUInput {
struct GPUTexture **coba; /* input texture, only set at runtime */
struct Image *ima; /* image */
struct ImageUser *iuser; /* image user */
- bool image_isdata; /* image does not contain color data */
bool bindtex; /* input is responsible for binding the texture? */
int texid; /* number for multitexture, starting from zero */
eGPUType textype; /* texture type (2D, 1D Array ...) */
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index edc2f2171a5..f1c82dc53a7 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -50,6 +50,7 @@
#include "MEM_guardedalloc.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -207,53 +208,232 @@ static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget)
return NULL;
}
-typedef struct VerifyThreadData {
- ImBuf *ibuf;
- float *srgb_frect;
-} VerifyThreadData;
+static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
+{
+ uint bindcode = 0;
+ const bool mipmap = GPU_get_mipmap();
+
+#ifdef WITH_DDS
+ if (ibuf->ftype == IMB_FTYPE_DDS) {
+ /* DDS is loaded directly in compressed form. */
+ GPU_create_gl_tex_compressed(
+ &bindcode, ibuf->rect, ibuf->x, ibuf->y, textarget, mipmap, ima, ibuf);
+ return bindcode;
+ }
+#endif
+
+ /* Regular uncompressed texture. */
+ float *rect_float = ibuf->rect_float;
+ uchar *rect = (uchar *)ibuf->rect;
+ bool compress_as_srgb = false;
+
+ if (rect_float == NULL) {
+ /* Byte image is in original colorspace from the file. If the file is sRGB
+ * scene linear, or non-color data no conversion is needed. Otherwise we
+ * compress as scene linear + sRGB transfer function to avoid precision loss
+ * in common cases.
+ *
+ * We must also convert to premultiplied for correct texture interpolation
+ * and consistency with float images. */
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace);
+
+ rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
+ if (rect == NULL) {
+ return bindcode;
+ }
+
+ IMB_colormanagement_imbuf_to_srgb_texture(
+ rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb);
+ }
+ }
+ else if (ibuf->channels != 4) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
+ if (rect_float == NULL) {
+ return bindcode;
+ }
-static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
- ImBuf *ibuf,
- const int start_line,
- const int height)
+ IMB_buffer_float_from_float(rect_float,
+ ibuf->rect_float,
+ ibuf->channels,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_LINEAR_RGB,
+ false,
+ ibuf->x,
+ ibuf->y,
+ ibuf->x,
+ ibuf->x);
+ }
+
+ /* Create OpenGL texture. */
+ GPU_create_gl_tex(&bindcode,
+ (uint *)rect,
+ rect_float,
+ ibuf->x,
+ ibuf->y,
+ textarget,
+ mipmap,
+ compress_as_srgb,
+ ima);
+
+ /* Free buffers if needed. */
+ if (rect && rect != (uchar *)ibuf->rect) {
+ MEM_freeN(rect);
+ }
+ if (rect_float && rect_float != ibuf->rect_float) {
+ MEM_freeN(rect_float);
+ }
+
+ return bindcode;
+}
+
+static void gpu_texture_update_scaled(
+ uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
{
- size_t offset = ibuf->channels * start_line * ibuf->x;
- float *current_srgb_frect = srgb_frect + offset;
- float *current_rect_float = ibuf->rect_float + offset;
- IMB_buffer_float_from_float(current_srgb_frect,
- current_rect_float,
- ibuf->channels,
- IB_PROFILE_SRGB,
- IB_PROFILE_LINEAR_RGB,
- true,
- ibuf->x,
- height,
- ibuf->x,
- ibuf->x);
- IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
+ /* Partial update with scaling. */
+ int limit_w = smaller_power_of_2_limit(full_w);
+ int limit_h = smaller_power_of_2_limit(full_h);
+ float xratio = limit_w / (float)full_w;
+ float yratio = limit_h / (float)full_h;
+
+ /* Find sub coordinates in scaled image. Take ceiling because we will be
+ * losing 1 pixel due to rounding errors in x,y. */
+ int sub_x = x * xratio;
+ int sub_y = y * yratio;
+ int sub_w = (int)ceil(xratio * w);
+ int sub_h = (int)ceil(yratio * h);
+
+ /* ...but take back if we are over the limit! */
+ if (sub_w + sub_x > limit_w) {
+ sub_w--;
+ }
+ if (sub_h + sub_y > limit_h) {
+ sub_h--;
+ }
+
+ /* Scale pixels. */
+ ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h);
+ IMB_scaleImBuf(ibuf, sub_w, sub_h);
+
+ if (ibuf->rect_float) {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+ }
+ else {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+
+ IMB_freeImBuf(ibuf);
}
-static void verify_thread_do(void *data_v, int start_scanline, int num_scanlines)
+static void gpu_texture_update_unscaled(
+ uchar *rect, float *rect_float, int x, int y, int w, int h, GLint tex_stride, GLint tex_offset)
{
- VerifyThreadData *data = (VerifyThreadData *)data_v;
- gpu_verify_high_bit_srgb_buffer_slice(
- data->srgb_frect, data->ibuf, start_scanline, num_scanlines);
+ /* Partial update without scaling. Stride and offset are used to copy only a
+ * subset of a possible larger buffer than what we are updating. */
+ GLint row_length;
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, tex_stride);
+
+ if (rect_float == NULL) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset);
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset);
+ }
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
}
-static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect, ImBuf *ibuf)
+static void gpu_texture_update_from_ibuf(ImBuf *ibuf, int x, int y, int w, int h)
{
- if (ibuf->y < 64) {
- gpu_verify_high_bit_srgb_buffer_slice(srgb_frect, ibuf, 0, ibuf->y);
+ /* Partial update of texture for texture painting. This is often much
+ * quicker than fully updating the texture for high resolution images.
+ * Assumes the OpenGL texture is bound to 0. */
+ const bool scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y);
+
+ if (scaled) {
+ /* Extra padding to account for bleed from neighboring pixels. */
+ const int padding = 4;
+ const int xmax = min_ii(x + w + padding, ibuf->x);
+ const int ymax = min_ii(y + h + padding, ibuf->y);
+ x = max_ii(x - padding, 0);
+ y = max_ii(y - padding, 0);
+ w = xmax - x;
+ h = ymax - y;
+ }
+
+ /* Get texture data pointers. */
+ float *rect_float = ibuf->rect_float;
+ uchar *rect = (uchar *)ibuf->rect;
+ GLint tex_stride = ibuf->x;
+ GLint tex_offset = ibuf->channels * (y * ibuf->x + x);
+
+ if (rect_float == NULL) {
+ /* Byte pixels. */
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
+ ibuf->rect_colorspace);
+
+ rect = MEM_mallocN(sizeof(uchar) * 4 * w * h, __func__);
+ if (rect == NULL) {
+ return;
+ }
+
+ tex_stride = w;
+ tex_offset = 0;
+
+ /* Convert to scene linear with sRGB compression, and premultiplied for
+ * correct texture interpolation. */
+ IMB_colormanagement_imbuf_to_srgb_texture(rect, x, y, w, h, ibuf, compress_as_srgb);
+ }
+ }
+ else if (ibuf->channels != 4 || scaled) {
+ /* Float pixels. */
+ rect_float = MEM_mallocN(sizeof(float) * 4 * x * y, __func__);
+ if (rect_float == NULL) {
+ return;
+ }
+
+ tex_stride = w;
+ tex_offset = 0;
+
+ size_t ibuf_offset = (y * ibuf->x + x) * ibuf->channels;
+ IMB_buffer_float_from_float(rect_float,
+ ibuf->rect_float + ibuf_offset,
+ ibuf->channels,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_LINEAR_RGB,
+ false,
+ w,
+ h,
+ x,
+ ibuf->x);
+ }
+
+ if (scaled) {
+ /* Slower update where we first have to scale the input pixels. */
+ gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h);
}
else {
- VerifyThreadData data;
- data.ibuf = ibuf;
- data.srgb_frect = srgb_frect;
- IMB_processor_apply_threaded_scanlines(ibuf->y, verify_thread_do, &data);
+ /* Fast update at same resolution. */
+ gpu_texture_update_unscaled(rect, rect_float, x, y, w, h, tex_stride, tex_offset);
+ }
+
+ /* Free buffers if needed. */
+ if (rect && rect != (uchar *)ibuf->rect) {
+ MEM_freeN(rect);
+ }
+ if (rect_float && rect_float != ibuf->rect_float) {
+ MEM_freeN(rect_float);
}
}
-GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data)
+GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget)
{
if (ima == NULL) {
return NULL;
@@ -286,62 +466,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
return *tex;
}
- /* flag to determine whether deep format is used */
- bool use_high_bit_depth = false, do_color_management = false;
-
- if (ibuf->rect_float) {
- use_high_bit_depth = true;
-
- /* TODO unneeded when float images are correctly treated as linear always */
- if (!is_data) {
- do_color_management = true;
- }
- }
-
- const int rectw = ibuf->x;
- const int recth = ibuf->y;
- uint *rect = ibuf->rect;
- float *frect = NULL;
- float *srgb_frect = NULL;
-
- if (use_high_bit_depth) {
- if (do_color_management) {
- frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4,
- "floar_buf_col_cor");
- gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
- }
- else {
- frect = ibuf->rect_float;
- }
- }
-
- const bool mipmap = GPU_get_mipmap();
-
-#ifdef WITH_DDS
- if (ibuf->ftype == IMB_FTYPE_DDS) {
- GPU_create_gl_tex_compressed(&bindcode, rect, rectw, recth, textarget, mipmap, ima, ibuf);
- }
- else
-#endif
- {
- GPU_create_gl_tex(
- &bindcode, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
- }
-
- /* mark as non-color data texture */
- if (bindcode) {
- if (is_data) {
- ima->gpuflag |= IMA_GPU_IS_DATA;
- }
- else {
- ima->gpuflag &= ~IMA_GPU_IS_DATA;
- }
- }
-
- /* clean up */
- if (srgb_frect) {
- MEM_freeN(srgb_frect);
- }
+ bindcode = gpu_texture_create_from_ibuf(ima, ibuf, textarget);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -349,15 +474,14 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
return *tex;
}
-static void **gpu_gen_cube_map(
- uint *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
+static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth)
{
- size_t block_size = use_high_bit_depth ? sizeof(float[4]) : sizeof(uchar[4]);
+ size_t block_size = frect ? sizeof(float[4]) : sizeof(uchar[4]);
void **sides = NULL;
int h = recth / 2;
int w = rectw / 3;
- if ((use_high_bit_depth && frect == NULL) || (!use_high_bit_depth && rect == NULL) || w != h) {
+ if (w != h) {
return sides;
}
@@ -376,7 +500,7 @@ static void **gpu_gen_cube_map(
* | NegZ | PosZ | PosY |
* |______|______|______|
*/
- if (use_high_bit_depth) {
+ if (frect) {
float(*frectb)[4] = (float(*)[4])frect;
float(**fsides)[4] = (float(**)[4])sides;
@@ -430,7 +554,7 @@ void GPU_create_gl_tex(uint *bind,
int recth,
int textarget,
bool mipmap,
- bool use_high_bit_depth,
+ bool use_srgb,
Image *ima)
{
ImBuf *ibuf = NULL;
@@ -441,7 +565,7 @@ void GPU_create_gl_tex(uint *bind,
rectw = smaller_power_of_2_limit(rectw);
recth = smaller_power_of_2_limit(recth);
- if (use_high_bit_depth) {
+ if (frect) {
ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
IMB_scaleImBuf(ibuf, rectw, recth);
@@ -459,12 +583,15 @@ void GPU_create_gl_tex(uint *bind,
glGenTextures(1, (GLuint *)bind);
glBindTexture(textarget, *bind);
+ GLenum internal_format = (frect) ? GL_RGBA16F : (use_srgb) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
+
if (textarget == GL_TEXTURE_2D) {
- if (use_high_bit_depth) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
+ if (frect) {
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
}
else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
@@ -484,15 +611,14 @@ void GPU_create_gl_tex(uint *bind,
int w = rectw / 3, h = recth / 2;
if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
- void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth);
- GLenum informat = use_high_bit_depth ? GL_RGBA16F : GL_RGBA8;
- GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE;
+ void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth);
+ GLenum type = frect ? GL_FLOAT : GL_UNSIGNED_BYTE;
if (cube_map) {
for (int i = 0; i < 6; i++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0,
- informat,
+ internal_format,
w,
h,
0,
@@ -617,14 +743,14 @@ void GPU_create_gl_tex_compressed(
#ifndef WITH_DDS
(void)ibuf;
/* Fall back to uncompressed if DDS isn't enabled */
- GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
+ GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, true, ima);
#else
glGenTextures(1, (GLuint *)bind);
glBindTexture(textarget, *bind);
if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf) == 0) {
glDeleteTextures(1, (GLuint *)bind);
- GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
+ GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, true, ima);
}
glBindTexture(textarget, 0);
@@ -680,146 +806,20 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
}
}
-/* check if image has been downscaled and do scaled partial update */
-static bool gpu_check_scaled_image(
- ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
-{
- if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
- int x_limit = smaller_power_of_2_limit(ibuf->x);
- int y_limit = smaller_power_of_2_limit(ibuf->y);
-
- float xratio = x_limit / (float)ibuf->x;
- float yratio = y_limit / (float)ibuf->y;
-
- /* find new width, height and x,y gpu texture coordinates */
-
- /* take ceiling because we will be losing 1 pixel due to rounding errors in x,y... */
- int rectw = (int)ceil(xratio * w);
- int recth = (int)ceil(yratio * h);
-
- x *= xratio;
- y *= yratio;
-
- /* ...but take back if we are over the limit! */
- if (rectw + x > x_limit) {
- rectw--;
- }
- if (recth + y > y_limit) {
- recth--;
- }
-
- GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
-
- /* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
- if (frect) {
- ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h);
- IMB_scaleImBuf(ibuf_scale, rectw, recth);
-
- glTexSubImage2D(
- GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA, GL_FLOAT, ibuf_scale->rect_float);
-
- IMB_freeImBuf(ibuf_scale);
- }
- /* byte images are not continuous in memory so do manual interpolation */
- else {
- uchar *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect");
- uint *p = (uint *)scalerect;
- int i, j;
- float inv_xratio = 1.0f / xratio;
- float inv_yratio = 1.0f / yratio;
- for (i = 0; i < rectw; i++) {
- float u = (x + i) * inv_xratio;
- for (j = 0; j < recth; j++) {
- float v = (y + j) * inv_yratio;
- bilinear_interpolation_color_wrap(ibuf, (uchar *)(p + i + j * (rectw)), NULL, u, v);
- }
- }
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, scalerect);
-
- MEM_freeN(scalerect);
- }
-
- if (GPU_get_mipmap()) {
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
-
- GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
-
- return true;
- }
-
- return false;
-}
-
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if ((ima->gputexture[TEXTARGET_TEXTURE_2D] == NULL) || (ibuf == NULL) || (w == 0) || (h == 0)) {
- /* these cases require full reload still */
+ /* Full reload of texture. */
GPU_free_image(ima);
}
else {
- /* for the special case, we can do a partial update
- * which is much quicker for painting */
- GLint row_length, skip_pixels, skip_rows;
-
- /* if color correction is needed, we must update the part that needs updating. */
- if (ibuf->rect_float) {
- float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
- bool is_data = (ima->gpuflag & IMA_GPU_IS_DATA) != 0;
- IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
-
- if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
- MEM_freeN(buffer);
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
-
- MEM_freeN(buffer);
-
- if (GPU_get_mipmap()) {
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
-
- GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
+ /* Partial update of texture. */
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
- glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
- glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
- glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+ gpu_texture_update_from_ibuf(ibuf, x, y, w, h);
- /* see comment above as to why we are using gpu mipmap generation here */
if (GPU_get_mipmap()) {
glGenerateMipmap(GL_TEXTURE_2D);
}
@@ -1242,7 +1242,7 @@ static void gpu_free_image_immediate(Image *ima)
}
}
- ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_IS_DATA);
+ ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE);
}
void GPU_free_image(Image *ima)
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 1a668a48eed..6aa13b0d8ca 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -597,15 +597,6 @@ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
/* Code generation */
-bool GPU_material_do_color_management(GPUMaterial *mat)
-{
- if (!BKE_scene_check_color_management_enabled(mat->scene)) {
- return false;
- }
-
- return true;
-}
-
bool GPU_material_use_domain_surface(GPUMaterial *mat)
{
return (mat->domain & GPU_DOMAIN_SURFACE);
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index ad4831ed903..58d0dd5576f 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1081,7 +1081,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
/* this binds a texture, so that's why we restore it to 0 */
if (bindcode == 0) {
GPU_create_gl_tex(
- &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, 0, NULL);
+ &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL);
}
if (tex) {
tex->bindcode = bindcode;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 2f80bc95a0c..5596940cbf6 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -117,38 +117,6 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
outcol = vec4(rgb, hsv.w);
}
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045)
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- else
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
-}
-
-float linearrgb_to_srgb(float c)
-{
- if (c < 0.0031308)
- return (c < 0.0) ? 0.0 : c * 12.92;
- else
- return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-}
-
-void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
-{
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
- col_to.a = col_from.a;
-}
-
-void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
-{
- col_to.r = linearrgb_to_srgb(col_from.r);
- col_to.g = linearrgb_to_srgb(col_from.g);
- col_to.b = linearrgb_to_srgb(col_from.b);
- col_to.a = col_from.a;
-}
-
void color_to_normal_new_shading(vec3 color, out vec3 normal)
{
normal = vec3(2.0) * color - vec3(1.0);
@@ -2330,6 +2298,21 @@ void node_tex_environment_empty(vec3 co, out vec4 color)
/* 16bits floats limits. Higher/Lower values produce +/-inf. */
#define safe_color(a) (clamp(a, -65520.0, 65520.0))
+void tex_color_alpha_clear(vec4 color, out vec4 result)
+{
+ result = vec4(color.rgb, 1.0);
+}
+
+void tex_color_alpha_unpremultiply(vec4 color, out vec4 result)
+{
+ if (color.a == 0.0 || color.a == 1.0) {
+ result = vec4(color.rgb, 1.0);
+ }
+ else {
+ result = vec4(color.rgb / color.a, 1.0);
+ }
+}
+
void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
{
color = safe_color(texture(ima, co.xy));
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 620f8984d9f..e683d38a0aa 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -58,6 +58,10 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *
const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf);
const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf);
+bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace);
+bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
+bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
+
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormangement_xyz_to_rgb(float rgb[3], const float xyz[3]);
@@ -124,6 +128,14 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
struct ColorSpace *colorspace,
bool predivide);
+void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *rect,
+ const int x,
+ const int y,
+ const int width,
+ const int height,
+ const struct ImBuf *ibuf,
+ const bool compress_as_srgb);
+
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
@@ -340,6 +352,7 @@ enum {
COLOR_ROLE_DEFAULT_SEQUENCER,
COLOR_ROLE_DEFAULT_BYTE,
COLOR_ROLE_DEFAULT_FLOAT,
+ COLOR_ROLE_DATA,
};
#include "intern/colormanagement_inline.c"
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index 2566016ffdd..a83f2d60b8c 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -48,6 +48,13 @@ typedef struct ColorSpace {
bool is_invertible;
bool is_data;
+
+ /* Additional info computed only when needed since it's not cheap. */
+ struct {
+ bool cached;
+ bool is_srgb;
+ bool is_scene_linear;
+ } info;
} ColorSpace;
typedef struct ColorManagedDisplay {
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index f31d4ede693..b460d268d38 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -65,6 +65,7 @@
#define DISPLAY_BUFFER_CHANNELS 4
/* ** list of all supported color spaces, displays and views */
+static char global_role_data[MAX_COLORSPACE_NAME];
static char global_role_scene_linear[MAX_COLORSPACE_NAME];
static char global_role_color_picking[MAX_COLORSPACE_NAME];
static char global_role_texture_painting[MAX_COLORSPACE_NAME];
@@ -488,6 +489,7 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
const char *name;
/* get roles */
+ colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, NULL);
colormanage_role_color_space_name_get(
config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL);
colormanage_role_color_space_name_get(
@@ -1260,6 +1262,8 @@ void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *di
const char *IMB_colormanagement_role_colorspace_name_get(int role)
{
switch (role) {
+ case COLOR_ROLE_DATA:
+ return global_role_data;
case COLOR_ROLE_SCENE_LINEAR:
return global_role_scene_linear;
case COLOR_ROLE_COLOR_PICKING:
@@ -1341,6 +1345,42 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
}
}
+bool IMB_colormanagement_space_is_data(ColorSpace *colorspace)
+{
+ return (colorspace && colorspace->is_data);
+}
+
+static void colormanage_ensure_srgb_scene_linear_info(ColorSpace *colorspace)
+{
+ if (!colorspace->info.cached) {
+ OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
+ OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config,
+ colorspace->name);
+
+ bool is_scene_linear, is_srgb;
+ OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb);
+
+ OCIO_colorSpaceRelease(ocio_colorspace);
+ OCIO_configRelease(config);
+
+ colorspace->info.is_scene_linear = is_scene_linear;
+ colorspace->info.is_srgb = is_srgb;
+ colorspace->info.cached = true;
+ }
+}
+
+bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace)
+{
+ colormanage_ensure_srgb_scene_linear_info(colorspace);
+ return (colorspace && colorspace->info.is_scene_linear);
+}
+
+bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace)
+{
+ colormanage_ensure_srgb_scene_linear_info(colorspace);
+ return (colorspace && colorspace->info.is_srgb);
+}
+
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
@@ -2111,6 +2151,57 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
}
}
+void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer,
+ const int offset_x,
+ const int offset_y,
+ const int width,
+ const int height,
+ const struct ImBuf *ibuf,
+ const bool compress_as_srgb)
+{
+ /* Convert byte buffer for texture storage on the GPU. These have builtin
+ * support for converting sRGB to linear, which allows us to store textures
+ * without precision or performance loss at minimal memory usage. */
+ BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+
+ OCIO_ConstProcessorRcPtr *processor = NULL;
+ if (compress_as_srgb && ibuf->rect_colorspace &&
+ !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ processor = colorspace_to_scene_linear_processor(ibuf->rect_colorspace);
+ }
+
+ /* TODO(brecht): make this multithreaded, or at least process in batches. */
+ const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const unsigned char *in = in_buffer + in_offset * 4;
+ unsigned char *out = out_buffer + out_offset * 4;
+
+ if (processor) {
+ /* Convert to scene linear, to sRGB and premultiply. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ float pixel[4];
+ rgba_uchar_to_float(pixel, in);
+ OCIO_processorApplyRGB(processor, pixel);
+ linearrgb_to_srgb_v3_v3(pixel, pixel);
+ mul_v3_fl(pixel, pixel[3]);
+ rgba_float_to_uchar(out, pixel);
+ }
+ }
+ else {
+ /* Premultiply only. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ out[0] = (in[0] * in[3]) >> 8;
+ out[1] = (in[1] * in[3]) >> 8;
+ out[2] = (in[2] * in[3]) >> 8;
+ out[3] = in[3];
+ }
+ }
+ }
+}
+
/* Conversion between color picking role. Typically we would expect such a
* requirements:
* - It is approximately perceptually linear, so that the HSV numbers and
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index fec5f96b4f3..0aceeda20d5 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -191,8 +191,6 @@ enum {
IMA_GPU_REFRESH = (1 << 0),
/** All mipmap levels in OpenGL texture set? */
IMA_GPU_MIPMAP_COMPLETE = (1 << 1),
- /** OpenGL image texture bound as non-color data. */
- IMA_GPU_IS_DATA = (1 << 2),
};
/* ima->type and ima->source moved to BKE_image.h, for API */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 226e1d2f841..3890fc63f3f 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -832,7 +832,7 @@ typedef struct NodeTexSky {
typedef struct NodeTexImage {
NodeTexBase base;
ImageUser iuser;
- int color_space;
+ int color_space DNA_DEPRECATED;
int projection;
float projection_blend;
int interpolation;
@@ -853,7 +853,7 @@ typedef struct NodeTexBrick {
typedef struct NodeTexEnvironment {
NodeTexBase base;
ImageUser iuser;
- int color_space;
+ int color_space DNA_DEPRECATED;
int projection;
int interpolation;
char _pad[4];
@@ -1121,10 +1121,6 @@ typedef struct NodeCryptomatte {
#define SHD_SKY_OLD 0
#define SHD_SKY_NEW 1
-/* image/environment texture */
-#define SHD_COLORSPACE_NONE 0
-#define SHD_COLORSPACE_COLOR 1
-
/* environment texture */
#define SHD_PROJ_EQUIRECTANGULAR 0
#define SHD_PROJ_MIRROR_BALL 1
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 40ee069657c..8ba1f5440be 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -525,6 +525,22 @@ static char *rna_ColorManagedViewSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("view_settings");
}
+static bool rna_ColorManagedColorspaceSettings_is_data_get(struct PointerRNA *ptr)
+{
+ ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data;
+ const char *data_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA);
+ return STREQ(colorspace->name, data_name);
+}
+
+static void rna_ColorManagedColorspaceSettings_is_data_set(struct PointerRNA *ptr, bool value)
+{
+ ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data;
+ if (value) {
+ const char *data_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA);
+ STRNCPY(colorspace->name, data_name);
+ }
+}
+
static int rna_ColorManagedColorspaceSettings_colorspace_get(struct PointerRNA *ptr)
{
ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data;
@@ -1227,6 +1243,7 @@ static void rna_def_colormanage(BlenderRNA *brna)
prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, color_space_items);
RNA_def_property_enum_funcs(prop,
"rna_ColorManagedColorspaceSettings_colorspace_get",
@@ -1235,6 +1252,17 @@ static void rna_def_colormanage(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Input Color Space", "Color space of the image or movie on disk");
RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update");
+ prop = RNA_def_property(srna, "is_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_ColorManagedColorspaceSettings_is_data_get",
+ "rna_ColorManagedColorspaceSettings_is_data_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Is Data",
+ "Treat image as non-color data without color management, like normal or displacement maps");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update");
+
//
srna = RNA_def_struct(brna, "ColorManagedSequencerColorspaceSettings", NULL);
RNA_def_struct_path_func(srna, "rna_ColorManagedSequencerColorspaceSettings_path");
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index ca75f862b11..553dbeeb97b 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -211,69 +211,30 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int filter, int mag)
+static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
{
- GPUTexture *tex = image->gputexture[TEXTARGET_TEXTURE_2D];
- int error = GL_NO_ERROR;
-
- if (tex)
- return error;
-
ImageUser iuser = {NULL};
iuser.framenr = frame;
iuser.ok = true;
- void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- /* clean glError buffer */
- while (glGetError() != GL_NO_ERROR) {
- }
+ GPUTexture *tex = GPU_texture_from_blender(image, &iuser, GL_TEXTURE_2D);
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
- BKE_image_release_ibuf(image, ibuf, lock);
+ if (tex == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2);
return (int)GL_INVALID_OPERATION;
}
- unsigned int bindcode = 0;
- GPU_create_gl_tex(&bindcode,
- ibuf->rect,
- ibuf->rect_float,
- ibuf->x,
- ibuf->y,
- GL_TEXTURE_2D,
- (filter != GL_NEAREST && filter != GL_LINEAR),
- false,
- image);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
-
- /* TODO(merwin): validate input (dimensions, filter, mag) before calling OpenGL
- * instead of trusting input & testing for error after */
- error = glGetError();
-
- if (error) {
- glDeleteTextures(1, (GLuint *)&bindcode);
- }
- else {
- image->gputexture[TEXTARGET_TEXTURE_2D] = GPU_texture_from_bindcode(GL_TEXTURE_2D, bindcode);
- }
-
- BKE_image_release_ibuf(image, ibuf, lock);
-
- return error;
+ return GL_NO_ERROR;
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int filter, int mag)
+static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
{
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL)
- error = rna_Image_gl_load(image, reports, frame, filter, mag);
+ error = rna_Image_gl_load(image, reports, frame);
return error;
}
@@ -367,52 +328,20 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
- RNA_def_int(func,
- "filter",
- GL_LINEAR_MIPMAP_NEAREST,
- -INT_MAX,
- INT_MAX,
- "Filter",
- "The texture minifying function to use if the image wasn't loaded",
- -INT_MAX,
- INT_MAX);
- RNA_def_int(func,
- "mag",
- GL_LINEAR,
- -INT_MAX,
- INT_MAX,
- "Magnification",
- "The texture magnification function to use if the image wasn't loaded",
- -INT_MAX,
- INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "gl_load", "rna_Image_gl_load");
- RNA_def_function_ui_description(func, "Load the image into OpenGL graphics memory");
+ RNA_def_function_ui_description(
+ func,
+ "Load the image into an OpenGL texture. On success, image.bindcode will contain the "
+ "OpenGL texture bindcode. Colors read from the texture will be in scene linear color space "
+ "and have premultiplied alpha.");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
- RNA_def_int(func,
- "filter",
- GL_LINEAR_MIPMAP_NEAREST,
- -INT_MAX,
- INT_MAX,
- "Filter",
- "The texture minifying function",
- -INT_MAX,
- INT_MAX);
- RNA_def_int(func,
- "mag",
- GL_LINEAR,
- -INT_MAX,
- INT_MAX,
- "Magnification",
- "The texture magnification function",
- -INT_MAX,
- INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index e4270f3854e..4906f8ac28e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3987,21 +3987,6 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static const EnumPropertyItem sh_tex_prop_color_space_items[] = {
- {SHD_COLORSPACE_COLOR,
- "COLOR",
- 0,
- "Color",
- "Image contains color data, and will be converted to linear color for rendering"},
- {SHD_COLORSPACE_NONE,
- "NONE",
- 0,
- "Non-Color Data",
- "Image contains non-color data, for example a displacement or normal map, "
- "and will not be converted"},
- {0, NULL, 0, NULL, NULL},
-};
-
static const EnumPropertyItem sh_tex_prop_interpolation_items[] = {
{SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"},
{SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"},
@@ -4038,12 +4023,6 @@ static void def_sh_tex_environment(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items);
- RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
- RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
- RNA_def_property_update(prop, 0, "rna_Node_update");
-
prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_projection_items);
RNA_def_property_ui_text(prop, "Projection", "Projection of the input image");
@@ -4122,12 +4101,6 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items);
- RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
- RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
- RNA_def_property_update(prop, 0, "rna_Node_update");
-
prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_projection_items);
RNA_def_property_ui_text(
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 916cb81953e..165ada05a56 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -67,6 +67,7 @@
#include "RE_shader_ext.h"
#include "GPU_material.h"
+#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index c3b8bc8bfd0..615f55e4350 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -46,7 +46,6 @@ static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *no
NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->color_space = SHD_COLORSPACE_COLOR;
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
BKE_imageuser_default(&tex->iuser);
@@ -68,7 +67,6 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
NodeTexImage *tex_original = node_original->storage;
ImageUser *iuser = &tex_original->iuser;
- int isdata = tex->color_space == SHD_COLORSPACE_NONE;
GPUNodeLink *outalpha;
if (!ima) {
@@ -89,7 +87,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
"node_tex_environment_equirectangular",
in[0].link,
GPU_constant(&clamp_size),
- GPU_image(ima, iuser, isdata),
+ GPU_image(ima, iuser),
&in[0].link);
}
else {
@@ -104,7 +102,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_linear_no_mip",
in[0].link,
- GPU_image(ima, iuser, isdata),
+ GPU_image(ima, iuser),
&out[0].link,
&outalpha);
break;
@@ -112,26 +110,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPU_link(mat,
"node_tex_image_nearest",
in[0].link,
- GPU_image(ima, iuser, isdata),
+ GPU_image(ima, iuser),
&out[0].link,
&outalpha);
break;
default:
- GPU_link(mat,
- "node_tex_image_cubic",
- in[0].link,
- GPU_image(ima, iuser, isdata),
- &out[0].link,
- &outalpha);
+ GPU_link(
+ mat, "node_tex_image_cubic", in[0].link, GPU_image(ima, iuser), &out[0].link, &outalpha);
break;
}
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat)) {
- GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
+ if (out[0].hasoutput) {
+ GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 722434ce783..95e76491b4a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -57,7 +57,6 @@ static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->color_space = SHD_COLORSPACE_COLOR;
BKE_imageuser_default(&tex->iuser);
node->storage = tex;
@@ -99,7 +98,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX) ? names_box[tex->interpolation] :
names[tex->interpolation];
- bool do_color_correction = false;
bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT);
const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP);
@@ -114,20 +112,10 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPUNodeLink *vnor, *ob_mat, *blend;
GPUNodeLink **texco = &in[0].link;
- int isdata = tex->color_space == SHD_COLORSPACE_NONE;
-
if (!ima) {
return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
}
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if ((tex->color_space == SHD_COLORSPACE_COLOR) && ibuf &&
- (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat)) {
- do_color_correction = true;
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
if (!*texco) {
*texco = GPU_attribute(CD_MTFACE, "");
}
@@ -140,26 +128,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
break;
case SHD_PROJ_BOX:
vnor = GPU_builtin(GPU_WORLD_NORMAL);
ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
blend = GPU_uniform(&tex->projection_blend);
- gpu_image = GPU_image(ima, iuser, isdata);
+ gpu_image = GPU_image(ima, iuser);
/* equivalent to normal_world_to_object */
GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm);
- GPU_link(
- mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser, isdata), &col1, &col2, &col3);
- if (do_color_correction) {
- GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
- GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
- GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
- }
+ GPU_link(mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser), &col1, &col2, &col3);
GPU_stack_link(
mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend);
break;
@@ -171,9 +153,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
break;
case SHD_PROJ_TUBE:
@@ -183,20 +165,25 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPU_link(mat, "set_rgb", *texco, &input_coords);
}
if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco);
+ GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco);
}
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser));
break;
}
if (tex->projection != SHD_PROJ_BOX) {
if (do_texco_clip) {
gpu_node_name = names_clip[tex->interpolation];
- GPU_stack_link(
- mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata), out[0].link);
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser), out[0].link);
+ }
+ }
+
+ if (out[0].hasoutput) {
+ if (out[1].hasoutput) {
+ GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link);
}
- if (do_color_correction) {
- GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
+ else {
+ GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link);
}
}