Implement GPU-side dither
authorSergey Sharybin <sergey.vfx@gmail.com>
Fri, 13 Dec 2013 06:36:45 +0000 (12:36 +0600)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 13 Dec 2013 06:36:45 +0000 (12:36 +0600)
Summary:
Uses some magic pseudo-random which is actually a
texture coordinate hashing function.

TODOs:
- Dither noise is the same for all the frames.
- It's different from Floyd's dither we've been
  using before.
- Currently CPU and GPU dithering used different
  implementation. Ideally we need to use the same
  dither in CPU.

Reviewers: brecht

Reviewed By: brecht

Differential Revision: http://developer.blender.org/D58

13 files changed:
intern/opencolorio/fallback_impl.cc
intern/opencolorio/gpu_shader_display_transform.glsl
intern/opencolorio/ocio_capi.cc
intern/opencolorio/ocio_capi.h
intern/opencolorio/ocio_impl.h
intern/opencolorio/ocio_impl_glsl.cc
source/blender/editors/render/render_internal.c
source/blender/editors/screen/glutil.c
source/blender/editors/space_sequencer/sequencer_draw.c
source/blender/imbuf/IMB_colormanagement.h
source/blender/imbuf/intern/colormanagement.c
source/blender/imbuf/intern/divers.c
source/blender/makesrna/intern/rna_render.c

index 6383bbbb07f388b8fe04924b21bf3ce198aaca0c..c0797cbc37faf5211b940cc589325d6077d878de 100644 (file)
@@ -419,7 +419,8 @@ bool FallbackImpl::supportGLSLDraw(void)
 }
 
 bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*processor*/,
-                                 OCIO_CurveMappingSettings * /*curve_mapping_settings*/, bool /*predivide*/)
+                                 OCIO_CurveMappingSettings * /*curve_mapping_settings*/,
+                                 float /*dither*/,  bool /*predivide*/)
 {
        return false;
 }
index 6ba3fa55e8f7a8d9d5a459ca05e40c4869572682..8a85d6cbffe8b22ab31b9803747535533f8050d4 100644 (file)
@@ -2,6 +2,10 @@ uniform sampler2D image_texture;
 uniform sampler3D lut3d_texture;
 uniform bool predivide;
 
+#ifdef USE_DITHER
+uniform float dither;
+#endif
+
 #ifdef USE_CURVE_MAPPING
 /* Curve mapping parameters
  *
@@ -102,6 +106,33 @@ vec4 curvemapping_evaluate_premulRGBF(vec4 col)
 }
 #endif
 
+#ifdef USE_DITHER
+float dither_random_value(vec2 co)
+{
+       return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453) * 0.005 * dither;
+}
+
+vec2 round_to_pixel(vec2 st)
+{
+       vec2 result;
+       vec2 size = textureSize(image_texture, 0);
+       result.x = float(int(st.x * size.x)) / size.x;
+       result.y = float(int(st.y * size.y)) / size.y;
+       return result;
+}
+
+vec4 apply_dither(vec2 st, vec4 col)
+{
+       vec4 result;
+       float random_value = dither_random_value(round_to_pixel(st));
+       result.r = col.r + random_value;
+       result.g = col.g + random_value;
+       result.b = col.b + random_value;
+       result.a = col.a;
+       return result;
+}
+#endif
+
 void main()
 {
        vec4 col = texture2D(image_texture, gl_TexCoord[0].st);
@@ -119,5 +150,12 @@ void main()
         *       and the reason is simple -- opengl is always configured
         *       for straight alpha at this moment
         */
-       gl_FragColor = OCIODisplay(col, lut3d_texture);
+
+       vec4 result = OCIODisplay(col, lut3d_texture);
+
+#ifdef USE_DITHER
+       result = apply_dither(gl_TexCoord[0].st, result);
+#endif
+
+       gl_FragColor = result;
 }
index 47ee3afddfd315d05a81c3a380bb6a5e0fd3fd7d..a4f2db456e8f9acb1d9d48a2e74bb502d0a40408 100644 (file)
@@ -324,9 +324,9 @@ int OCIO_supportGLSLDraw(void)
 }
 
 int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                       OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide)
+                       OCIO_CurveMappingSettings *curve_mapping_settings, float dither, bool predivide)
 {
-       return (int) impl->setupGLSLDraw(state_r, processor, curve_mapping_settings, predivide);
+       return (int) impl->setupGLSLDraw(state_r, processor, curve_mapping_settings, dither, predivide);
 }
 
 void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state)
index 5abe104fcd41f2fad7b462790e57db436ec1a4d5..d667dece62af77fee612767036ba657d837532ce 100644 (file)
@@ -189,7 +189,7 @@ void OCIO_matrixTransformScale(float *m44, float *offset4, const float *scale4);
 
 int OCIO_supportGLSLDraw(void);
 int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                       OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide);
+                       OCIO_CurveMappingSettings *curve_mapping_settings, float dither, bool predivide);
 void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state);
 
index 4e7c1bcc83282894c4a8bf462ea1fe8131627fde..47e6d82990236cef89d68f4f8351fdbf199e19c2 100644 (file)
@@ -107,7 +107,7 @@ public:
 
        virtual bool supportGLSLDraw(void) = 0;
        virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                                  OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide) = 0;
+                                  OCIO_CurveMappingSettings *curve_mapping_settings, float dither, bool predivide) = 0;
        virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0;
        virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0;
 
@@ -194,7 +194,7 @@ public:
 
        bool supportGLSLDraw(void);
        bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                          OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide);
+                          OCIO_CurveMappingSettings *curve_mapping_settings, float dither, bool predivide);
        void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
        void freeGLState(struct OCIO_GLSLDrawState *state_r);
 
@@ -282,7 +282,7 @@ public:
 
        bool supportGLSLDraw(void);
        bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                          OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide);
+                          OCIO_CurveMappingSettings *curve_mapping_settings, float dither, bool predivide);
        void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
        void freeGLState(struct OCIO_GLSLDrawState *state_r);
 
index 2af3befc8a935fe9d988e9946fc374416a96c87e..3a23c26634533edaea119416ab2d4b23e399d24f 100644 (file)
@@ -33,6 +33,7 @@
  *
  */
 
+#include <limits>
 #include <sstream>
 #include <string.h>
 
@@ -62,6 +63,8 @@ typedef struct OCIO_GLSLDrawState {
 
        float *lut3d;  /* 3D LUT table */
 
+       bool dither_used;
+
        bool curve_mapping_used;
        bool curve_mapping_texture_allocated;
        bool curve_mapping_texture_valid;
@@ -229,10 +232,12 @@ bool OCIOImpl::supportGLSLDraw()
  * restore OpenGL context to it's pre-GLSL draw state.
  */
 bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor,
-                             OCIO_CurveMappingSettings *curve_mapping_settings, bool predivide)
+                             OCIO_CurveMappingSettings *curve_mapping_settings,
+                             float dither, bool predivide)
 {
        ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
        bool use_curve_mapping = curve_mapping_settings != NULL;
+       bool use_dither = dither > std::numeric_limits<float>::epsilon();
 
        /* Create state if needed. */
        OCIO_GLSLDrawState *state;
@@ -267,7 +272,7 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
 
        /* Step 1: Create a GPU Shader Description */
        GpuShaderDesc shaderDesc;
-       shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
+       shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_3);
        shaderDesc.setFunctionName("OCIODisplay");
        shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
 
@@ -297,7 +302,8 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
        std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
        if (state->program == 0 ||
            shaderCacheID != state->shadercacheid ||
-           use_curve_mapping != state->curve_mapping_used)
+           use_curve_mapping != state->curve_mapping_used ||
+           use_dither != state->dither_used)
        {
                state->shadercacheid = shaderCacheID;
 
@@ -311,6 +317,12 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
 
                std::ostringstream os;
 
+               os << "#version 130\n";
+
+               if (use_dither) {
+                       os << "#define USE_DITHER\n";
+               }
+
                if (use_curve_mapping) {
                        os << "#define USE_CURVE_MAPPING\n";
                }
@@ -325,6 +337,7 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
                }
 
                state->curve_mapping_used = use_curve_mapping;
+               state->dither_used = use_dither;
        }
 
        if (state->program) {
@@ -344,6 +357,10 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
                glUniform1i(glGetUniformLocation(state->program, "lut3d_texture"), 1);
                glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide);
 
