Implement GPU-side dither
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
This commit is contained in:
parent
669b590229
commit
5a91df3271
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
static float vec[2] = {12.9898f, 78.233f};
|
||||
float st[2];
|
||||
float value;
|
||||
copy_v2_fl2(st, s, t);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
di->v[i] = di->v0[i] = di->v1[i] = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return FTOCHAR(value);
|
||||
}
|
||||
|
||||
MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di)
|
||||
MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[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);
|
||||
#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, float s, float t)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue