diff options
Diffstat (limited to 'source/blender/editors/render/render_opengl.c')
-rw-r--r-- | source/blender/editors/render/render_opengl.c | 254 |
1 files changed, 105 insertions, 149 deletions
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index c718dfa9229..992b827113d 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -69,9 +69,9 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_compositing.h" +#include "GPU_framebuffer.h" #include "render_intern.h" @@ -88,14 +88,21 @@ typedef struct OGLRender { ScrArea *prevsa; ARegion *prevar; + int views_len; /* multi-view views */ + bool is_sequencer; SpaceSeq *sseq; + struct { + ImBuf **ibufs_arr; + } seq_data; Image *ima; ImageUser iuser; GPUOffScreen *ofs; + int ofs_samples; + bool ofs_full_samples; GPUFX *fx; int sizex, sizey; int write_still; @@ -104,7 +111,7 @@ typedef struct OGLRender { bMovieHandle *mh; int cfrao, nfra; - size_t totvideos; + int totvideos; /* quick lookup */ int view_id; @@ -228,13 +235,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } BLI_lock_thread(LOCK_DRAW_IMAGE); - if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) { - oglrender->ima->flag |= IMA_IS_STEREO; - } - else { - oglrender->ima->flag &= ~IMA_IS_STEREO; + if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) oglrender->iuser.flag &= ~IMA_SHOW_STEREO; - } BLI_unlock_thread(LOCK_DRAW_IMAGE); /* will only work for non multiview correctly */ @@ -256,9 +258,6 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; Object *camera = NULL; - ImBuf *ibuf; - float winmat[4][4]; - float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf; int sizex = oglrender->sizex; int sizey = oglrender->sizey; const short view_context = (v3d != NULL); @@ -268,48 +267,35 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) 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); + /* use pre-calculated ImBuf (avoids deadlock), see: */ + ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id]; if (ibuf) { - ImBuf *linear_ibuf; - - BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); - - linear_ibuf = IMB_dupImBuf(ibuf); + ImBuf *out = 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); + /* 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); } - else { - /* ensure float buffer is in linear space, not in display space */ - BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf); - } - - memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); - - IMB_freeImBuf(linear_ibuf); + 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); @@ -326,114 +312,41 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); - BLI_assert(rectf != NULL); - 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(&rectf[i], &rectf[i], col_src); + blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]); } 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) { -#if 0 - const bool is_ortho = (scene->r.mode & R_ORTHO) != 0; -#endif - 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 { + /* 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 - 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); + 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; } - 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; @@ -472,7 +385,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) /* 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); + BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4); MEM_freeN(rect); } @@ -509,8 +422,31 @@ static void screen_opengl_render_apply(OGLRender *oglrender) ImBuf *ibuf; void *lock; + if (oglrender->is_sequencer) { + Scene *scene = oglrender->scene; + + SeqRenderData context; + SpaceSeq *sseq = oglrender->sseq; + int chanshown = sseq ? sseq->chanshown : 0; + + BKE_sequencer_new_render_data( + oglrender->bmain->eval_ctx, oglrender->bmain, scene, + oglrender->sizex, oglrender->sizey, 100.0f, + &context); + + for (view_id = 0; view_id < oglrender->views_len; view_id++) { + context.view_id = view_id; + context.gpu_offscreen = oglrender->ofs; + context.gpu_fx = oglrender->fx; + context.gpu_full_samples = oglrender->ofs_full_samples; + + oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); + } + } + rr = RE_AcquireResultRead(oglrender->re); for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) { + BLI_assert(view_id < oglrender->views_len); RE_SetActiveRenderView(oglrender->re, rv->name); oglrender->view_id = view_id; screen_opengl_render_doit(oglrender, rr); @@ -541,6 +477,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; + const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; + const bool full_samples = (samples != 0) && (scene->r.scemode & R_FULL_SAMPLE); bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); @@ -585,7 +523,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, err_out); + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); @@ -597,6 +535,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) op->customdata = oglrender; oglrender->ofs = ofs; + oglrender->ofs_samples = samples; + oglrender->ofs_full_samples = full_samples; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); @@ -605,9 +545,13 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->write_still = is_write_still && !is_animation; + oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r); + oglrender->is_sequencer = is_sequencer; if (is_sequencer) { oglrender->sseq = CTX_wm_space_seq(C); + ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__); + oglrender->seq_data.ibufs_arr = ibufs_arr; } oglrender->prevsa = prevsa; @@ -635,7 +579,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE); - BKE_image_backup_render(oglrender->scene, oglrender->ima); + BKE_image_backup_render(oglrender->scene, oglrender->ima, true); oglrender->iuser.scene = scene; oglrender->iuser.ok = 1; @@ -661,7 +605,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) { Main *bmain = CTX_data_main(C); Scene *scene = oglrender->scene; - size_t i; + int i; if (oglrender->mh) { if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { @@ -692,6 +636,10 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) GPU_offscreen_free(oglrender->ofs); + if (oglrender->is_sequencer) { + MEM_freeN(oglrender->seq_data.ibufs_arr); + } + oglrender->scene->customdata_mask_modal = 0; CTX_wm_area_set(C, oglrender->prevsa); @@ -706,7 +654,7 @@ static void screen_opengl_render_cancel(bContext *C, wmOperator *op) } /* share between invoke and exec */ -static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) +static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) { /* initialize animation */ OGLRender *oglrender; @@ -719,12 +667,20 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->reports = op->reports; if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - size_t i, width, height; + size_t width, height; + int i; BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height); - oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); + if (oglrender->mh == NULL) { + BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported"); + screen_opengl_render_end(C, oglrender); + return false; + } + + oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); + for (i = 0; i < oglrender->totvideos; i++) { const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i); @@ -733,7 +689,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix)) { screen_opengl_render_end(C, oglrender); - return 0; + return false; } } } @@ -742,7 +698,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->nfra = PSFRA; scene->r.cfra = PSFRA; - return 1; + return true; } static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) @@ -807,8 +763,8 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) rr = RE_AcquireResultRead(oglrender->re); if (is_movie) { - ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex, - oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0); + ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, + oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0); if (ok) { printf("Append frame %d", scene->r.cfra); BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra); @@ -904,7 +860,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven } oglrender = op->customdata; - render_view_open(C, event->x, event->y); + render_view_open(C, event->x, event->y, op->reports); /* view may be changed above (R_OUTPUT_WINDOW) */ oglrender->win = CTX_wm_window(C); |