+               if (use_dither) {
+                       glUniform1f(glGetUniformLocation(state->program, "dither"), dither);
+               }
+
                if (use_curve_mapping) {
                        glUniform1i(glGetUniformLocation(state->program, "curve_mapping_texture"), 2);
                        glUniform1i(glGetUniformLocation(state->program, "curve_mapping_lut_size"), curve_mapping_settings->lut_size);
index e1a271e996b4b0f0faa65b2df060f8229154ec44..1b090cb16ec81cdce4afcf60e1150fc0a4dff977 100644 (file)
@@ -1150,7 +1150,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
 
                /* Try using GLSL display transform. */
                if (force_fallback == false) {
-                       if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, true)) {
+                       if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, 0.0f, true)) {
                                glEnable(GL_BLEND);
                                glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                                glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT,
index 57d97178be5f35524293c0187be29b4cc2c09455..af5f9d3c875602c10b52c998439334e4d08f17df 100644 (file)
@@ -1044,9 +1044,6 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
        if (ibuf->rect == NULL && ibuf->rect_float == NULL)
                return;
 
-       /* Dithering is not supported on GLSL yet */
-       force_fallback |= ibuf->dither != 0.0f;
-
        /* Single channel images could not be transformed using GLSL yet */
        force_fallback |= ibuf->channels == 1;
 
@@ -1093,15 +1090,18 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
                if (ibuf->rect_float) {
                        if (ibuf->float_colorspace) {
                                ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
-                                                                                   ibuf->float_colorspace, true);
+                                                                                   ibuf->float_colorspace,
+                                                                                   ibuf->dither, true);
                        }
                        else {
-                               ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, true);
+                               ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings,
+                                                                        ibuf->dither, true);
                        }
                }
                else {
                        ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
-                                                                           ibuf->rect_colorspace, false);
+                                                                           ibuf->rect_colorspace,
+                                                                           ibuf->dither, false);
                }
 
                if (ok) {
index cb69a7fe654c824aba663a3b72ccd1babc3824ee..267b070fd42ac882e361847815f009f321f9b1ee 100644 (file)
@@ -1086,10 +1086,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
                        type = GL_FLOAT;
 
                        if (ibuf->float_colorspace) {
-                               glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, true);
+                               glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, ibuf->dither, true);
                        }
                        else {
-                               glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, true);
+                               glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, ibuf->dither, true);
                        }
                }
                else if (ibuf->rect) {
@@ -1097,7 +1097,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
                        format = GL_RGBA;
                        type = GL_UNSIGNED_BYTE;
 
-                       glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, false);
+                       glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, ibuf->dither, false);
                }
                else {
                        format = GL_RGBA;
index 09cdb3a4ee96eba8b69575a22b5f5765ae6f8373..7e115b265de16eb1718d45e53890beca55f80b2e 100644 (file)
@@ -178,16 +178,17 @@ bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings
 /* Configures GLSL shader for conversion from scene linear to display space */
 bool IMB_colormanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings,
                                          const struct ColorManagedDisplaySettings *display_settings,
-                                         bool predivide);
+                                         float dither, bool predivide);
 /* Same as above, but display space conversion happens from a specified space */
 bool IMB_colormanagement_setup_glsl_draw_from_space(const struct ColorManagedViewSettings *view_settings,
                                                     const struct ColorManagedDisplaySettings *display_settings,
                                                     struct ColorSpace *colorspace,
-                                                    bool predivide);
+                                                    float dither, bool predivide);
 /* Same as setup_glsl_draw, but color management settings are guessing from a given context */
-bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C, bool predivide);
+bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C, float dither, bool predivide);
 /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */
-bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *colorspace, bool predivide);
+bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *colorspace,
+                                                        float dither, bool predivide);
 /* Finish GLSL-based display space conversion */
 void IMB_colormanagement_finish_glsl_draw(void);
 
index 3c1a96e4005b0d48ed5bdb395eef7e3aa96f2349..a2e2fab7ba1c97b6bd85d3a63c158705ec94d7d1 100644 (file)
@@ -3091,7 +3091,8 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSE
  */
 bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings,
                                                     const ColorManagedDisplaySettings *display_settings,
-                                                    struct ColorSpace *from_colorspace, bool predivide)
+                                                    struct ColorSpace *from_colorspace,
+                                                    float dither, bool predivide)
 {
        ColorManagedViewSettings default_view_settings;
        const ColorManagedViewSettings *applied_view_settings;
@@ -3114,33 +3115,35 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettin
 
        return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor,
                                  global_glsl_state.use_curve_mapping ? &global_glsl_state.curve_mapping_settings : NULL,
-                                 predivide);
+                                 dither, predivide);
 }
 
 /* Configures GLSL shader for conversion from scene linear to display space */
 bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings,
                                          const ColorManagedDisplaySettings *display_settings,
-                                         bool predivide)
+                                         float dither, bool predivide)
 {
        return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
-                                                             NULL, predivide);
+                                                             NULL, dither, predivide);
 }
 
 /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */
-bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *from_colorspace, bool predivide)
+bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C, struct ColorSpace *from_colorspace,
+                                                        float dither, bool predivide)
 {
        ColorManagedViewSettings *view_settings;
        ColorManagedDisplaySettings *display_settings;
 
        IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
 
-       return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace, predivide);
+       return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace,
+                                                             dither, predivide);
 }
 
 /* Same as setup_glsl_draw, but color management settings are guessing from a given context */
-bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, bool predivide)
+bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
 {
-       return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, predivide);
+       return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
 }
 
 /* Finish GLSL-based display space conversion */
index af9f7109106a154960af6e71a4cf2379dc9d933f..a3647c7b45b542ba30e15f073bdf3815c75f817a 100644 (file)
@@ -31,7 +31,6 @@
  *  \ingroup imbuf
  */
 
-#include "BLI_rand.h"
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 
@@ -107,63 +106,33 @@ void IMB_interlace(ImBuf *ibuf)
 /************************* Floyd-Steinberg dithering *************************/
 
 typedef struct DitherContext {
-       int *error_buf, *e;
-       int v[4], v0[4], v1[4];
-       float f;
+       float dither;
 } DitherContext;
 
-static DitherContext *create_dither_context(int w, float factor)
+static DitherContext *create_dither_context(float dither)
 {
        DitherContext *di;
-       int i;
-       
-       di = MEM_callocN(sizeof(DitherContext), "dithering context");
-       di->f = factor / 16.0f;
-       di->error_buf = MEM_callocN(4 * (w + 1) * sizeof(int), "dithering error");
-       di->e = di->error_buf;
 
-       for (i = 0; i < 4; ++i)
-               di->v[i] = di->v0[i] = di->v1[i] = 1024.0f * (BLI_frand() - 0.5f);
+       di = MEM_mallocN(sizeof(DitherContext), "dithering context");
+       di->dither = dither;
 
        return di;
 }
 
 static void clear_dither_context(DitherContext *di)
 {
-       MEM_freeN(di->error_buf);
        MEM_freeN(di);
 }
 
-static void dither_finish_row(DitherContext *di)
+MINLINE float dither_random_value(float s, float t)
 {
-       int i;
-
-       for (i = 0; i < 4; i++)
-               di->v[i] = di->v0[i] = di->v1[i] = 0;
+       static float vec[2] = {12.9898f, 78.233f};
+       float st[2];
+       float value;
+       copy_v2_fl2(st, s, t);
 
-       di->e = di->error_buf;
-}
-
-MINLINE unsigned char dither_value(unsigned short v_in, DitherContext *di, int i)
-{
-       int dv, d2;
-       unsigned char v_out;
-
-       di->v[i] = v_in + (2 * di->v[i] + di->e[4]) * di->f;
-       CLAMP(di->v[i], 0, 0xFF00);
-       v_out = USHORTTOUCHAR(di->v[i]);
-       di->v[i] -= v_out << 8;
-       dv = di->v[i];
-       d2 = di->v[i] << 1;
-       di->v[i] += d2;
-       *(di->e++) = di->v[i] + di->v0[i];
-       di->v[i] += d2;
-
-       di->v0[i] = di->v[i] + di->v1[i];
-       di->v1[i] = dv;
-       di->v[i] += d2;
-
-       return v_out;
+       value = sinf(dot_v2v2(st, vec)) * 43758.5453f;
+       return value - floor(value);
 }
 
 /************************* Generic Buffer Conversion *************************/
