Core: Fix/refactor invalid logic around handling of 'default materials'.
These were handled mostly completely outside of IDManagement code, yet (ab)using the same ID management system in some cases, adding hacks to address some issues, etc. Also address a similar issue in the eevee lookdev `LookdevWorld` code. Since initializing pre-allocated (or static) buffers as valid IDs is not currently supported, and these use-cases do not seem common enough to be worth supporting it currently, instead switch to storing allocated IDs into static pointers. This allows to use proper 'out-of-main' ID creation code API. NOTE: There are still some remaining issues, especially in the GP material BKE api. These are noted in comments for now, as it would be out of scope to address them in this commit. Pull Request: https://projects.blender.org/blender/blender/pulls/138263
This commit is contained in:
committed by
Bastien Montagne
parent
58247efc69
commit
368c737fe7
@@ -215,6 +215,11 @@ void ramp_blend(int type, float r_col[3], float fac, const float col[3]);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Default Materials
|
||||
*
|
||||
* TODO: Explain expected usages? Seems to be primarily defined for GPU/viewport code?
|
||||
*
|
||||
* \warning _NEVER_ use these materials as fallback data for regular ID data. They should only be
|
||||
* used as template/copy source, or in some very specific, local and short-lived contexts.
|
||||
* \{ */
|
||||
|
||||
Material *BKE_material_default_empty();
|
||||
|
||||
@@ -2589,6 +2589,8 @@ Material *BKE_grease_pencil_object_material_ensure_from_brush(Main *bmain,
|
||||
}
|
||||
|
||||
/* Fall back to default material. */
|
||||
/* XXX FIXME This is critical abuse of the 'default material' feature, these IDs should never be
|
||||
* used/returned as 'regular' data. */
|
||||
return BKE_material_default_gpencil();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,8 +88,6 @@ static void material_init_data(ID *id)
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(material, id));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(material, DNA_struct_default_get(Material), id);
|
||||
|
||||
*((short *)id->name) = ID_MA;
|
||||
}
|
||||
|
||||
static void material_copy_data(Main *bmain,
|
||||
@@ -937,6 +935,8 @@ Material *BKE_gpencil_material(Object *ob, short act)
|
||||
return ma;
|
||||
}
|
||||
|
||||
/* XXX FIXME This is critical abuse of the 'default material' feature, these IDs should never be
|
||||
* used/returned as 'regular' data. */
|
||||
return BKE_material_default_gpencil();
|
||||
}
|
||||
|
||||
@@ -2016,29 +2016,37 @@ void BKE_material_eval(Depsgraph *depsgraph, Material *material)
|
||||
* Used for rendering when objects have no materials assigned, and initializing
|
||||
* default shader nodes. */
|
||||
|
||||
static Material default_material_empty;
|
||||
static Material default_material_holdout;
|
||||
static Material default_material_surface;
|
||||
static Material default_material_volume;
|
||||
static Material default_material_gpencil;
|
||||
static Material *default_material_empty = nullptr;
|
||||
static Material *default_material_holdout = nullptr;
|
||||
static Material *default_material_surface = nullptr;
|
||||
static Material *default_material_volume = nullptr;
|
||||
static Material *default_material_gpencil = nullptr;
|
||||
|
||||
static Material *default_materials[] = {&default_material_empty,
|
||||
&default_material_holdout,
|
||||
&default_material_surface,
|
||||
&default_material_volume,
|
||||
&default_material_gpencil,
|
||||
nullptr};
|
||||
static Material **default_materials[] = {&default_material_empty,
|
||||
&default_material_holdout,
|
||||
&default_material_surface,
|
||||
&default_material_volume,
|
||||
&default_material_gpencil,
|
||||
nullptr};
|
||||
|
||||
static void material_default_gpencil_init(Material *ma)
|
||||
static Material *material_default_create(Material **ma_p, const char *name)
|
||||
{
|
||||
BLI_strncpy(ma->id.name + 2, "Default GPencil", MAX_NAME);
|
||||
*ma_p = static_cast<Material *>(
|
||||
BKE_libblock_alloc_in_lib(nullptr, std::nullopt, ID_MA, name, LIB_ID_CREATE_NO_MAIN));
|
||||
return *ma_p;
|
||||
}
|
||||
|
||||
static void material_default_gpencil_init(Material **ma_p)
|
||||
{
|
||||
Material *ma = material_default_create(ma_p, "Default GPencil");
|
||||
|
||||
BKE_gpencil_material_attr_init(ma);
|
||||
add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
|
||||
}
|
||||
|
||||
static void material_default_surface_init(Material *ma)
|
||||
static void material_default_surface_init(Material **ma_p)
|
||||
{
|
||||
BLI_strncpy(ma->id.name + 2, "Default Surface", MAX_NAME);
|
||||
Material *ma = material_default_create(ma_p, "Default Surface");
|
||||
|
||||
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
|
||||
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
|
||||
@@ -2064,9 +2072,9 @@ static void material_default_surface_init(Material *ma)
|
||||
blender::bke::node_set_active(*ntree, *output);
|
||||
}
|
||||
|
||||
static void material_default_volume_init(Material *ma)
|
||||
static void material_default_volume_init(Material **ma_p)
|
||||
{
|
||||
BLI_strncpy(ma->id.name + 2, "Default Volume", MAX_NAME);
|
||||
Material *ma = material_default_create(ma_p, "Default Volume");
|
||||
|
||||
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
|
||||
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
|
||||
@@ -2090,9 +2098,9 @@ static void material_default_volume_init(Material *ma)
|
||||
blender::bke::node_set_active(*ntree, *output);
|
||||
}
|
||||
|
||||
static void material_default_holdout_init(Material *ma)
|
||||
static void material_default_holdout_init(Material **ma_p)
|
||||
{
|
||||
BLI_strncpy(ma->id.name + 2, "Default Holdout", MAX_NAME);
|
||||
Material *ma = material_default_create(ma_p, "Default Holdout");
|
||||
|
||||
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
|
||||
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
|
||||
@@ -2117,34 +2125,34 @@ static void material_default_holdout_init(Material *ma)
|
||||
|
||||
Material *BKE_material_default_empty()
|
||||
{
|
||||
return &default_material_empty;
|
||||
return default_material_empty;
|
||||
}
|
||||
|
||||
Material *BKE_material_default_holdout()
|
||||
{
|
||||
return &default_material_holdout;
|
||||
return default_material_holdout;
|
||||
}
|
||||
|
||||
Material *BKE_material_default_surface()
|
||||
{
|
||||
return &default_material_surface;
|
||||
return default_material_surface;
|
||||
}
|
||||
|
||||
Material *BKE_material_default_volume()
|
||||
{
|
||||
return &default_material_volume;
|
||||
return default_material_volume;
|
||||
}
|
||||
|
||||
Material *BKE_material_default_gpencil()
|
||||
{
|
||||
return &default_material_gpencil;
|
||||
return default_material_gpencil;
|
||||
}
|
||||
|
||||
void BKE_material_defaults_free_gpu()
|
||||
{
|
||||
for (int i = 0; default_materials[i]; i++) {
|
||||
Material *ma = default_materials[i];
|
||||
if (ma->gpumaterial.first) {
|
||||
Material *ma = *default_materials[i];
|
||||
if (ma && ma->gpumaterial.first) {
|
||||
GPU_material_free(&ma->gpumaterial);
|
||||
}
|
||||
}
|
||||
@@ -2155,13 +2163,12 @@ void BKE_material_defaults_free_gpu()
|
||||
void BKE_materials_init()
|
||||
{
|
||||
for (int i = 0; default_materials[i]; i++) {
|
||||
/* Note: material_init_data() expects input struct to be initialized at zero.
|
||||
* However, we are initializing global static materials in this function, which will only get
|
||||
* properly defined in the respective material_default_*_init() functions. */
|
||||
memset(&default_materials[i]->id, 0, sizeof(Material));
|
||||
material_init_data(&default_materials[i]->id);
|
||||
BLI_assert_msg(*default_materials[i] == nullptr,
|
||||
"Default material pointers should always be null when initializing them, maybe "
|
||||
"missing a call to `BKE_materials_exit` first?");
|
||||
}
|
||||
|
||||
material_default_create(&default_material_empty, "Default Empty");
|
||||
material_default_surface_init(&default_material_surface);
|
||||
material_default_volume_init(&default_material_volume);
|
||||
material_default_holdout_init(&default_material_holdout);
|
||||
@@ -2171,6 +2178,10 @@ void BKE_materials_init()
|
||||
void BKE_materials_exit()
|
||||
{
|
||||
for (int i = 0; default_materials[i]; i++) {
|
||||
material_free_data(&default_materials[i]->id);
|
||||
Material *ma = *default_materials[i];
|
||||
*default_materials[i] = nullptr;
|
||||
if (ma) {
|
||||
BKE_id_free(nullptr, &ma->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,9 +284,8 @@ PointCloud *BKE_pointcloud_add(Main *bmain, const char *name)
|
||||
|
||||
PointCloud *BKE_pointcloud_add_default(Main *bmain, const char *name)
|
||||
{
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(BKE_libblock_alloc(bmain, ID_PT, name, 0));
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(BKE_id_new(bmain, ID_PT, name));
|
||||
|
||||
pointcloud_init_data(&pointcloud->id);
|
||||
pointcloud_random(pointcloud);
|
||||
|
||||
return pointcloud;
|
||||
@@ -297,7 +296,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(BKE_libblock_alloc(
|
||||
nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
|
||||
|
||||
pointcloud_init_data(&pointcloud->id);
|
||||
BKE_libblock_init_empty(&pointcloud->id);
|
||||
|
||||
CustomData_realloc(&pointcloud->pdata, 0, totpoint);
|
||||
pointcloud->totpoint = totpoint;
|
||||
|
||||
@@ -31,8 +31,11 @@ namespace blender::eevee {
|
||||
|
||||
LookdevWorld::LookdevWorld()
|
||||
{
|
||||
bNodeTree *ntree = bke::node_tree_add_tree(
|
||||
nullptr, "Lookdev World Nodetree", ntreeType_Shader->idname);
|
||||
/* Create a dummy World data block to hold the nodetree generated for studio-lights. */
|
||||
world = static_cast<::World *>(BKE_id_new_nomain(ID_MA, "Lookdev"));
|
||||
|
||||
bNodeTree *ntree = bke::node_tree_add_tree_embedded(
|
||||
nullptr, &world->id, "Lookdev World Nodetree", ntreeType_Shader->idname);
|
||||
|
||||
bNode *coordinate = bke::node_add_static_node(nullptr, *ntree, SH_NODE_TEX_COORD);
|
||||
bNodeSocket *coordinate_out = bke::node_find_socket(*coordinate, SOCK_OUT, "Generated");
|
||||
@@ -65,12 +68,14 @@ LookdevWorld::LookdevWorld()
|
||||
bke::node_add_link(*ntree, *background, *background_out, *output, *output_in);
|
||||
bke::node_set_active(*ntree, *output);
|
||||
|
||||
world->use_nodes = true;
|
||||
world->nodetree = ntree;
|
||||
|
||||
/* Create a dummy image data block to hold GPU textures generated by studio-lights. */
|
||||
STRNCPY(image.id.name, "IMLookdev");
|
||||
BKE_libblock_init_empty(&image.id);
|
||||
image.type = IMA_TYPE_IMAGE;
|
||||
image.source = IMA_SRC_GENERATED;
|
||||
ImageTile *base_tile = BKE_image_get_tile(&image, 0);
|
||||
image = static_cast<::Image *>(BKE_id_new_nomain(ID_IM, "Lookdev"));
|
||||
image->type = IMA_TYPE_IMAGE;
|
||||
image->source = IMA_SRC_GENERATED;
|
||||
ImageTile *base_tile = BKE_image_get_tile(image, 0);
|
||||
base_tile->gen_x = 1;
|
||||
base_tile->gen_y = 1;
|
||||
base_tile->gen_type = IMA_GENTYPE_BLANK;
|
||||
@@ -78,19 +83,13 @@ LookdevWorld::LookdevWorld()
|
||||
/* TODO: This works around the issue that the first time the texture is accessed the image would
|
||||
* overwrite the set GPU texture. A better solution would be to use image data-blocks as part of
|
||||
* the studio-lights, but that requires a larger refactoring. */
|
||||
BKE_image_get_gpu_texture(&image, &environment_storage->iuser);
|
||||
|
||||
/* Create a dummy image data block to hold GPU textures generated by studio-lights. */
|
||||
STRNCPY(world.id.name, "WOLookdev");
|
||||
BKE_libblock_init_empty(&world.id);
|
||||
world.use_nodes = true;
|
||||
world.nodetree = ntree;
|
||||
BKE_image_get_gpu_texture(image, &environment_storage->iuser);
|
||||
}
|
||||
|
||||
LookdevWorld::~LookdevWorld()
|
||||
{
|
||||
BKE_libblock_free_datablock(&image.id, 0);
|
||||
BKE_libblock_free_datablock(&world.id, 0);
|
||||
BKE_id_free(nullptr, &image->id);
|
||||
BKE_id_free(nullptr, &world->id);
|
||||
}
|
||||
|
||||
bool LookdevWorld::sync(const LookdevParameters &new_parameters)
|
||||
@@ -101,7 +100,7 @@ bool LookdevWorld::sync(const LookdevParameters &new_parameters)
|
||||
intensity_socket_->value = parameters_.intensity;
|
||||
angle_socket_->value = parameters_.rot_z;
|
||||
|
||||
GPU_TEXTURE_FREE_SAFE(image.gputexture[TEXTARGET_2D][0]);
|
||||
GPU_TEXTURE_FREE_SAFE(image->gputexture[TEXTARGET_2D][0]);
|
||||
environment_node_->id = nullptr;
|
||||
|
||||
StudioLight *sl = BKE_studiolight_find(parameters_.hdri.c_str(),
|
||||
@@ -111,12 +110,12 @@ bool LookdevWorld::sync(const LookdevParameters &new_parameters)
|
||||
GPUTexture *texture = sl->equirect_radiance_gputexture;
|
||||
if (texture != nullptr) {
|
||||
GPU_texture_ref(texture);
|
||||
image.gputexture[TEXTARGET_2D][0] = texture;
|
||||
environment_node_->id = &image.id;
|
||||
image->gputexture[TEXTARGET_2D][0] = texture;
|
||||
environment_node_->id = &image->id;
|
||||
}
|
||||
}
|
||||
|
||||
GPU_material_free(&world.gpumaterial);
|
||||
GPU_material_free(&world->gpumaterial);
|
||||
}
|
||||
return parameters_changed;
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ class LookdevWorld {
|
||||
bNode *environment_node_ = nullptr;
|
||||
bNodeSocketValueFloat *intensity_socket_ = nullptr;
|
||||
bNodeSocketValueFloat *angle_socket_ = nullptr;
|
||||
::Image image = {};
|
||||
::World world = {};
|
||||
::Image *image = nullptr;
|
||||
::World *world = nullptr;
|
||||
|
||||
LookdevParameters parameters_;
|
||||
|
||||
@@ -86,7 +86,7 @@ class LookdevWorld {
|
||||
|
||||
::World *world_get()
|
||||
{
|
||||
return &world;
|
||||
return world;
|
||||
}
|
||||
|
||||
float background_opacity_get() const
|
||||
|
||||
Reference in New Issue
Block a user