Draw: Inline small functions to reduce overhead

Some functions used at least once per object/instance
when drawing are so trivial that function call overhead
becomes significant. Allowing these functions to be
inlined can remove that overhead and also give the
compiler more information it can use for optimization.

In the Erindale Flower Shop file, this change gives me
a 10% improvement in playback FPS, from 8.77 to 9.65.

Pull Request: https://projects.blender.org/blender/blender/pulls/140402
This commit is contained in:
Hans Goudey
2025-06-17 16:06:05 +02:00
committed by Hans Goudey
parent 1d90d9f3bb
commit 54c3c8f411
9 changed files with 61 additions and 71 deletions

View File

@@ -8,8 +8,11 @@
#pragma once
#include "BKE_mesh_types.hh"
#include "BKE_subdiv.hh"
#include "DNA_mesh_types.h"
/* Hardcoded for until GPU shaders are automatically generated, then we will have a more
* programmatic way of detecting this. */
#define MAX_GPU_SUBDIV_SSBOS 12
@@ -74,7 +77,11 @@ bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfMod
*/
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const SubsurfModifierData *smd, const Mesh *mesh);
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh);
inline bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
return runtime_data && runtime_data->has_gpu_subdiv;
}
extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(blender::bke::subdiv::Subdiv *subdiv);

View File

@@ -120,12 +120,6 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const SubsurfModifierData *smd, cons
!BKE_subsurf_modifier_has_split_normals(smd, mesh);
}
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
return runtime_data && runtime_data->has_gpu_subdiv;
}
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(subdiv::Subdiv *subdiv) = nullptr;
subdiv::Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,

View File

