Files
test/source/blender/draw/engines/workbench/workbench_render.c
Hans Goudey 5b87862ddc Curves: Further split of curves draw code from particles
Extends the changes started in f31c3f8114 to completely separate
much of the DRW curves code from the particle hair drawing. In the short
term this increases duplication, but the idea is to simplify development
by making it easier to do larger changes to the new code, and the new
system will replace the particle hair at some point.

After this, only the shaders themselves are shared.

Differential Revision: https://developer.blender.org/D14699
2022-04-22 10:44:01 -05:00

213 lines
6.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2016 Blender Foundation. */
/** \file
* \ingroup draw_engine
*
* Render functions for final render output.
*/
#include "BLI_rect.h"
#include "DNA_node_types.h"
#include "BKE_report.h"
#include "DRW_render.h"
#include "ED_view3d.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_cache(void *vedata,
struct Object *ob,
struct RenderEngine *UNUSED(engine),
struct Depsgraph *UNUSED(depsgraph))
{
workbench_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? */
struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
/* Set the perspective, view and window matrix. */
float winmat[4][4], viewmat[4][4], viewinv[4][4];
RE_GetCameraWindow(engine->re, ob_camera_eval, winmat);
RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv);
invert_m4_m4(viewmat, viewinv);
DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
DRW_view_default_set(view);
DRW_view_set_active(view);
}
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();
/* When doing a multi view rendering the first view will allocate the buffers
* the other views will reuse these buffers */
if (dtxl->color == NULL) {
BLI_assert(dtxl->depth == NULL);
dtxl->color = GPU_texture_create_2d("txl.color", UNPACK2(size), 1, GPU_RGBA16F, NULL);
dtxl->depth = GPU_texture_create_2d("txl.depth", UNPACK2(size), 1, GPU_DEPTH24_STENCIL8, 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_result_z(struct RenderLayer *rl,
const char *viewname,
const rcti *rect)
{
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_read_depth(dfbl->default_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
GPU_DATA_FLOAT,
rp->rect);
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert ogl depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
for (int i = 0; i < pix_ct; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
}
}
}
else {
/* Keep in mind, near and far distance are negatives. */
float near = DRW_view_near_distance_get(NULL);
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
for (int i = 0; i < pix_ct; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * range - near;
}
}
}
}
}
void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
{
WORKBENCH_Data *data = ved;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
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;
}
workbench_private_data_alloc(data->stl);
data->stl->wpd->cam_original_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
workbench_engine_init(data);
workbench_cache_init(data);
DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache);
workbench_cache_finish(data);
DRW_render_instance_buffer_finish();
/* Also we weed to have a correct FBO bound for #DRW_curves_update */
GPU_framebuffer_bind(dfbl->default_fb);
DRW_curves_update();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
WORKBENCH_PrivateData *wpd = data->stl->wpd;
while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
if (RE_engine_test_break(engine)) {
break;
}
workbench_update_world_ubo(wpd);
workbench_draw_sample(data);
}
workbench_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->default_fb);
GPU_framebuffer_read_color(dfbl->default_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
4,
0,
GPU_DATA_FLOAT,
rp->rect);
workbench_render_result_z(render_layer, viewname, rect);
}
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);
}