void render_view3d_draw(RenderEngine *engine, const bContext *C) { Render *re = engine->re; RenderResult rres; int keep_data = render_view3d_changed(engine, C); if (engine->flag & RE_ENGINE_DO_UPDATE) render_view3d_do(engine, C, keep_data); if (re == NULL) return; RE_AcquireResultImage(re, &rres); if (rres.rectf) { Scene *scene = CTX_data_scene(C); bool force_fallback = false; bool need_fallback = true; float dither = scene->r.dither_intensity; /* Dithering is not supported on GLSL yet */ force_fallback |= dither != 0.0f; /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */ force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL); /* Try using GLSL display transform. */ if (force_fallback == false) { if (IMB_colormanagement_setup_glsl_draw(NULL, &scene->display_settings, 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, GL_LINEAR, rres.rectf); glDisable(GL_BLEND); IMB_colormanagement_finish_glsl_draw(); need_fallback = false; } } /* If GLSL failed, use old-school CPU-based transform. */ if (need_fallback) { unsigned char *display_buffer = MEM_mallocN(4 * rres.rectx * rres.recty * sizeof(char), "render_view3d_draw"); IMB_colormanagement_buffer_make_display_space(rres.rectf, display_buffer, rres.rectx, rres.recty, 4, dither, NULL, &scene->display_settings); glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsAuto(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer); glDisable(GL_BLEND); MEM_freeN(display_buffer); } } RE_ReleaseResultImage(re); }
/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */ void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) { if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) { glColor4f(1.0, 1.0, 1.0, 1.0); glaDrawPixelsTex(x, y, img_w, img_h, format, type, zoomfilter, rect); } else { glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect); } }
/* 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 * * NOTE: this only works for RGBA buffers! */ 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, TRUE)) { 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); glaDrawPixelsTex(0, 0, width, height, GL_RGBA, 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; }
/* Draw given image buffer on a screen using GLSL for display transform */ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, ColorManagedViewSettings *view_settings, ColorManagedDisplaySettings *display_settings) { bool force_fallback = false; bool need_fallback = true; /* Early out */ 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; /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */ force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL); /* This is actually lots of crap, but currently not sure about * more clear way to bypass partial buffer update crappyness * while rendering. * * The thing is -- render engines are only updating byte and * display buffers for active render result opened in image * editor. This works fine to show render progress without * switching render layers in image editor user, but this is * completely useless for GLSL display, where we need to have * original buffer which we could color manage. * * For the time of rendering, we'll stick back to slower CPU * display buffer update. GLSL could be used as soon as some * fixes (?) are done in render itself, so we'll always have * image buffer with relevant float buffer opened while * rendering. * * On the other hand, when using Cycles, stressing GPU with * GLSL could backfire on a performance. * - sergey - */ if (G.is_rendering) { /* Try to detect whether we're drawing render result, * other images could have both rect and rect_float * but they'll be synchronized */ if (ibuf->rect_float && ibuf->rect && ((ibuf->mall & IB_rectfloat) == 0)) { force_fallback = true; } } /* Try to draw buffer using GLSL display transform */ if (force_fallback == false) { int ok; if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, ibuf->float_colorspace, TRUE); } else { ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, TRUE); } } else { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, ibuf->rect_colorspace, FALSE); } if (ok) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0, 1.0, 1.0, 1.0); if (ibuf->rect_float) { int format = 0; if (ibuf->channels == 3) format = GL_RGB; else if (ibuf->channels == 4) format = GL_RGBA; else BLI_assert(!"Incompatible number of channels for GLSL display"); if (format != 0) { glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT, zoomfilter, ibuf->rect_float); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect); } IMB_colormanagement_finish_glsl_draw(); need_fallback = false; } } /* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */ if (need_fallback) { unsigned char *display_buffer; void *cache_handle; display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle); if (display_buffer) glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, display_buffer); IMB_display_buffer_release(cache_handle); } }
void render_view3d_draw(RenderEngine *engine, const bContext *C) { Render *re = engine->re; RenderResult rres; char name[32]; render_view3d_do(engine, C); if (re == NULL) { sprintf(name, "View3dPreview %p", (void *)CTX_wm_region(C)); re = RE_GetRender(name); if (re == NULL) return; } /* Viewport render preview doesn't support multiview, view hardcoded to 0 */ RE_AcquireResultImage(re, &rres, 0); if (rres.rectf) { RegionView3D *rv3d = CTX_wm_region_view3d(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); bool force_fallback = false; bool need_fallback = true; float dither = scene->r.dither_intensity; float scale_x, scale_y; rcti clip_rect; int xof, yof; if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) { scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx; scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty; xof = clip_rect.xmin; yof = clip_rect.ymin; } else { scale_x = (float) ar->winx / rres.rectx; scale_y = (float) ar->winy / rres.recty; xof = rres.xof; yof = rres.yof; } /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */ force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL); /* Try using GLSL display transform. */ if (force_fallback == false) { if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, dither, true)) { glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glPixelZoom(scale_x, scale_y); glaDrawPixelsTex(xof, yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT, GL_NEAREST, rres.rectf); glPixelZoom(1.0f, 1.0f); glDisable(GL_BLEND); IMB_colormanagement_finish_glsl_draw(); need_fallback = false; } } /* If GLSL failed, use old-school CPU-based transform. */ if (need_fallback) { unsigned char *display_buffer = MEM_mallocN(4 * rres.rectx * rres.recty * sizeof(char), "render_view3d_draw"); IMB_colormanagement_buffer_make_display_space(rres.rectf, display_buffer, rres.rectx, rres.recty, 4, dither, &scene->view_settings, &scene->display_settings); glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glPixelZoom(scale_x, scale_y); glaDrawPixelsAuto(xof, yof, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); glPixelZoom(1.0f, 1.0f); glDisable(GL_BLEND); MEM_freeN(display_buffer); } } RE_ReleaseResultImage(re); }
/* sets up the opengl context. * width, height are to match the values from ED_mask_get_size() */ void ED_mask_draw_region(Mask *mask, ARegion *ar, const char draw_flag, const char draw_type, const char overlay_mode, const int width_i, const int height_i, /* convert directly into aspect corrected vars */ const float aspx, const float aspy, const bool do_scale_applied, const bool do_draw_cb, float stabmat[4][4], /* optional - only used by clip */ const bContext *C /* optional - only used when do_post_draw is set or called from clip editor */ ) { struct View2D *v2d = &ar->v2d; /* aspect always scales vertically in movie and image spaces */ const float width = width_i, height = (float)height_i * (aspy / aspx); int x, y; /* int w, h; */ float zoomx, zoomy; /* frame image */ float maxdim; float xofs, yofs; /* find window pixel coordinates of origin */ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y); /* w = BLI_rctf_size_x(&v2d->tot); */ /* h = BLI_rctf_size_y(&v2d->tot); */ zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur); zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / BLI_rctf_size_y(&ar->v2d.cur); if (do_scale_applied) { zoomx /= width; zoomy /= height; } x += v2d->tot.xmin * zoomx; y += v2d->tot.ymin * zoomy; /* frame the image */ maxdim = max_ff(width, height); if (width == height) { xofs = yofs = 0; } else if (width < height) { xofs = ((height - width) / -2.0f) * zoomx; yofs = 0.0f; } else { /* (width > height) */ xofs = 0.0f; yofs = ((width - height) / -2.0f) * zoomy; } if (draw_flag & MASK_DRAWFLAG_OVERLAY) { float *buffer = threaded_mask_rasterize(mask, width, height); int format; if (overlay_mode == MASK_OVERLAY_ALPHACHANNEL) { glColor3f(1.0f, 1.0f, 1.0f); format = GL_LUMINANCE; } else { /* More blending types could be supported in the future. */ glEnable(GL_BLEND); glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); format = GL_ALPHA; } glPushMatrix(); glTranslatef(x, y, 0); glScalef(zoomx, zoomy, 0); if (stabmat) { glMultMatrixf(stabmat); } glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer); glPopMatrix(); if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) { glDisable(GL_BLEND); } MEM_freeN(buffer); } /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */ glPushMatrix(); if (stabmat) { glMultMatrixf(stabmat); } glTranslatef(x + xofs, y + yofs, 0); glScalef(maxdim * zoomx, maxdim * zoomy, 0); if (do_draw_cb) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); } /* draw! */ draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy); if (do_draw_cb) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); } glPopMatrix(); }
/* Draw given image buffer on a screen using GLSL for display transform */ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, ColorManagedViewSettings *view_settings, ColorManagedDisplaySettings *display_settings) { bool force_fallback = false; bool need_fallback = true; /* Early out */ if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; /* Single channel images could not be transformed using GLSL yet */ force_fallback |= ibuf->channels == 1; /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */ force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL); /* Try to draw buffer using GLSL display transform */ if (force_fallback == false) { int ok; if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, ibuf->float_colorspace, ibuf->dither, true); } else { 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, ibuf->dither, false); } if (ok) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0, 1.0, 1.0, 1.0); if (ibuf->rect_float) { int format = 0; if (ibuf->channels == 3) format = GL_RGB; else if (ibuf->channels == 4) format = GL_RGBA; else BLI_assert(!"Incompatible number of channels for GLSL display"); if (format != 0) { glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT, zoomfilter, ibuf->rect_float); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect); } IMB_colormanagement_finish_glsl_draw(); need_fallback = false; } } /* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */ if (need_fallback) { unsigned char *display_buffer; void *cache_handle; display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle); if (display_buffer) glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, display_buffer); IMB_display_buffer_release(cache_handle); } }