/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright 2016, Blender Foundation. */ /** \file * \ingroup draw_engine * * Render functions for final render output. */ #include "BLI_rect.h" #include "BKE_report.h" #include "DRW_render.h" #include "GPU_shader.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "RE_pipeline.h" #include "workbench_private.h" static void workbench_render_deferred_cache( void *vedata, struct Object *ob, struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph)) { workbench_deferred_solid_cache_populate(vedata, ob); } static void workbench_render_forward_cache( void *vedata, struct Object *ob, struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph)) { workbench_forward_cache_populate(vedata, ob); } static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph) { /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ Scene *scene = DEG_get_evaluated_scene(depsgraph); struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); float frame = BKE_scene_frame_get(scene); /* Set the persective, view and window matrix. */ float winmat[4][4], wininv[4][4]; float viewmat[4][4], viewinv[4][4]; float persmat[4][4], persinv[4][4]; RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat); RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv); invert_m4_m4(viewmat, viewinv); mul_m4_m4m4(persmat, winmat, viewmat); invert_m4_m4(persinv, persmat); invert_m4_m4(wininv, winmat); DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV); DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); } static bool workbench_render_framebuffers_init(void) { /* For image render, allocate own buffers because we don't have a viewport. */ const float *viewport_size = DRW_viewport_size_get(); const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); dtxl->color = GPU_texture_create_2D(size[0], size[1], GPU_RGBA16F, NULL, NULL); dtxl->depth = GPU_texture_create_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, NULL); if (!(dtxl->depth && dtxl->color)) { return false; } DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); GPU_framebuffer_ensure_config(&dfbl->default_fb, { GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color) }); GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, { GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_NONE }); GPU_framebuffer_ensure_config(&dfbl->color_only_fb, { GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(dtxl->color) }); bool ok = true; ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL); return ok; } static void workbench_render_framebuffers_finish(void) { } void workbench_render(WORKBENCH_Data *data, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect) { DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene = draw_ctx->scene; Depsgraph *depsgraph = draw_ctx->depsgraph; workbench_render_matrices_init(engine, depsgraph); if (!workbench_render_framebuffers_init()) { RE_engine_report(engine, RPT_ERROR, "Failed to allocate OpenGL buffers"); return; } const bool deferred = (scene->display.shading.flag & XRAY_FLAG(&scene->display)) == 0; if (deferred) { /* Init engine. */ workbench_deferred_engine_init(data); /* Init objects. */ workbench_deferred_cache_init(data); DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache); workbench_deferred_cache_finish(data); DRW_render_instance_buffer_finish(); /* Also we weed to have a correct fbo bound for DRW_hair_update */ GPU_framebuffer_bind(dfbl->color_only_fb); DRW_hair_update(); /* Draw. */ int num_samples = workbench_taa_calculate_num_iterations(data); for (int sample = 0; sample < num_samples; sample++) { if (RE_engine_test_break(engine)) { break; } /* TODO: Save matrices instead of recomputing them for each samples. */ workbench_render_matrices_init(engine, depsgraph); workbench_deferred_draw_background(data); workbench_deferred_draw_scene(data); } workbench_deferred_draw_finish(data); } else { /* Init engine. */ workbench_forward_engine_init(data); /* Init objects. */ workbench_forward_cache_init(data); DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache); workbench_forward_cache_finish(data); DRW_render_instance_buffer_finish(); /* Also we weed to have a correct fbo bound for DRW_hair_update */ GPU_framebuffer_bind(dfbl->color_only_fb); DRW_hair_update(); /* Draw. */ int num_samples = workbench_taa_calculate_num_iterations(data); for (int sample = 0; sample < num_samples; sample++) { if (RE_engine_test_break(engine)) { break; } workbench_forward_draw_background(data); workbench_forward_draw_scene(data); } workbench_forward_draw_finish(data); } /* Write render output. */ const char *viewname = RE_GetActiveRenderView(engine->re); RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); GPU_framebuffer_bind(dfbl->color_only_fb); GPU_framebuffer_read_color(dfbl->color_only_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect); workbench_render_framebuffers_finish(); } void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) { RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA); }