@@ -176,18 +145,32 @@ MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4])
        b[3] = USHORTTOUCHAR(us[3]);
 }
 
-MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[4], DitherContext *di)
+MINLINE unsigned char ftochar(float value)
+{
+       return FTOCHAR(value);
+}
+
+MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[4], DitherContext *di, float s, float t)
 {
-       b[0] = dither_value(us[0], di, 0);
-       b[1] = dither_value(us[1], di, 1);
-       b[2] = dither_value(us[2], di, 2);
-       b[3] = dither_value(us[3], di, 3);
+#define USHORTTOFLOAT(val) ((float)val / 65535.0f)
+       float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
+
+       b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
+       b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
+       b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
+       b[3] = USHORTTOUCHAR(us[3]);
+
+#undef USHORTTOFLOAT
 }
 
-MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di)
+MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di, float s, float t)
 {
-       unsigned short us[4] = {FTOUSHORT(f[0]), FTOUSHORT(f[1]), FTOUSHORT(f[2]), FTOUSHORT(f[3])};
-       ushort_to_byte_dither_v4(b, us, di);
+       float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
+
+       b[0] = ftochar(dither_value + f[0]);
+       b[1] = ftochar(dither_value + f[1]);
+       b[2] = ftochar(dither_value + f[2]);
+       b[3] = FTOCHAR(f[3]);
 }
 
 /* float to byte pixels, output 4-channel RGBA */
@@ -198,15 +181,19 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
        float tmp[4];
        int x, y;
        DitherContext *di = NULL;
+       float inv_width = 1.0f / width,
+             inv_height = 1.0f / height;
 
        /* we need valid profiles */
        BLI_assert(profile_to != IB_PROFILE_NONE);
        BLI_assert(profile_from != IB_PROFILE_NONE);
 
        if (dither)
-               di = create_dither_context(width, dither);
+               di = create_dither_context(dither);
 
        for (y = 0; y < height; y++) {
+               float t = y * inv_height;
+
                if (channels_from == 1) {
                        /* single channel input */
                        const float *from = rect_from + stride_from * y;
@@ -256,12 +243,12 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
                                if (dither && predivide) {
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
                                                premul_to_straight_v4_v4(straight, from);
-                                               float_to_byte_dither_v4(to, straight, di);
+                                               float_to_byte_dither_v4(to, straight, di, (float) x * inv_width, t);
                                        }
                                }
                                else if (dither) {
                                        for (x = 0; x < width; x++, from += 4, to += 4)
-                                               float_to_byte_dither_v4(to, from, di);
+                                               float_to_byte_dither_v4(to, from, di, (float) x * inv_width, t);
                                }
                                else if (predivide) {
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
@@ -283,13 +270,13 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
                                                premul_to_straight_v4_v4(straight, from);
                                                linearrgb_to_srgb_ushort4(us, from);
-                                               ushort_to_byte_dither_v4(to, us, di);
+                                               ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t);
                                        }
                                }
                                else if (dither) {
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
                                                linearrgb_to_srgb_ushort4(us, from);
-                                               ushort_to_byte_dither_v4(to, us, di);
+                                               ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t);
                                        }
                                }
                                else if (predivide) {
@@ -311,13 +298,13 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
                                if (dither && predivide) {
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
                                                srgb_to_linearrgb_predivide_v4(tmp, from);
-                                               float_to_byte_dither_v4(to, tmp, di);
+                                               float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t);
                                        }
                                }
                                else if (dither) {
                                        for (x = 0; x < width; x++, from += 4, to += 4) {
                                                srgb_to_linearrgb_v4(tmp, from);
-                                               float_to_byte_dither_v4(to, tmp, di);
+                                               float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t);
                                        }
                                }
                                else if (predivide) {
@@ -334,9 +321,6 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
                                }
                        }
                }
-
-               if (dither)
-                       dither_finish_row(di);
        }
 
        if (dither)
index 9c3c6ce6c04f31a0cfc4c23b60f198f72fd8577e..854275ccb64614c925f5c2a5b42f04140413b736 100644 (file)
@@ -73,6 +73,7 @@ static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene
 {
        IMB_colormanagement_setup_glsl_draw(&scene->view_settings,
                                            &scene->display_settings,
+                                           scene->r.dither_intensity,
                                            false);
 }