diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 5774a057eb5..650e4527196 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -33,6 +33,9 @@ struct rcti; struct rctf; +struct ImBuf; +struct bContext; + void fdrawbezier(float vec[4][3]); void fdrawline(float x1, float y1, float x2, float y2); void fdrawbox(float x1, float y1, float x2, float y2); @@ -223,5 +226,13 @@ typedef struct bglMats { } bglMats; void bgl_get_mats(bglMats *mats); +/* **** Color management helper functions for GLSL display/transform ***** */ + +/* Draw imbuf on a screen, preferably using GLSL display transform */ +void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter); + +/* Transform buffer from role to scene linear space using GLSL OCIO conversion */ +int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role); + #endif /* __BIF_GLUTIL_H__ */ diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 365ac02d15b..de8accf0180 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -140,15 +140,23 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat } } if (rectf == NULL) return; - - if (ibuf->rect == NULL) - imb_addrectImBuf(ibuf); rectf += 4 * (rr->rectx * ymin + xmin); - IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin, - &scene->view_settings, &scene->display_settings, - rxmin, rymin, rxmin + xmax, rymin + ymax, TRUE); + if (ibuf->rect) { + IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin, + &scene->view_settings, &scene->display_settings, + rxmin, rymin, rxmin + xmax, rymin + ymax, TRUE); + } + + /* update float buffer as well, so fast GLSL display could use it + * + * TODO(sergey): not actually sure it is nice thing to modify something here + * but ibuf->rect used to be modified here + */ + IMB_buffer_float_from_float(ibuf->rect_float + 4 * (ibuf->x * rymin + rxmin), rectf, + 4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, FALSE, + xmax, ymax, ibuf->x, rr->rectx); } /* ****************************** render invoking ***************** */ diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index f47d737beca..9d443fab552 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -69,6 +69,8 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" #include "GPU_extensions.h" @@ -261,11 +263,14 @@ static void screen_opengl_render_apply(OGLRender *oglrender) */ if (!oglrender->is_sequencer) { - /* sequencer has got tricker ocnversion happened above */ - - IMB_buffer_float_from_float(rr->rectf, rr->rectf, - 4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, TRUE, - oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); + /* sequencer has got trickier conversion happened above + * also assume opengl's space matches byte buffer color space + */ + if (!glaBufferTransformFromRole_glsl(rr->rectf, oglrender->sizex, oglrender->sizey, COLOR_ROLE_DEFAULT_BYTE)) { + IMB_buffer_float_from_float(rr->rectf, rr->rectf, + 4, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, TRUE, + oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); + } } /* rr->rectf is now filled with image data */ diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 33373354aa4..c9c4c253e28 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC ../../blenlib ../../blenloader ../../bmesh + ../../gpu ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 89315e041de..fecb3c58a2d 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -43,10 +43,16 @@ #include "BKE_blender.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_extensions.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf_types.h" + #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif @@ -983,3 +989,89 @@ void bglFlush(void) #endif } #endif + +/* **** Color management helper functions for GLSL display/transform ***** */ + +/* Draw given image buffer on a screen using GLSL for display transform */ +void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter) +{ + bool need_fallback = true; + + /* Bytes and dithering are not supported on GLSL yet */ + if (ibuf->rect_float && ibuf->dither == 0.0f) { + if (IMB_colormanagement_setup_glsl_draw_from_ctx(C)) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1.0, 1.0, 1.0, 1.0); + + glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, zoomfilter, ibuf->rect_float); + + IMB_colormanagement_finish_glsl_draw(); + + need_fallback = false; + } + } + + if (need_fallback) { + unsigned char *display_buffer; + void *cache_handle; + + display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); + + if (display_buffer) + glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, zoomfilter, display_buffer); + + IMB_display_buffer_release(cache_handle); + } +} + +/* Transform buffer from role to scene linear space using GLSL OCIO conversion + * + * See IMB_colormanagement_setup_transform_from_role_glsl description for + * some more details + */ +int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role) +{ + GPUOffScreen *ofs; + char err_out[256]; + rcti display_rect; + + ofs = GPU_offscreen_create(width, height, err_out); + + if (!ofs) + return FALSE; + + GPU_offscreen_bind(ofs); + + if (!IMB_colormanagement_setup_transform_from_role_glsl(role)) { + GPU_offscreen_unbind(ofs); + GPU_offscreen_free(ofs); + return FALSE; + } + + BLI_rcti_init(&display_rect, 0, width, 0, height); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glaDefine2DArea(&display_rect); + glLoadIdentity(); + + glaDrawPixelsTex(0, 0, width, height, GL_FLOAT, GL_NEAREST, buffer); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + GPU_offscreen_read_pixels(ofs, GL_FLOAT, buffer); + + IMB_colormanagement_finish_glsl_transform(); + + /* unbind */ + GPU_offscreen_unbind(ofs); + GPU_offscreen_free(ofs); + + return TRUE; +} diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index cbca2f0c46e..774220764e7 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -248,53 +248,6 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) ED_region_info_draw(ar, str, block, 0.6f); } -static void draw_movieclip_buffer_glsl(SpaceClip *sc, ImBuf *ibuf, int x, int y, - float zoomx, float zoomy) -{ - MovieClip *clip = ED_space_clip_get_clip(sc); - int filter = GL_LINEAR; - - glPushMatrix(); - glTranslatef(x, y, 0.0f); - glScalef(zoomx, zoomy, 1.0f); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glColor4f(1.0, 1.0, 1.0, 1.0); - - /* non-scaled proxy shouldn;t use diltering */ - if ((clip->flag & MCLIP_USE_PROXY) == 0 || - ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) - { - filter = GL_NEAREST; - } - - glaDrawPixelsTex(0, 0, ibuf->x, ibuf->y, GL_FLOAT, filter, ibuf->rect_float); - - glPopMatrix(); -} - -static void draw_movieclip_buffer_fallback(const bContext *C, ImBuf *ibuf, int x, int y, - int width, int height, float zoomx, float zoomy) -{ - unsigned char *display_buffer; - void *cache_handle; - - display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); - - if (display_buffer) { - /* set zoom */ - glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y); - - glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); - - /* reset zoom */ - glPixelZoom(1.0f, 1.0f); - } - - IMB_display_buffer_release(cache_handle); -} - static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, ImBuf *ibuf, int width, int height, float zoomx, float zoomy) { @@ -308,7 +261,8 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, glRectf(x, y, x + zoomx * width, y + zoomy * height); } else { - bool need_fallback = true; + MovieClip *clip = ED_space_clip_get_clip(sc); + int filter = GL_LINEAR; /* checkerboard for case alpha */ if (ibuf->planes == 32) { @@ -318,19 +272,14 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); } - /* GLSL display transform for byte buffers is not supported yet */ - if (ibuf->rect_float && IMB_coloemanagement_setup_glsl_draw_from_ctx(C)) { - draw_movieclip_buffer_glsl(sc, ibuf, x, y, zoomx, zoomy); + /* non-scaled proxy shouldn't use filtering */ + if ((clip->flag & MCLIP_USE_PROXY) == 0 || + ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) + { + filter = GL_NEAREST; + } - IMB_coloemanagement_finish_glsl_draw(); - - need_fallback = false; - } - - /* if GLSL display failed, fallback to regular glaDrawPixelsAuto method */ - if (need_fallback) { - draw_movieclip_buffer_fallback(C, ibuf, x, y, width, height, zoomx, zoomy); - } + glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST); if (ibuf->planes == 32) glDisable(GL_BLEND); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index f27a99ac44b..7fc83809b60 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -505,9 +505,6 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->rect_float); } else { - unsigned char *display_buffer; - void *cache_handle; - if (sima->flag & SI_USE_ALPHA) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -515,12 +512,7 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy); } - display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); - - if (display_buffer) - glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); - - IMB_display_buffer_release(cache_handle); + glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST); if (sima->flag & SI_USE_ALPHA) glDisable(GL_BLEND); diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 473bd7d0c7a..a758cfa04f0 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -150,11 +150,18 @@ void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processo /* ** OpenGL drawing routines using GLSL for color space transform ** */ -int IMB_coloemanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, +/* Configures GLSL shader for conversion from scene linear to display space */ +int IMB_colormanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings); +/* Same as above, but color management settings are guessing from a given context */ +int IMB_colormanagement_setup_glsl_draw_from_ctx(const struct bContext *C); +/* Finish GLSL-based display space conversion */ +void IMB_colormanagement_finish_glsl_draw(void); -int IMB_coloemanagement_setup_glsl_draw_from_ctx(const struct bContext *C); -void IMB_coloemanagement_finish_glsl_draw(void); +/* Configures GLSL shader for conversion from space defined by role to scene linear space */ +int IMB_colormanagement_setup_transform_from_role_glsl(int role); +/* Finish GLSL-based color space conversion */ +void IMB_colormanagement_finish_glsl_transform(void); /* Roles */ enum { diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index e9447d255cb..1aa8c5af342 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -113,6 +113,7 @@ static struct global_glsl_state { /* Container for GLSL state needed for OCIO module. */ struct OCIO_GLSLDrawState *ocio_glsl_state; + struct OCIO_GLSLDrawState *transform_ocio_glsl_state; } global_glsl_state; /*********************** Color managed cache *************************/ @@ -626,6 +627,9 @@ void colormanagement_exit(void) if (global_glsl_state.ocio_glsl_state) OCIO_freeOGLState(global_glsl_state.ocio_glsl_state); + if (global_glsl_state.transform_ocio_glsl_state) + OCIO_freeOGLState(global_glsl_state.transform_ocio_glsl_state); + colormanage_free_config(); } @@ -2750,7 +2754,20 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s } } -int IMB_coloemanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, +/** + * Configures GLSL shader for conversion from scene linear + * to display space + * + * Will create appropriate OCIO processor and setup GLSL shader, + * so further 2D texture usage will use this conversion. + * + * When there's no need to apply transform on 2D textures, use + * IMB_colormanagement_finish_glsl_draw(). + * + * This is low-level function, use glaDrawImBuf_glsl_ctx if you + * only need to display given image buffer + */ +int IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { ColorManagedViewSettings default_view_settings; @@ -2778,17 +2795,52 @@ int IMB_coloemanagement_setup_glsl_draw(const ColorManagedViewSettings *view_set return OCIO_setupGLSLDraw(&global_glsl_state.ocio_glsl_state, global_glsl_state.processor); } -int IMB_coloemanagement_setup_glsl_draw_from_ctx(const bContext *C) +/* Same as above, but color management settings are guessing from a given context */ +int IMB_colormanagement_setup_glsl_draw_from_ctx(const bContext *C) { ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; display_transform_get_from_ctx(C, &view_settings, &display_settings); - return IMB_coloemanagement_setup_glsl_draw(view_settings, display_settings); + return IMB_colormanagement_setup_glsl_draw(view_settings, display_settings); } -void IMB_coloemanagement_finish_glsl_draw(void) +/* Finish GLSL-based display space conversion */ +void IMB_colormanagement_finish_glsl_draw(void) { OCIO_finishGLSLDraw(global_glsl_state.ocio_glsl_state); } + +/* ** Color space conversion using GLSL shader ** */ + +/** + * Configures GLSL shader for conversion from space defined by role + * to scene linear space + * + * Will create appropriate OCIO processor and setup GLSL shader, + * so further 2D texture usage will use this conversion. + * + * Role is an pseudonym for a color space, see bottom of file + * IMB_colormanagement.h for list of available roles. + * + * When there's no need to apply transform on 2D textures, use + * IMB_colormanagement_finish_glsl_transform(). + */ +int IMB_colormanagement_setup_transform_from_role_glsl(int role) +{ + OCIO_ConstProcessorRcPtr *processor; + ColorSpace *colorspace; + + colorspace = colormanage_colorspace_get_roled(role); + + processor = colorspace_to_scene_linear_processor(colorspace); + + return OCIO_setupGLSLDraw(&global_glsl_state.transform_ocio_glsl_state, processor); +} + +/* Finish GLSL-based color space conversion */ +void IMB_colormanagement_finish_glsl_transform(void) +{ + OCIO_finishGLSLDraw(global_glsl_state.transform_ocio_glsl_state); +}