@@ -16,14 +16,6 @@
namespace blender::workbench {
Material::Material() = default;
Material::Material(float3 color)
{
base_color = color;
packed_data = Material::pack_data(0.0f, 0.4f, 1.0f);
}
Material::Material(::Object &ob, bool random)
{
if (random) {
@@ -40,28 +32,6 @@ Material::Material(::Object &ob, bool random)
packed_data = Material::pack_data(0.0f, 0.4f, ob.color[3]);
}
Material::Material(::Material &mat)
{
base_color = &mat.r;
packed_data = Material::pack_data(mat.metallic, mat.roughness, mat.a);
}
bool Material::is_transparent()
{
uint32_t full_alpha_ref = 0x00ff0000;
return (packed_data & full_alpha_ref) != full_alpha_ref;
}
uint32_t Material::pack_data(float metallic, float roughness, float alpha)
{
/* Remap to Disney roughness. */
roughness = sqrtf(roughness);
uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha);
return (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
}
MaterialTexture::MaterialTexture(Object *ob, int material_index)
{
const ::bNode *node = nullptr;

View File

@@ -5,6 +5,7 @@
#include "BKE_context.hh"
#include "DNA_camera_types.h"
#include "DNA_material_types.h"
#include "DRW_render.hh"
#include "GPU_shader.hh"
#include "draw_manager.hh"
@@ -110,16 +111,36 @@ struct Material {
/* Packed data into a int. Decoded in the shader. */
uint packed_data = 0;
Material();
Material(float3 color);
Material() = default;
Material(float3 color) : base_color(color), packed_data(Material::pack_data(0.0f, 0.4f, 1.0f)) {}
Material(::Object &ob, bool random = false);
Material(::Material &mat);
Material(::Material &mat)
: base_color(&mat.r), packed_data(Material::pack_data(mat.metallic, mat.roughness, mat.a))
{
}
static uint32_t pack_data(float metallic, float roughness, float alpha);
bool is_transparent();
};
inline bool Material::is_transparent()
{
uint32_t full_alpha_ref = 0x00ff0000;
return (packed_data & full_alpha_ref) != full_alpha_ref;
}
inline uint32_t Material::pack_data(float metallic, float roughness, float alpha)
{
/* Remap to Disney roughness. */
roughness = sqrtf(roughness);
uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha);
return (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
}
ImageGPUTextures get_material_texture(GPUSamplerState &sampler_state);
struct SceneState {

View File

@@ -12,6 +12,8 @@
#include <functional>
#include "BKE_mesh_wrapper.hh"
#include "BKE_subdiv_modifier.hh"
#include "BLI_math_vector_types.hh"
#include "DNA_object_enums.h"
#include "DNA_object_types.h"
@@ -192,7 +194,17 @@ template<typename T> T &DRW_object_get_data_for_drawing(const Object &object)
return *static_cast<T *>(object.data);
}
template<> Mesh &DRW_object_get_data_for_drawing(const Object &object);
template<> inline Mesh &DRW_object_get_data_for_drawing(const Object &object)
{
/* For drawing we want either the base mesh if GPU subdivision is enabled, or the
* tessellated mesh if GPU subdivision is disabled. */
BLI_assert(object.type == OB_MESH);
Mesh &mesh = *static_cast<Mesh *>(object.data);
if (BKE_subsurf_modifier_has_gpu_subdiv(&mesh)) {
return mesh;
}
return *BKE_mesh_wrapper_ensure_subdivision(&mesh);
}
/**
* Same as DRW_object_get_data_for_drawing, but for the editmesh cage,

View File

@@ -358,17 +358,6 @@ const SortedFaceData &mesh_render_data_faces_sorted_ensure(const MeshRenderData
/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
* \{ */
const Mesh &editmesh_final_or_this(const Object &object, const Mesh &mesh)
{
if (mesh.runtime->edit_mesh != nullptr) {
if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(&object)) {
return *editmesh_eval_final;
}
}
return mesh;
}
const CustomData &mesh_cd_ldata_get_from_mesh(const Mesh &mesh)
{
switch (mesh.runtime->wrapper_type) {

View File

@@ -106,11 +106,6 @@
thread_local DRWContext *DRWContext::g_context = nullptr;
DRWContext &drw_get()
{
return DRWContext::get_active();
}
DRWContext::DRWContext(Mode mode_,
Depsgraph *depsgraph,
const int2 size,
@@ -370,18 +365,6 @@ bool DRW_object_is_visible_psys_in_active_context(const Object *object, const Pa
return true;
}
template<> Mesh &DRW_object_get_data_for_drawing(const Object &object)
{
/* For drawing we want either the base mesh if GPU subdivision is enabled, or the
* tessellated mesh if GPU subdivision is disabled. */
BLI_assert(object.type == OB_MESH);
Mesh &mesh = *static_cast<Mesh *>(object.data);
if (BKE_subsurf_modifier_has_gpu_subdiv(&mesh)) {
return mesh;
}
return *BKE_mesh_wrapper_ensure_subdivision(&mesh);
}
const Mesh *DRW_object_get_editmesh_cage_for_drawing(const Object &object)
{
/* Same as DRW_object_get_data_for_drawing, but for the cage mesh. */

View File

@@ -74,7 +74,10 @@ struct DRWData {
* \{ */
/* Get thread local draw context. */
DRWContext &drw_get();
inline DRWContext &drw_get()
{
return DRWContext::get_active();
}
namespace blender::draw {

View File

@@ -18,6 +18,7 @@
#include "DNA_scene_types.h"
#include "BKE_mesh.hh"
#include "BKE_object.hh"
#include "bmesh.hh"
@@ -120,7 +121,17 @@ struct MeshRenderData {
const char *default_color_name;
};
const Mesh &editmesh_final_or_this(const Object &object, const Mesh &mesh);
inline const Mesh &editmesh_final_or_this(const Object &object, const Mesh &mesh)
{
if (mesh.runtime->edit_mesh != nullptr) {
if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(&object)) {
return *editmesh_eval_final;
}
}
return mesh;
}
const CustomData &mesh_cd_vdata_get_from_mesh(const Mesh &mesh);
const CustomData &mesh_cd_edata_get_from_mesh(const Mesh &mesh);
const CustomData &mesh_cd_pdata_get_from_mesh(const Mesh &mesh);