void ViewerOperation::updateImage(rcti *rect) { IMB_partial_display_buffer_update(this->m_ibuf, this->m_outputBuffer, NULL, getWidth(), 0, 0, this->m_viewSettings, this->m_displaySettings, rect->xmin, rect->ymin, rect->xmax, rect->ymax, false); this->updateDraw(); }
/* called inside thread! */ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect) { float *rectf = NULL; int ymin, ymax, xmin, xmax; int rymin, rxmin; /* if renrect argument, we only refresh scanlines */ if (renrect) { /* if (ymax == recty), rendering of layer is ready, we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) return; /* xmin here is first subrect x coord, xmax defines subrect width */ xmin = renrect->xmin + rr->crop; xmax = renrect->xmax - xmin + rr->crop; if (xmax < 2) return; ymin = renrect->ymin + rr->crop; ymax = renrect->ymax - ymin + rr->crop; if (ymax < 2) return; renrect->ymin = renrect->ymax; } else { xmin = ymin = rr->crop; xmax = rr->rectx - 2 * rr->crop; ymax = rr->recty - 2 * rr->crop; } /* xmin ymin is in tile coords. transform to ibuf */ rxmin = rr->tilerect.xmin + xmin; if (rxmin >= ibuf->x) return; rymin = rr->tilerect.ymin + ymin; if (rymin >= ibuf->y) return; if (rxmin + xmax > ibuf->x) xmax = ibuf->x - rxmin; if (rymin + ymax > ibuf->y) ymax = ibuf->y - rymin; if (xmax < 1 || ymax < 1) return; /* find current float rect for display, first case is after composite... still weak */ if (rr->rectf) rectf = rr->rectf; else { if (rr->rect32) { /* special case, currently only happens with sequencer rendering, * which updates the whole frame, so we can only mark display buffer * as invalid here (sergey) */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; return; } else { if (rr->renlay == NULL || rr->renlay->rectf == NULL) return; rectf = rr->renlay->rectf; } } 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); }
static void screen_opengl_render_apply(OGLRender *oglrender) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; RenderResult *rr; Object *camera = NULL; ImBuf *ibuf; void *lock; float winmat[4][4]; int sizex = oglrender->sizex; int sizey = oglrender->sizey; const short view_context = (v3d != NULL); bool draw_bgpic = true; bool draw_sky = (scene->r.alphamode == R_ADDSKY); unsigned char *rect = NULL; rr = RE_AcquireResultRead(oglrender->re); if (oglrender->is_sequencer) { SeqRenderData context; int chanshown = oglrender->sseq ? oglrender->sseq->chanshown : 0; context = BKE_sequencer_new_render_data(oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f); ibuf = BKE_sequencer_give_ibuf(context, CFRA, chanshown); if (ibuf) { ImBuf *linear_ibuf; BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); linear_ibuf = IMB_dupImBuf(ibuf); IMB_freeImBuf(ibuf); if (linear_ibuf->rect_float == NULL) { /* internally sequencer working in display space and stores both bytes and float buffers in that space. * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear */ IMB_float_from_rect(linear_ibuf); } else { /* ensure float buffer is in linear space, not in display space */ BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf); } memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); IMB_freeImBuf(linear_ibuf); } } else if (view_context) { ED_view3d_draw_offscreen_init(scene, v3d); GPU_offscreen_bind(oglrender->ofs); /* bind */ /* render 3d view */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { /*int is_ortho = scene->r.mode & R_ORTHO;*/ camera = v3d->camera; RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat); } else { rctf viewplane; float clipsta, clipend; int is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); } rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); if ((scene->r.mode & R_OSA) == 0) { ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); } else { /* simple accumulation, less hassle then FSAA FBO's */ static float jit_ofs[32][2]; float winmat_jitter[4][4]; int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1"); int i, j; BLI_jitter_init(jit_ofs[0], scene->r.osa); /* first sample buffer, also initializes 'rv3d->persmat' */ ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) accum_buffer[i] = rect[i]; /* skip the first sample */ for (j = 1; j < scene->r.osa; j++) { copy_m4_m4(winmat_jitter, winmat); window_translate_m4(winmat_jitter, rv3d->persmat, (jit_ofs[j][0] * 2.0f) / sizex, (jit_ofs[j][1] * 2.0f) / sizey); ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_bgpic, draw_sky); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) accum_buffer[i] += rect[i]; } for (i = 0; i < sizex * sizey * 4; i++) rect[i] = accum_buffer[i] / scene->r.osa; MEM_freeN(accum_buffer); } GPU_offscreen_unbind(oglrender->ofs); /* unbind */ } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rect, OB_SOLID, FALSE, TRUE, (draw_sky) ? R_ADDSKY: R_ALPHAPREMUL, err_out); camera = scene->camera; if (ibuf_view) { /* steal rect reference from ibuf */ rect = (unsigned char *)ibuf_view->rect; ibuf_view->mall &= ~IB_rect; IMB_freeImBuf(ibuf_view); } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); } } /* note on color management: * * OpenGL renders into sRGB colors, but render buffers are expected to be * linear So we convert to linear here, so the conversion back to bytes can make it * sRGB (or other display space) again, and so that e.g. openexr saving also saves the * correct linear float buffer. */ if (rect) { int profile_to; if (BKE_scene_check_color_management_enabled(scene)) profile_to = IB_PROFILE_LINEAR_RGB; else profile_to = IB_PROFILE_SRGB; /* sequencer has got trickier conversion happened above * also assume opengl's space matches byte buffer color space */ IMB_buffer_float_from_byte(rr->rectf, rect, profile_to, IB_PROFILE_SRGB, true, oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); } /* rr->rectf is now filled with image data */ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4); RE_ReleaseResult(oglrender->re); /* update byte from float buffer */ ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock); if (ibuf) { /* update display buffer */ if (ibuf->rect == NULL) imb_addrectImBuf(ibuf); IMB_partial_display_buffer_update(ibuf, rr->rectf, rect, rr->rectx, 0, 0, &scene->view_settings, &scene->display_settings, 0, 0, rr->rectx, rr->recty, true); /* write file for animation */ if (oglrender->write_still) { char name[FILE_MAX]; int ok; if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) { IMB_color_to_bw(ibuf); } BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE); ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, TRUE); /* no need to stamp here */ if (ok) printf("OpenGL Render written to '%s'\n", name); else printf("OpenGL Render failed to write '%s'\n", name); } } BKE_image_release_ibuf(oglrender->ima, ibuf, lock); if (rect) MEM_freeN(rect); }
/* called inside thread! */ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname) { Scene *scene = rj->scene; const float *rectf = NULL; int ymin, ymax, xmin, xmax; int rymin, rxmin; int linear_stride, linear_offset_x, linear_offset_y; ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; /* Exception for exr tiles -- display buffer conversion happens here, * NOT in the color management pipeline. */ if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID && rr->do_exr_tile == false) { /* The whole image buffer it so be color managed again anyway. */ return; } /* if renrect argument, we only refresh scanlines */ if (renrect) { /* if (ymax == recty), rendering of layer is ready, we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) return; /* xmin here is first subrect x coord, xmax defines subrect width */ xmin = renrect->xmin + rr->crop; xmax = renrect->xmax - xmin + rr->crop; if (xmax < 2) return; ymin = renrect->ymin + rr->crop; ymax = renrect->ymax - ymin + rr->crop; if (ymax < 2) return; renrect->ymin = renrect->ymax; } else { xmin = ymin = rr->crop; xmax = rr->rectx - 2 * rr->crop; ymax = rr->recty - 2 * rr->crop; } /* xmin ymin is in tile coords. transform to ibuf */ rxmin = rr->tilerect.xmin + xmin; if (rxmin >= ibuf->x) return; rymin = rr->tilerect.ymin + ymin; if (rymin >= ibuf->y) return; if (rxmin + xmax > ibuf->x) xmax = ibuf->x - rxmin; if (rymin + ymax > ibuf->y) ymax = ibuf->y - rymin; if (xmax < 1 || ymax < 1) return; /* The thing here is, the logic below (which was default behavior * of how rectf is acquiring since forever) gives float buffer for * composite output only. This buffer can not be used for other * passes obviously. * * We might try finding corresponding for pass buffer in render result * (which is actually missing when rendering with Cycles, who only * writes all the passes when the tile is finished) or use float * buffer from image buffer as reference, which is easier to use and * contains all the data we need anyway. * - sergey - */ /* TODO(sergey): Need to check has_combined here? */ if (iuser->pass == 0) { RenderView *rv; size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); rv = RE_RenderViewGetById(rr, view_id); /* find current float rect for display, first case is after composite... still weak */ if (rv->rectf) rectf = rv->rectf; else { if (rv->rect32) { /* special case, currently only happens with sequencer rendering, * which updates the whole frame, so we can only mark display buffer * as invalid here (sergey) */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; return; } else { if (rr->renlay == NULL) return; rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname); } } if (rectf == NULL) return; rectf += 4 * (rr->rectx * ymin + xmin); linear_stride = rr->rectx; linear_offset_x = rxmin; linear_offset_y = rymin; } else { rectf = ibuf->rect_float; linear_stride = ibuf->x; linear_offset_x = 0; linear_offset_y = 0; } if (rr->do_exr_tile) { /* We don't support changing color management settings during rendering * when using Save Buffers option. */ view_settings = &rj->view_settings; display_settings = &rj->display_settings; } else { view_settings = &scene->view_settings; display_settings = &scene->display_settings; } IMB_partial_display_buffer_update(ibuf, rectf, NULL, linear_stride, linear_offset_x, linear_offset_y, view_settings, display_settings, rxmin, rymin, rxmin + xmax, rymin + ymax, rr->do_exr_tile); }
/* called inside thread! */ static void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect) { float *rectf = NULL; int ymin, ymax, xmin, xmax; int rymin, rxmin; int linear_stride, linear_offset_x, linear_offset_y; if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) { /* The whole image buffer it so be color managed again anyway. */ return; } /* if renrect argument, we only refresh scanlines */ if (renrect) { /* if (ymax == recty), rendering of layer is ready, we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) return; /* xmin here is first subrect x coord, xmax defines subrect width */ xmin = renrect->xmin + rr->crop; xmax = renrect->xmax - xmin + rr->crop; if (xmax < 2) return; ymin = renrect->ymin + rr->crop; ymax = renrect->ymax - ymin + rr->crop; if (ymax < 2) return; renrect->ymin = renrect->ymax; } else { xmin = ymin = rr->crop; xmax = rr->rectx - 2 * rr->crop; ymax = rr->recty - 2 * rr->crop; } /* xmin ymin is in tile coords. transform to ibuf */ rxmin = rr->tilerect.xmin + xmin; if (rxmin >= ibuf->x) return; rymin = rr->tilerect.ymin + ymin; if (rymin >= ibuf->y) return; if (rxmin + xmax > ibuf->x) xmax = ibuf->x - rxmin; if (rymin + ymax > ibuf->y) ymax = ibuf->y - rymin; if (xmax < 1 || ymax < 1) return; /* The thing here is, the logic below (which was default behavior * of how rectf is acquiring since forever) gives float buffer for * composite output only. This buffer can not be used for other * passes obviously. * * We might try finding corresponding for pass buffer in render result * (which is actually missing when rendering with Cycles, who only * writes all the passes when the tile is finished) or use float * buffer from image buffer as reference, which is easier to use and * contains all the data we need anyway. * - sergey - */ /* TODO(sergey): Need to check has_combined here? */ if (iuser->pass == 0) { /* find current float rect for display, first case is after composite... still weak */ if (rr->rectf) rectf = rr->rectf; else { if (rr->rect32) { /* special case, currently only happens with sequencer rendering, * which updates the whole frame, so we can only mark display buffer * as invalid here (sergey) */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; return; } else { if (rr->renlay == NULL || rr->renlay->rectf == NULL) return; rectf = rr->renlay->rectf; } } if (rectf == NULL) return; rectf += 4 * (rr->rectx * ymin + xmin); linear_stride = rr->rectx; linear_offset_x = rxmin; linear_offset_y = rymin; } else { rectf = ibuf->rect_float; linear_stride = ibuf->x; linear_offset_x = 0; linear_offset_y = 0; } IMB_partial_display_buffer_update(ibuf, rectf, NULL, linear_stride, linear_offset_x, linear_offset_y, &scene->view_settings, &scene->display_settings, rxmin, rymin, rxmin + xmax, rymin + ymax); }