static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect) { RenderJob *rj = rjv; Image *ima = rj->image; ImBuf *ibuf; void *lock; const char *viewname = RE_GetActiveRenderView(rj->re); /* only update if we are displaying the slot being rendered */ if (ima->render_slot != ima->last_render_slot) { rj->image_outdated = true; return; } else if (rj->image_outdated) { /* update entire render */ rj->image_outdated = false; BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE); *(rj->do_update) = true; return; } if (rr == NULL) return; /* update part of render */ render_image_update_pass_and_layer(rj, rr, &rj->iuser); ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); if (ibuf) { /* Don't waste time on CPU side color management if * image will be displayed using GLSL. * * Need to update rect if Save Buffers enabled because in * this case GLSL doesn't have original float buffer to * operate with. */ if (rr->do_exr_tile || ibuf->channels == 1 || U.image_draw_method != IMAGE_DRAW_METHOD_GLSL) { image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname); } /* make jobs timer to send notifier */ *(rj->do_update) = true; } BKE_image_release_ibuf(ima, ibuf, lock); }
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; Object *camera = NULL; ImBuf *ibuf; 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; const char *viewname = RE_GetActiveRenderView(oglrender->re); if (oglrender->is_sequencer) { SeqRenderData context; SpaceSeq *sseq = oglrender->sseq; int chanshown = sseq ? sseq->chanshown : 0; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; BKE_sequencer_new_render_data( oglrender->bmain->eval_ctx, oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f, &context); context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); if (ibuf) { float *rectf; 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); } rectf = RE_RenderViewGetRectf(rr, oglrender->view_id); memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); IMB_freeImBuf(linear_ibuf); } if (gpd) { int i; unsigned char *gp_rect; GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); G.f |= G_RENDER_OGL; ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { float col_src[4]; rgba_uchar_to_float(col_src, &gp_rect[i]); blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src); } GPU_offscreen_unbind(oglrender->ofs, true); MEM_freeN(gp_rect); } } else if (view_context) { bool is_persp; /* full copy */ GPUFXSettings fx_settings = v3d->fx_settings; ED_view3d_draw_offscreen_init(scene, v3d); GPU_offscreen_bind(oglrender->ofs, true); /* bind */ /* render 3d view */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { /*int is_ortho = scene->r.mode & R_ORTHO;*/ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat); if (camera->type == OB_CAMERA) { Camera *cam = camera->data; is_persp = cam->type == CAM_PERSP; } else is_persp = true; BKE_camera_to_gpu_dof(camera, &fx_settings); } else { rctf viewplane; float clipsta, clipend; bool 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); is_persp = !is_ortho; } 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, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); 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, 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, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); 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, is_persp, oglrender->ofs, oglrender->fx, &fx_settings, viewname); 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, true); /* 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, true, (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, 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; float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id); 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(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_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4); MEM_freeN(rect); } }
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; Object *camera = NULL; ImBuf *ibuf; 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; const char *viewname = RE_GetActiveRenderView(oglrender->re); if (oglrender->is_sequencer) { SeqRenderData context; SpaceSeq *sseq = oglrender->sseq; int chanshown = sseq ? sseq->chanshown : 0; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; BKE_sequencer_new_render_data( oglrender->bmain->eval_ctx, oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f, &context); context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); context.gpu_offscreen = oglrender->ofs; context.gpu_fx = oglrender->fx; context.gpu_full_samples = oglrender->ofs_full_samples; ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); if (ibuf) { ImBuf *out = IMB_dupImBuf(ibuf); IMB_freeImBuf(ibuf); /* OpenGL render is considered to be preview and should be * as fast as possible. So currently we're making sure sequencer * result is always byte to simplify color management pipeline. * * TODO(sergey): In the case of output to float container (EXR) * it actually makes sense to keep float buffer instead. */ if (out->rect_float != NULL) { IMB_rect_from_float(out); imb_freerectfloatImBuf(out); } BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); IMB_freeImBuf(out); } if (gpd) { int i; unsigned char *gp_rect; unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); G.f |= G_RENDER_OGL; ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]); } GPU_offscreen_unbind(oglrender->ofs, true); MEM_freeN(gp_rect); } } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view; const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf( scene, v3d, ar, sizex, sizey, IB_rect, draw_bgpic, alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname, oglrender->fx, oglrender->ofs, err_out); /* for stamp only */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); } } else { ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rect, OB_SOLID, false, true, true, alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname, oglrender->fx, oglrender->ofs, 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; float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf; 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(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_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4); MEM_freeN(rect); } }
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; Object *camera = NULL; 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; const char *viewname = RE_GetActiveRenderView(oglrender->re); ImBuf *ibuf_result = NULL; if (oglrender->is_sequencer) { SpaceSeq *sseq = oglrender->sseq; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; /* use pre-calculated ImBuf (avoids deadlock), see: */ ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id]; if (ibuf) { ImBuf *out = IMB_dupImBuf(ibuf); IMB_freeImBuf(ibuf); /* OpenGL render is considered to be preview and should be * as fast as possible. So currently we're making sure sequencer * result is always byte to simplify color management pipeline. * * TODO(sergey): In the case of output to float container (EXR) * it actually makes sense to keep float buffer instead. */ if (out->rect_float != NULL) { IMB_rect_from_float(out); imb_freerectfloatImBuf(out); } BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); IMB_freeImBuf(out); } else if (gpd){ /* If there are no strips, Grease Pencil still needs a buffer to draw on */ ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect); RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); IMB_freeImBuf(out); } if (gpd) { int i; unsigned char *gp_rect; unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); G.f |= G_RENDER_OGL; ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]); } GPU_offscreen_unbind(oglrender->ofs, true); MEM_freeN(gp_rect); } } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view; const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf( scene, v3d, ar, sizex, sizey, IB_rect, draw_bgpic, alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname, oglrender->fx, oglrender->ofs, err_out); /* for stamp only */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); } } else { ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( scene, scene->camera, oglrender->sizex, oglrender->sizey, IB_rect, OB_SOLID, false, true, true, alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname, oglrender->fx, oglrender->ofs, err_out); camera = scene->camera; } if (ibuf_view) { ibuf_result = ibuf_view; rect = (unsigned char *)ibuf_view->rect; } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); } } if (ibuf_result != NULL) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); } }