This includes much improved GPU rendering performance, viewport interactivity, new shadow catcher, revamped sampling settings, subsurface scattering anisotropy, new GPU volume sampling, improved PMJ sampling pattern, and more. Some features have also been removed or changed, breaking backwards compatibility. Including the removal of the OpenCL backend, for which alternatives are under development. Release notes and code docs: https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles https://wiki.blender.org/wiki/Source/Render/Cycles Credits: * Sergey Sharybin * Brecht Van Lommel * Patrick Mours (OptiX backend) * Christophe Hery (subsurface scattering anisotropy) * William Leeson (PMJ sampling pattern) * Alaska (various fixes and tweaks) * Thomas Dinges (various fixes) For the full commit history, see the cycles-x branch. This squashes together all the changes since intermediate changes would often fail building or tests. Ref T87839, T87837, T87836 Fixes T90734, T89353, T80267, T80267, T77185, T69800
421 lines
14 KiB
C
421 lines
14 KiB
C
/*
|
|
* 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 2019, Blender Foundation.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup draw_engine
|
|
*
|
|
* Engine for drawing a selection map where the pixels indicate the selection indices.
|
|
*/
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "UI_resources.h"
|
|
|
|
#include "DRW_engine.h"
|
|
#include "DRW_select_buffer.h"
|
|
|
|
#include "draw_cache_impl.h"
|
|
#include "draw_manager.h"
|
|
|
|
#include "select_engine.h"
|
|
#include "select_private.h"
|
|
|
|
#define SELECT_ENGINE "SELECT_ENGINE"
|
|
|
|
/* *********** STATIC *********** */
|
|
|
|
static struct {
|
|
struct GPUFrameBuffer *framebuffer_select_id;
|
|
struct GPUTexture *texture_u32;
|
|
|
|
SELECTID_Shaders sh_data[GPU_SHADER_CFG_LEN];
|
|
struct SELECTID_Context context;
|
|
uint runtime_new_objects;
|
|
} e_data = {NULL}; /* Engine data */
|
|
|
|
/* Shaders */
|
|
extern char datatoc_common_view_lib_glsl[];
|
|
extern char datatoc_selection_id_3D_vert_glsl[];
|
|
extern char datatoc_selection_id_frag_glsl[];
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Utils
|
|
* \{ */
|
|
|
|
static void select_engine_framebuffer_setup(void)
|
|
{
|
|
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
|
int size[2];
|
|
size[0] = GPU_texture_width(dtxl->depth);
|
|
size[1] = GPU_texture_height(dtxl->depth);
|
|
|
|
if (e_data.framebuffer_select_id == NULL) {
|
|
e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id");
|
|
}
|
|
|
|
if ((e_data.texture_u32 != NULL) && ((GPU_texture_width(e_data.texture_u32) != size[0]) ||
|
|
(GPU_texture_height(e_data.texture_u32) != size[1]))) {
|
|
GPU_texture_free(e_data.texture_u32);
|
|
e_data.texture_u32 = NULL;
|
|
}
|
|
|
|
/* Make sure the depth texture is attached.
|
|
* It may disappear when loading another Blender session. */
|
|
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0);
|
|
|
|
if (e_data.texture_u32 == NULL) {
|
|
e_data.texture_u32 = GPU_texture_create_2d(
|
|
"select_buf_ids", size[0], size[1], 1, GPU_R32UI, NULL);
|
|
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0);
|
|
|
|
GPU_framebuffer_check_valid(e_data.framebuffer_select_id, NULL);
|
|
}
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Engine Functions
|
|
* \{ */
|
|
|
|
static void select_engine_init(void *vedata)
|
|
{
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg;
|
|
|
|
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
|
|
SELECTID_Shaders *sh_data = &e_data.sh_data[sh_cfg];
|
|
|
|
/* Prepass */
|
|
if (!sh_data->select_id_flat) {
|
|
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
|
|
sh_data->select_id_flat = GPU_shader_create_from_arrays({
|
|
.vert = (const char *[]){sh_cfg_data->lib,
|
|
datatoc_common_view_lib_glsl,
|
|
datatoc_selection_id_3D_vert_glsl,
|
|
NULL},
|
|
.frag = (const char *[]){datatoc_selection_id_frag_glsl, NULL},
|
|
.defs = (const char *[]){sh_cfg_data->def, NULL},
|
|
});
|
|
}
|
|
if (!sh_data->select_id_uniform) {
|
|
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
|
|
sh_data->select_id_uniform = GPU_shader_create_from_arrays({
|
|
.vert = (const char *[]){sh_cfg_data->lib,
|
|
datatoc_common_view_lib_glsl,
|
|
datatoc_selection_id_3D_vert_glsl,
|
|
NULL},
|
|
.frag = (const char *[]){datatoc_selection_id_frag_glsl, NULL},
|
|
.defs = (const char *[]){sh_cfg_data->def, "#define UNIFORM_ID\n", NULL},
|
|
});
|
|
}
|
|
|
|
if (!stl->g_data) {
|
|
/* Alloc transient pointers */
|
|
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
|
|
}
|
|
|
|
{
|
|
/* Create view from a subregion */
|
|
const DRWView *view_default = DRW_view_default_get();
|
|
float viewmat[4][4], winmat[4][4], winmat_subregion[4][4];
|
|
DRW_view_viewmat_get(view_default, viewmat, false);
|
|
DRW_view_winmat_get(view_default, winmat, false);
|
|
projmat_from_subregion(winmat,
|
|
(int[2]){draw_ctx->region->winx, draw_ctx->region->winy},
|
|
e_data.context.last_rect.xmin,
|
|
e_data.context.last_rect.xmax,
|
|
e_data.context.last_rect.ymin,
|
|
e_data.context.last_rect.ymax,
|
|
winmat_subregion);
|
|
|
|
stl->g_data->view_subregion = DRW_view_create(viewmat, winmat_subregion, NULL, NULL, NULL);
|
|
|
|
/* Create view with depth offset */
|
|
stl->g_data->view_faces = (DRWView *)view_default;
|
|
stl->g_data->view_edges = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.0f);
|
|
stl->g_data->view_verts = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.1f);
|
|
}
|
|
}
|
|
|
|
static void select_cache_init(void *vedata)
|
|
{
|
|
SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
|
|
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
|
|
SELECTID_PrivateData *pd = stl->g_data;
|
|
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
SELECTID_Shaders *sh = &e_data.sh_data[draw_ctx->sh_cfg];
|
|
|
|
if (e_data.context.select_mode == -1) {
|
|
e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene,
|
|
draw_ctx->obact);
|
|
BLI_assert(e_data.context.select_mode != 0);
|
|
}
|
|
|
|
DRWState state = DRW_STATE_DEFAULT;
|
|
state |= RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? DRW_STATE_CLIP_PLANES : 0;
|
|
|
|
{
|
|
DRW_PASS_CREATE(psl->depth_only_pass, state);
|
|
pd->shgrp_depth_only = DRW_shgroup_create(sh->select_id_uniform, psl->depth_only_pass);
|
|
|
|
DRW_PASS_CREATE(psl->select_id_face_pass, state);
|
|
if (e_data.context.select_mode & SCE_SELECT_FACE) {
|
|
pd->shgrp_face_flat = DRW_shgroup_create(sh->select_id_flat, psl->select_id_face_pass);
|
|
}
|
|
else {
|
|
pd->shgrp_face_unif = DRW_shgroup_create(sh->select_id_uniform, psl->select_id_face_pass);
|
|
DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "id", 0);
|
|
}
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
|
DRW_PASS_CREATE(psl->select_id_edge_pass, state | DRW_STATE_FIRST_VERTEX_CONVENTION);
|
|
|
|
pd->shgrp_edge = DRW_shgroup_create(sh->select_id_flat, psl->select_id_edge_pass);
|
|
}
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
|
DRW_PASS_CREATE(psl->select_id_vert_pass, state);
|
|
pd->shgrp_vert = DRW_shgroup_create(sh->select_id_flat, psl->select_id_vert_pass);
|
|
DRW_shgroup_uniform_float_copy(pd->shgrp_vert, "sizeVertex", 2 * G_draw.block.sizeVertex);
|
|
}
|
|
}
|
|
|
|
/* Check if the viewport has changed. */
|
|
float(*persmat)[4] = draw_ctx->rv3d->persmat;
|
|
e_data.context.is_dirty = !compare_m4m4(e_data.context.persmat, persmat, FLT_EPSILON);
|
|
|
|
if (!e_data.context.is_dirty) {
|
|
/* Check if any of the drawn objects have been transformed. */
|
|
Object **ob = &e_data.context.objects_drawn[0];
|
|
for (uint i = e_data.context.objects_drawn_len; i--; ob++) {
|
|
DrawData *data = DRW_drawdata_get(&(*ob)->id, &draw_engine_select_type);
|
|
if (data && (data->recalc & ID_RECALC_TRANSFORM) != 0) {
|
|
data->recalc &= ~ID_RECALC_TRANSFORM;
|
|
e_data.context.is_dirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e_data.context.is_dirty) {
|
|
/* Remove all tags from drawn or culled objects. */
|
|
copy_m4_m4(e_data.context.persmat, persmat);
|
|
e_data.context.objects_drawn_len = 0;
|
|
e_data.context.index_drawn_len = 1;
|
|
select_engine_framebuffer_setup();
|
|
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
|
GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, (const float[4]){0.0f}, 1.0f);
|
|
}
|
|
e_data.runtime_new_objects = 0;
|
|
}
|
|
|
|
static void select_cache_populate(void *vedata, Object *ob)
|
|
{
|
|
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
|
|
const DRWContextState *draw_ctx = DRW_context_state_get();
|
|
|
|
SELECTID_ObjectData *sel_data = (SELECTID_ObjectData *)DRW_drawdata_get(
|
|
&ob->id, &draw_engine_select_type);
|
|
|
|
if (!e_data.context.is_dirty && sel_data && sel_data->is_drawn) {
|
|
/* The object indices have already been drawn. Fill depth pass.
|
|
* Opti: Most of the time this depth pass is not used. */
|
|
struct Mesh *me = ob->data;
|
|
if (e_data.context.select_mode & SCE_SELECT_FACE) {
|
|
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
|
|
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
|
|
}
|
|
else if (ob->dt >= OB_SOLID) {
|
|
#ifdef USE_CAGE_OCCLUSION
|
|
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me);
|
|
#else
|
|
struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me);
|
|
#endif
|
|
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat);
|
|
}
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
|
struct GPUBatch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me);
|
|
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_edges, ob->obmat);
|
|
}
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
|
struct GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me);
|
|
DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_verts, ob->obmat);
|
|
}
|
|
return;
|
|
}
|
|
|
|
float min[3], max[3];
|
|
select_id_object_min_max(ob, min, max);
|
|
|
|
if (DRW_culling_min_max_test(stl->g_data->view_subregion, ob->obmat, min, max)) {
|
|
if (sel_data == NULL) {
|
|
sel_data = (SELECTID_ObjectData *)DRW_drawdata_ensure(
|
|
&ob->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), NULL, NULL);
|
|
}
|
|
sel_data->dd.recalc = 0;
|
|
sel_data->drawn_index = e_data.context.objects_drawn_len;
|
|
sel_data->is_drawn = true;
|
|
|
|
struct ObjectOffsets *ob_offsets =
|
|
&e_data.context.index_offsets[e_data.context.objects_drawn_len];
|
|
|
|
uint offset = e_data.context.index_drawn_len;
|
|
select_id_draw_object(vedata,
|
|
draw_ctx->v3d,
|
|
ob,
|
|
e_data.context.select_mode,
|
|
offset,
|
|
&ob_offsets->vert,
|
|
&ob_offsets->edge,
|
|
&ob_offsets->face);
|
|
|
|
ob_offsets->offset = offset;
|
|
e_data.context.index_drawn_len = ob_offsets->vert;
|
|
e_data.context.objects_drawn[e_data.context.objects_drawn_len] = ob;
|
|
e_data.context.objects_drawn_len++;
|
|
e_data.runtime_new_objects++;
|
|
}
|
|
else if (sel_data) {
|
|
sel_data->is_drawn = false;
|
|
}
|
|
}
|
|
|
|
static void select_draw_scene(void *vedata)
|
|
{
|
|
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
|
|
SELECTID_PassList *psl = ((SELECTID_Data *)vedata)->psl;
|
|
|
|
if (!e_data.runtime_new_objects) {
|
|
/* Nothing new needs to be drawn. */
|
|
return;
|
|
}
|
|
|
|
DRW_view_set_active(stl->g_data->view_faces);
|
|
|
|
if (!DRW_pass_is_empty(psl->depth_only_pass)) {
|
|
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
|
GPU_framebuffer_bind(dfbl->depth_only_fb);
|
|
GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f);
|
|
DRW_draw_pass(psl->depth_only_pass);
|
|
}
|
|
|
|
/* Setup framebuffer */
|
|
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
|
|
|
DRW_draw_pass(psl->select_id_face_pass);
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
|
DRW_view_set_active(stl->g_data->view_edges);
|
|
DRW_draw_pass(psl->select_id_edge_pass);
|
|
}
|
|
|
|
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
|
DRW_view_set_active(stl->g_data->view_verts);
|
|
DRW_draw_pass(psl->select_id_vert_pass);
|
|
}
|
|
}
|
|
|
|
static void select_engine_free(void)
|
|
{
|
|
for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
|
|
SELECTID_Shaders *sh_data = &e_data.sh_data[sh_data_index];
|
|
DRW_SHADER_FREE_SAFE(sh_data->select_id_flat);
|
|
DRW_SHADER_FREE_SAFE(sh_data->select_id_uniform);
|
|
}
|
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.texture_u32);
|
|
GPU_FRAMEBUFFER_FREE_SAFE(e_data.framebuffer_select_id);
|
|
MEM_SAFE_FREE(e_data.context.objects);
|
|
MEM_SAFE_FREE(e_data.context.index_offsets);
|
|
MEM_SAFE_FREE(e_data.context.objects_drawn);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Engine Type
|
|
* \{ */
|
|
|
|
static const DrawEngineDataSize select_data_size = DRW_VIEWPORT_DATA_SIZE(SELECTID_Data);
|
|
|
|
DrawEngineType draw_engine_select_type = {
|
|
NULL,
|
|
NULL,
|
|
N_("Select ID"),
|
|
&select_data_size,
|
|
&select_engine_init,
|
|
&select_engine_free,
|
|
&select_cache_init,
|
|
&select_cache_populate,
|
|
NULL,
|
|
&select_draw_scene,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
/* NOTE: currently unused, we may want to register so we can see this when debugging the view. */
|
|
|
|
RenderEngineType DRW_engine_viewport_select_type = {
|
|
NULL,
|
|
NULL,
|
|
SELECT_ENGINE,
|
|
N_("Select ID"),
|
|
RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&draw_engine_select_type,
|
|
{NULL, NULL, NULL},
|
|
};
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Exposed `select_private.h` functions
|
|
* \{ */
|
|
|
|
struct SELECTID_Context *DRW_select_engine_context_get(void)
|
|
{
|
|
return &e_data.context;
|
|
}
|
|
|
|
GPUFrameBuffer *DRW_engine_select_framebuffer_get(void)
|
|
{
|
|
return e_data.framebuffer_select_id;
|
|
}
|
|
|
|
GPUTexture *DRW_engine_select_texture_get(void)
|
|
{
|
|
return e_data.texture_u32;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
#undef SELECT_ENGINE
|