Fix #34817: improve OpenGL preview render speed, it got quite a bit slower since 2.60.

Doing linearization with GLSL was already faster, but even faster is to just read the
bytes instead of floats and convert those to linear, since byte => float is just a quick
256 entry table lookup. Also made it assign the bytes directly to the image buffer so
they do not need to be converted back from float to byte for file saving, and made sky
render write the background color with OpenGL instead of doing it on the CPU.
This commit is contained in:
Brecht Van Lommel 2013-04-11 15:15:06 +00:00
parent 7164596891
commit 120fe74ffe
3 changed files with 60 additions and 52 deletions

@ -281,7 +281,7 @@ int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
bool ED_view3d_context_activate(struct bContext *C);
void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
void ED_view3d_draw_offscreen(struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic);
int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
bool draw_background, int alpha_mode, char err_out[256]);

@ -135,6 +135,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
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);
@ -167,7 +170,6 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
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);
@ -194,23 +196,27 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
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, TRUE);
GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, rr->rectf);
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];
float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float) * 4, "accum1");
float *accum_tmp = MEM_mallocN(sizex * sizey * sizeof(float) * 4, "accum2");
int j;
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, TRUE);
GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_buffer);
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++) {
@ -219,15 +225,17 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
(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, TRUE);
GPU_offscreen_read_pixels(oglrender->ofs, GL_FLOAT, accum_tmp);
add_vn_vn(accum_buffer, accum_tmp, sizex * sizey * sizeof(float));
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];
}
mul_vn_vn_fl(rr->rectf, accum_buffer, sizex * sizey * sizeof(float), 1.0f / scene->r.osa);
for (i = 0; i < sizex * sizey * 4; i++)
rect[i] = accum_buffer[i] / scene->r.osa;
MEM_freeN(accum_buffer);
MEM_freeN(accum_tmp);
}
GPU_offscreen_unbind(oglrender->ofs); /* unbind */
@ -236,11 +244,15 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* 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_rectfloat, OB_SOLID, FALSE, TRUE, R_ALPHAPREMUL, err_out);
IB_rect, OB_SOLID, FALSE, TRUE,
(draw_sky)? R_ADDSKY: R_ALPHAPREMUL, err_out);
camera = scene->camera;
if (ibuf_view) {
memcpy(rr->rectf, ibuf_view->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
/* steal rect reference from ibuf */
rect = (unsigned char*)ibuf_view->rect;
ibuf_view->mall &= ~IB_rect;
IMB_freeImBuf(ibuf_view);
}
else {
@ -248,12 +260,6 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
}
}
if (scene->r.alphamode == R_ADDSKY) {
float sky_color[3];
ED_view3d_offscreen_sky_color_get(scene, sky_color);
IMB_alpha_under_color_float(rr->rectf, sizex, sizey, sky_color);
}
/* note on color management:
*
* OpenGL renders into sRGB colors, but render buffers are expected to be
@ -262,21 +268,18 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
* correct linear float buffer.
*/
if (!oglrender->is_sequencer) {
if (rect) {
/* 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);
}
* also assume opengl's space matches byte buffer color space */
IMB_buffer_float_from_byte(rr->rectf, rect,
IB_PROFILE_LINEAR_RGB, 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, NULL, rr->rectf, rr->rectx, rr->recty, 4);
BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
RE_ReleaseResult(oglrender->re);
@ -284,8 +287,15 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
if (ibuf) {
image_buffer_rect_update(scene, rr, ibuf, NULL);
/* 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;
@ -302,6 +312,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
}
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
if (rect)
MEM_freeN(rect);
}
static int screen_opengl_render_init(bContext *C, wmOperator *op)

@ -2463,7 +2463,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
/* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, false);
ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, false, false);
GPU_lamp_shadow_buffer_unbind(shadow->lamp);
v3d->drawtype = drawtype;
@ -2611,7 +2611,7 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
* stuff like shadow buffers
*/
void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
float viewmat[4][4], float winmat[4][4], bool do_bgpic)
float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky)
{
RegionView3D *rv3d = ar->regiondata;
Base *base;
@ -2642,7 +2642,16 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
* warning! can be slow so only free animated images - campbell */
GPU_free_images_anim();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
/* clear opengl buffers */
if (do_sky) {
float sky_color[3];
ED_view3d_offscreen_sky_color_get(scene, sky_color);
glClearColor(sky_color[0], sky_color[1], sky_color[2], 1.0f);
}
else {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -2753,18 +2762,6 @@ void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3])
UI_GetThemeColor3fv(TH_BACK, sky_color);
}
static void offscreen_imbuf_add_sky(ImBuf *ibuf, Scene *scene)
{
float sky_color[3];
ED_view3d_offscreen_sky_color_get(scene, sky_color);
if (ibuf->rect_float)
IMB_alpha_under_color_float(ibuf->rect_float, ibuf->x, ibuf->y, sky_color);
else
IMB_alpha_under_color_byte((unsigned char *) ibuf->rect, ibuf->x, ibuf->y, sky_color);
}
/* utility func for ED_view3d_draw_offscreen */
ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
bool draw_background, int alpha_mode, char err_out[256])
@ -2772,6 +2769,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
RegionView3D *rv3d = ar->regiondata;
ImBuf *ibuf;
GPUOffScreen *ofs;
bool draw_sky = (alpha_mode == R_ADDSKY);
/* state changes make normal drawing go weird otherwise */
glPushAttrib(GL_LIGHTING_BIT);
@ -2794,10 +2792,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background);
ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background, draw_sky);
}
else {
ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background);
ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background, draw_sky);
}
/* read in pixels & stamp */
@ -2808,9 +2806,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
else if (ibuf->rect)
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
if (alpha_mode == R_ADDSKY)
offscreen_imbuf_add_sky(ibuf, scene);
/* unbind */
GPU_offscreen_unbind(ofs);
GPU_offscreen_free(ofs);