GPU: Threadsafe shader creation and acquisition
Move the `StaticShader` class from Workbench to `GPU_shader` and make compilation thread-safe (Shader usage is still not thread-safe). Use `StaticShader`s for all shader caches. Subdivision shaders are still not ported. (Part of #134690) Pull Request: https://projects.blender.org/blender/blender/pulls/134812
This commit is contained in:
@@ -29,39 +29,31 @@ namespace blender::eevee {
|
||||
*
|
||||
* \{ */
|
||||
|
||||
ShaderModule *ShaderModule::g_shader_module = nullptr;
|
||||
|
||||
ShaderModule *ShaderModule::module_get()
|
||||
{
|
||||
if (g_shader_module == nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
g_shader_module = new ShaderModule();
|
||||
}
|
||||
return g_shader_module;
|
||||
return &get_static_cache().get();
|
||||
}
|
||||
|
||||
void ShaderModule::module_free()
|
||||
{
|
||||
if (g_shader_module != nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
delete g_shader_module;
|
||||
g_shader_module = nullptr;
|
||||
}
|
||||
get_static_cache().release();
|
||||
}
|
||||
|
||||
ShaderModule::ShaderModule()
|
||||
{
|
||||
for (GPUShader *&shader : shaders_) {
|
||||
shader = nullptr;
|
||||
}
|
||||
|
||||
Vector<const GPUShaderCreateInfo *> infos;
|
||||
infos.reserve(MAX_SHADER_TYPE);
|
||||
|
||||
for (auto i : IndexRange(MAX_SHADER_TYPE)) {
|
||||
const char *name = static_shader_create_info_name_get(eShaderType(i));
|
||||
const GPUShaderCreateInfo *create_info = GPU_shader_create_info_get(name);
|
||||
infos.append(create_info);
|
||||
|
||||
if (GPU_use_parallel_compilation()) {
|
||||
infos.append(create_info);
|
||||
}
|
||||
else {
|
||||
shaders_[i] = {name};
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (name == nullptr) {
|
||||
@@ -84,10 +76,6 @@ ShaderModule::~ShaderModule()
|
||||
/* Finish compilation to avoid asserts on exit at GLShaderCompiler destructor. */
|
||||
is_ready(true);
|
||||
}
|
||||
|
||||
for (GPUShader *&shader : shaders_) {
|
||||
GPU_SHADER_FREE_SAFE(shader);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -101,8 +89,6 @@ void ShaderModule::precompile_specializations(int render_buffers_shadow_id,
|
||||
int shadow_ray_count,
|
||||
int shadow_ray_step_count)
|
||||
{
|
||||
BLI_assert(specialization_handle_ == 0);
|
||||
|
||||
if (!GPU_use_parallel_compilation()) {
|
||||
return;
|
||||
}
|
||||
@@ -125,16 +111,22 @@ void ShaderModule::precompile_specializations(int render_buffers_shadow_id,
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard lock = get_static_cache().lock_guard();
|
||||
/* TODO: This is broken. Different scenes can have different specializations. */
|
||||
BLI_assert(specialization_handle_ == 0);
|
||||
|
||||
specialization_handle_ = GPU_shader_batch_specializations(specializations);
|
||||
}
|
||||
|
||||
bool ShaderModule::is_ready(bool block)
|
||||
{
|
||||
std::lock_guard lock = get_static_cache().lock_guard();
|
||||
|
||||
if (compilation_handle_) {
|
||||
if (GPU_shader_batch_is_ready(compilation_handle_) || block) {
|
||||
Vector<GPUShader *> shaders = GPU_shader_batch_finalize(compilation_handle_);
|
||||
for (int i : IndexRange(MAX_SHADER_TYPE)) {
|
||||
shaders_[i] = shaders[i];
|
||||
shaders_[i].set(shaders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,17 +377,13 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
||||
GPUShader *ShaderModule::static_shader_get(eShaderType shader_type)
|
||||
{
|
||||
BLI_assert(is_ready());
|
||||
if (shaders_[shader_type] == nullptr) {
|
||||
if (GPU_use_parallel_compilation() && shaders_[shader_type].get() == nullptr) {
|
||||
const char *shader_name = static_shader_create_info_name_get(shader_type);
|
||||
if (GPU_use_parallel_compilation()) {
|
||||
fprintf(stderr, "EEVEE: error: Could not compile static shader \"%s\"\n", shader_name);
|
||||
BLI_assert(0);
|
||||
}
|
||||
else {
|
||||
shaders_[shader_type] = GPU_shader_create_from_info_name(shader_name);
|
||||
}
|
||||
fprintf(stderr, "EEVEE: error: Could not compile static shader \"%s\"\n", shader_name);
|
||||
BLI_assert(0);
|
||||
}
|
||||
return shaders_[shader_type];
|
||||
|
||||
return shaders_[shader_type].get();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
/* Keep alphabetical order and clean prefix. */
|
||||
enum eShaderType {
|
||||
AMBIENT_OCCLUSION_PASS = 0,
|
||||
@@ -166,12 +168,16 @@ enum eShaderType {
|
||||
*/
|
||||
class ShaderModule {
|
||||
private:
|
||||
std::array<GPUShader *, MAX_SHADER_TYPE> shaders_;
|
||||
std::array<StaticShader, MAX_SHADER_TYPE> shaders_;
|
||||
BatchHandle compilation_handle_ = 0;
|
||||
SpecializationBatchHandle specialization_handle_ = 0;
|
||||
|
||||
/** Shared shader module across all engine instances. */
|
||||
static ShaderModule *g_shader_module;
|
||||
static gpu::StaticShaderCache<ShaderModule> &get_static_cache()
|
||||
{
|
||||
/** Shared shader module across all engine instances. */
|
||||
static gpu::StaticShaderCache<ShaderModule> static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
public:
|
||||
ShaderModule();
|
||||
|
||||
@@ -11,171 +11,124 @@
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
|
||||
extern "C" char datatoc_gpencil_common_lib_glsl[];
|
||||
extern "C" char datatoc_gpencil_frag_glsl[];
|
||||
extern "C" char datatoc_gpencil_vert_glsl[];
|
||||
extern "C" char datatoc_gpencil_antialiasing_frag_glsl[];
|
||||
extern "C" char datatoc_gpencil_antialiasing_vert_glsl[];
|
||||
extern "C" char datatoc_gpencil_layer_blend_frag_glsl[];
|
||||
extern "C" char datatoc_gpencil_mask_invert_frag_glsl[];
|
||||
extern "C" char datatoc_gpencil_depth_merge_frag_glsl[];
|
||||
extern "C" char datatoc_gpencil_depth_merge_vert_glsl[];
|
||||
extern "C" char datatoc_gpencil_vfx_frag_glsl[];
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
extern "C" char datatoc_common_colormanagement_lib_glsl[];
|
||||
extern "C" char datatoc_common_fullscreen_vert_glsl[];
|
||||
extern "C" char datatoc_common_view_lib_glsl[];
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
class ShaderCache {
|
||||
private:
|
||||
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
||||
{
|
||||
static gpu::StaticShaderCache<ShaderCache> static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
public:
|
||||
static ShaderCache &get()
|
||||
{
|
||||
return get_static_cache().get();
|
||||
}
|
||||
static void release()
|
||||
{
|
||||
get_static_cache().release();
|
||||
}
|
||||
|
||||
static struct {
|
||||
/* SMAA antialiasing */
|
||||
GPUShader *antialiasing_sh[3];
|
||||
StaticShader antialiasing[3] = {{"gpencil_antialiasing_stage_0"},
|
||||
{"gpencil_antialiasing_stage_1"},
|
||||
{"gpencil_antialiasing_stage_2"}};
|
||||
/* GPencil Object rendering */
|
||||
GPUShader *gpencil_sh;
|
||||
/* Final Compositing over rendered background. */
|
||||
GPUShader *composite_sh;
|
||||
StaticShader geometry = {"gpencil_geometry"};
|
||||
/* All layer blend types in one shader! */
|
||||
GPUShader *layer_blend_sh;
|
||||
StaticShader layer_blend = {"gpencil_layer_blend"};
|
||||
/* Merge the final object depth to the depth buffer. */
|
||||
GPUShader *depth_merge_sh;
|
||||
StaticShader depth_merge = {"gpencil_depth_merge"};
|
||||
/* Invert the content of the mask buffer. */
|
||||
GPUShader *mask_invert_sh;
|
||||
StaticShader mask_invert = {"gpencil_mask_invert"};
|
||||
/* Effects. */
|
||||
GPUShader *fx_composite_sh;
|
||||
GPUShader *fx_colorize_sh;
|
||||
GPUShader *fx_blur_sh;
|
||||
GPUShader *fx_glow_sh;
|
||||
GPUShader *fx_pixel_sh;
|
||||
GPUShader *fx_rim_sh;
|
||||
GPUShader *fx_shadow_sh;
|
||||
GPUShader *fx_transform_sh;
|
||||
} g_shaders = {{nullptr}};
|
||||
StaticShader fx_composite = {"gpencil_fx_composite"};
|
||||
StaticShader fx_colorize = {"gpencil_fx_colorize"};
|
||||
StaticShader fx_blur = {"gpencil_fx_blur"};
|
||||
StaticShader fx_glow = {"gpencil_fx_glow"};
|
||||
StaticShader fx_pixelize = {"gpencil_fx_pixelize"};
|
||||
StaticShader fx_rim = {"gpencil_fx_rim"};
|
||||
StaticShader fx_shadow = {"gpencil_fx_shadow"};
|
||||
StaticShader fx_transform = {"gpencil_fx_transform"};
|
||||
};
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
using namespace blender::draw::gpencil;
|
||||
|
||||
void GPENCIL_shader_free()
|
||||
{
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[0]);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[1]);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[2]);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.gpencil_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.composite_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.layer_blend_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.depth_merge_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.mask_invert_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_composite_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_colorize_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_blur_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_glow_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_pixel_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_rim_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_shadow_sh);
|
||||
GPU_SHADER_FREE_SAFE(g_shaders.fx_transform_sh);
|
||||
ShaderCache::get().release();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_antialiasing(int stage)
|
||||
{
|
||||
BLI_assert(stage < 3);
|
||||
|
||||
if (!g_shaders.antialiasing_sh[stage]) {
|
||||
char stage_info_name[32];
|
||||
SNPRINTF(stage_info_name, "gpencil_antialiasing_stage_%d", stage);
|
||||
g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_info_name(stage_info_name);
|
||||
}
|
||||
return g_shaders.antialiasing_sh[stage];
|
||||
return ShaderCache::get().antialiasing[stage].get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_geometry_get()
|
||||
{
|
||||
if (!g_shaders.gpencil_sh) {
|
||||
g_shaders.gpencil_sh = GPU_shader_create_from_info_name("gpencil_geometry");
|
||||
}
|
||||
return g_shaders.gpencil_sh;
|
||||
return ShaderCache::get().geometry.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_layer_blend_get()
|
||||
{
|
||||
if (!g_shaders.layer_blend_sh) {
|
||||
g_shaders.layer_blend_sh = GPU_shader_create_from_info_name("gpencil_layer_blend");
|
||||
}
|
||||
return g_shaders.layer_blend_sh;
|
||||
return ShaderCache::get().layer_blend.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_mask_invert_get()
|
||||
{
|
||||
if (!g_shaders.mask_invert_sh) {
|
||||
g_shaders.mask_invert_sh = GPU_shader_create_from_info_name("gpencil_mask_invert");
|
||||
}
|
||||
return g_shaders.mask_invert_sh;
|
||||
return ShaderCache::get().mask_invert.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_depth_merge_get()
|
||||
{
|
||||
if (!g_shaders.depth_merge_sh) {
|
||||
g_shaders.depth_merge_sh = GPU_shader_create_from_info_name("gpencil_depth_merge");
|
||||
}
|
||||
return g_shaders.depth_merge_sh;
|
||||
return ShaderCache::get().depth_merge.get();
|
||||
}
|
||||
|
||||
/* ------- FX Shaders --------- */
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_blur_get()
|
||||
{
|
||||
if (!g_shaders.fx_blur_sh) {
|
||||
g_shaders.fx_blur_sh = GPU_shader_create_from_info_name("gpencil_fx_blur");
|
||||
}
|
||||
return g_shaders.fx_blur_sh;
|
||||
return ShaderCache::get().fx_blur.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_colorize_get()
|
||||
{
|
||||
if (!g_shaders.fx_colorize_sh) {
|
||||
g_shaders.fx_colorize_sh = GPU_shader_create_from_info_name("gpencil_fx_colorize");
|
||||
}
|
||||
return g_shaders.fx_colorize_sh;
|
||||
return ShaderCache::get().fx_colorize.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_composite_get()
|
||||
{
|
||||
if (!g_shaders.fx_composite_sh) {
|
||||
g_shaders.fx_composite_sh = GPU_shader_create_from_info_name("gpencil_fx_composite");
|
||||
}
|
||||
return g_shaders.fx_composite_sh;
|
||||
return ShaderCache::get().fx_composite.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_glow_get()
|
||||
{
|
||||
if (!g_shaders.fx_glow_sh) {
|
||||
g_shaders.fx_glow_sh = GPU_shader_create_from_info_name("gpencil_fx_glow");
|
||||
}
|
||||
return g_shaders.fx_glow_sh;
|
||||
return ShaderCache::get().fx_glow.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_pixelize_get()
|
||||
{
|
||||
if (!g_shaders.fx_pixel_sh) {
|
||||
g_shaders.fx_pixel_sh = GPU_shader_create_from_info_name("gpencil_fx_pixelize");
|
||||
}
|
||||
return g_shaders.fx_pixel_sh;
|
||||
return ShaderCache::get().fx_pixelize.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_rim_get()
|
||||
{
|
||||
if (!g_shaders.fx_rim_sh) {
|
||||
g_shaders.fx_rim_sh = GPU_shader_create_from_info_name("gpencil_fx_rim");
|
||||
}
|
||||
return g_shaders.fx_rim_sh;
|
||||
return ShaderCache::get().fx_rim.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_shadow_get()
|
||||
{
|
||||
if (!g_shaders.fx_shadow_sh) {
|
||||
g_shaders.fx_shadow_sh = GPU_shader_create_from_info_name("gpencil_fx_shadow");
|
||||
}
|
||||
return g_shaders.fx_shadow_sh;
|
||||
return ShaderCache::get().fx_shadow.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_transform_get()
|
||||
{
|
||||
if (!g_shaders.fx_transform_sh) {
|
||||
g_shaders.fx_transform_sh = GPU_shader_create_from_info_name("gpencil_fx_transform");
|
||||
}
|
||||
return g_shaders.fx_transform_sh;
|
||||
return ShaderCache::get().fx_transform.get();
|
||||
}
|
||||
|
||||
@@ -447,21 +447,25 @@ class ShapeCache {
|
||||
}
|
||||
};
|
||||
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
/**
|
||||
* Shader module. Shared between instances.
|
||||
*/
|
||||
class ShaderModule {
|
||||
private:
|
||||
struct ShaderDeleter {
|
||||
void operator()(GPUShader *shader)
|
||||
{
|
||||
GPU_SHADER_FREE_SAFE(shader);
|
||||
}
|
||||
};
|
||||
using ShaderPtr = std::unique_ptr<GPUShader, ShaderDeleter>;
|
||||
/* Allow StaticShaderCache access to the constructor. */
|
||||
friend gpu::StaticShaderCache<ShaderModule>;
|
||||
|
||||
/** Shared shader module across all engine instances. */
|
||||
static ShaderModule *g_shader_modules[2 /* Selection Instance. */][2 /* Clipping Enabled. */];
|
||||
using StaticCache =
|
||||
gpu::StaticShaderCache<ShaderModule>[2 /* Selection Instance. */][2 /* Clipping Enabled. */];
|
||||
|
||||
static StaticCache &get_static_cache()
|
||||
{
|
||||
/** Shared shader module across all engine instances. */
|
||||
static StaticCache static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
const SelectionType selection_type_;
|
||||
/** TODO: Support clipping. This global state should be set by the overlay::Instance and switch
|
||||
@@ -470,116 +474,119 @@ class ShaderModule {
|
||||
|
||||
public:
|
||||
/** Shaders */
|
||||
ShaderPtr anti_aliasing = shader("overlay_antialiasing");
|
||||
ShaderPtr armature_degrees_of_freedom = shader_clippable("overlay_armature_dof");
|
||||
ShaderPtr attribute_viewer_mesh = shader_clippable("overlay_viewer_attribute_mesh");
|
||||
ShaderPtr attribute_viewer_pointcloud = shader_clippable("overlay_viewer_attribute_pointcloud");
|
||||
ShaderPtr attribute_viewer_curve = shader_clippable("overlay_viewer_attribute_curve");
|
||||
ShaderPtr attribute_viewer_curves = shader_clippable("overlay_viewer_attribute_curves");
|
||||
ShaderPtr background_fill = shader("overlay_background");
|
||||
ShaderPtr background_clip_bound = shader("overlay_clipbound");
|
||||
ShaderPtr curve_edit_points = shader_clippable("overlay_edit_curves_point");
|
||||
ShaderPtr curve_edit_line = shader_clippable("overlay_edit_particle_strand");
|
||||
ShaderPtr curve_edit_handles = shader_clippable("overlay_edit_curves_handle");
|
||||
ShaderPtr facing = shader_clippable("overlay_facing");
|
||||
ShaderPtr grid = shader("overlay_grid_next");
|
||||
ShaderPtr grid_background = shader("overlay_grid_background");
|
||||
ShaderPtr grid_grease_pencil = shader_clippable("overlay_gpencil_canvas");
|
||||
ShaderPtr grid_image = shader("overlay_grid_image");
|
||||
ShaderPtr lattice_points = shader_clippable("overlay_edit_lattice_point");
|
||||
ShaderPtr lattice_wire = shader_clippable("overlay_edit_lattice_wire");
|
||||
ShaderPtr legacy_curve_edit_handles = shader_clippable("overlay_edit_curve_handle");
|
||||
ShaderPtr legacy_curve_edit_normals = shader_clippable("overlay_edit_curve_normals");
|
||||
ShaderPtr legacy_curve_edit_points = shader_clippable("overlay_edit_curve_point");
|
||||
ShaderPtr legacy_curve_edit_wires = shader_clippable("overlay_edit_curve_wire");
|
||||
ShaderPtr light_spot_cone = shader_clippable("overlay_extra_spot_cone");
|
||||
ShaderPtr mesh_analysis = shader_clippable("overlay_edit_mesh_analysis");
|
||||
ShaderPtr mesh_edit_depth = shader_clippable("overlay_edit_mesh_depth");
|
||||
ShaderPtr mesh_edit_edge = shader_clippable("overlay_edit_mesh_edge");
|
||||
ShaderPtr mesh_edit_face = shader_clippable("overlay_edit_mesh_face");
|
||||
ShaderPtr mesh_edit_facedot = shader_clippable("overlay_edit_mesh_facedot");
|
||||
ShaderPtr mesh_edit_vert = shader_clippable("overlay_edit_mesh_vert");
|
||||
ShaderPtr mesh_edit_skin_root = shader_clippable("overlay_edit_mesh_skin_root");
|
||||
ShaderPtr mesh_face_normal = shader_clippable("overlay_mesh_face_normal");
|
||||
ShaderPtr mesh_face_normal_subdiv = shader_clippable("overlay_mesh_face_normal_subdiv");
|
||||
ShaderPtr mesh_loop_normal = shader_clippable("overlay_mesh_loop_normal");
|
||||
ShaderPtr mesh_loop_normal_subdiv = shader_clippable("overlay_mesh_loop_normal_subdiv");
|
||||
ShaderPtr mesh_vert_normal = shader_clippable("overlay_mesh_vert_normal");
|
||||
ShaderPtr mesh_vert_normal_subdiv = shader_clippable("overlay_mesh_vert_normal_subdiv");
|
||||
ShaderPtr motion_path_line = shader_clippable("overlay_motion_path_line");
|
||||
ShaderPtr motion_path_vert = shader_clippable("overlay_motion_path_point");
|
||||
ShaderPtr outline_detect = shader("overlay_outline_detect");
|
||||
ShaderPtr outline_prepass_curves = shader_clippable("overlay_outline_prepass_curves");
|
||||
ShaderPtr outline_prepass_gpencil = shader_clippable("overlay_outline_prepass_gpencil");
|
||||
ShaderPtr outline_prepass_mesh = shader_clippable("overlay_outline_prepass_mesh");
|
||||
ShaderPtr outline_prepass_pointcloud = shader_clippable("overlay_outline_prepass_pointcloud");
|
||||
ShaderPtr outline_prepass_wire = shader_clippable("overlay_outline_prepass_wire");
|
||||
ShaderPtr paint_region_edge = shader_clippable("overlay_paint_wire");
|
||||
ShaderPtr paint_region_face = shader_clippable("overlay_paint_face");
|
||||
ShaderPtr paint_region_vert = shader_clippable("overlay_paint_point");
|
||||
ShaderPtr paint_texture = shader_clippable("overlay_paint_texture");
|
||||
ShaderPtr paint_weight = shader_clippable("overlay_paint_weight");
|
||||
StaticShader anti_aliasing = {"overlay_antialiasing"};
|
||||
StaticShader armature_degrees_of_freedom = shader_clippable("overlay_armature_dof");
|
||||
StaticShader attribute_viewer_mesh = shader_clippable("overlay_viewer_attribute_mesh");
|
||||
StaticShader attribute_viewer_pointcloud = shader_clippable(
|
||||
"overlay_viewer_attribute_pointcloud");
|
||||
StaticShader attribute_viewer_curve = shader_clippable("overlay_viewer_attribute_curve");
|
||||
StaticShader attribute_viewer_curves = shader_clippable("overlay_viewer_attribute_curves");
|
||||
StaticShader background_fill = {"overlay_background"};
|
||||
StaticShader background_clip_bound = {"overlay_clipbound"};
|
||||
StaticShader curve_edit_points = shader_clippable("overlay_edit_curves_point");
|
||||
StaticShader curve_edit_line = shader_clippable("overlay_edit_particle_strand");
|
||||
StaticShader curve_edit_handles = shader_clippable("overlay_edit_curves_handle");
|
||||
StaticShader facing = shader_clippable("overlay_facing");
|
||||
StaticShader grid = {"overlay_grid_next"};
|
||||
StaticShader grid_background = {"overlay_grid_background"};
|
||||
StaticShader grid_grease_pencil = shader_clippable("overlay_gpencil_canvas");
|
||||
StaticShader grid_image = {"overlay_grid_image"};
|
||||
StaticShader lattice_points = shader_clippable("overlay_edit_lattice_point");
|
||||
StaticShader lattice_wire = shader_clippable("overlay_edit_lattice_wire");
|
||||
StaticShader legacy_curve_edit_handles = shader_clippable("overlay_edit_curve_handle");
|
||||
StaticShader legacy_curve_edit_normals = shader_clippable("overlay_edit_curve_normals");
|
||||
StaticShader legacy_curve_edit_points = shader_clippable("overlay_edit_curve_point");
|
||||
StaticShader legacy_curve_edit_wires = shader_clippable("overlay_edit_curve_wire");
|
||||
StaticShader light_spot_cone = shader_clippable("overlay_extra_spot_cone");
|
||||
StaticShader mesh_analysis = shader_clippable("overlay_edit_mesh_analysis");
|
||||
StaticShader mesh_edit_depth = shader_clippable("overlay_edit_mesh_depth");
|
||||
StaticShader mesh_edit_edge = shader_clippable("overlay_edit_mesh_edge");
|
||||
StaticShader mesh_edit_face = shader_clippable("overlay_edit_mesh_face");
|
||||
StaticShader mesh_edit_facedot = shader_clippable("overlay_edit_mesh_facedot");
|
||||
StaticShader mesh_edit_vert = shader_clippable("overlay_edit_mesh_vert");
|
||||
StaticShader mesh_edit_skin_root = shader_clippable("overlay_edit_mesh_skin_root");
|
||||
StaticShader mesh_face_normal = shader_clippable("overlay_mesh_face_normal");
|
||||
StaticShader mesh_face_normal_subdiv = shader_clippable("overlay_mesh_face_normal_subdiv");
|
||||
StaticShader mesh_loop_normal = shader_clippable("overlay_mesh_loop_normal");
|
||||
StaticShader mesh_loop_normal_subdiv = shader_clippable("overlay_mesh_loop_normal_subdiv");
|
||||
StaticShader mesh_vert_normal = shader_clippable("overlay_mesh_vert_normal");
|
||||
StaticShader mesh_vert_normal_subdiv = shader_clippable("overlay_mesh_vert_normal_subdiv");
|
||||
StaticShader motion_path_line = shader_clippable("overlay_motion_path_line");
|
||||
StaticShader motion_path_vert = shader_clippable("overlay_motion_path_point");
|
||||
StaticShader outline_detect = {"overlay_outline_detect"};
|
||||
StaticShader outline_prepass_curves = shader_clippable("overlay_outline_prepass_curves");
|
||||
StaticShader outline_prepass_gpencil = shader_clippable("overlay_outline_prepass_gpencil");
|
||||
StaticShader outline_prepass_mesh = shader_clippable("overlay_outline_prepass_mesh");
|
||||
StaticShader outline_prepass_pointcloud = shader_clippable("overlay_outline_prepass_pointcloud");
|
||||
StaticShader outline_prepass_wire = shader_clippable("overlay_outline_prepass_wire");
|
||||
StaticShader paint_region_edge = shader_clippable("overlay_paint_wire");
|
||||
StaticShader paint_region_face = shader_clippable("overlay_paint_face");
|
||||
StaticShader paint_region_vert = shader_clippable("overlay_paint_point");
|
||||
StaticShader paint_texture = shader_clippable("overlay_paint_texture");
|
||||
StaticShader paint_weight = shader_clippable("overlay_paint_weight");
|
||||
/* TODO(fclem): Specialization constant. */
|
||||
ShaderPtr paint_weight_fake_shading = shader_clippable("overlay_paint_weight_fake_shading");
|
||||
ShaderPtr particle_edit_vert = shader_clippable("overlay_edit_particle_point");
|
||||
ShaderPtr particle_edit_edge = shader_clippable("overlay_edit_particle_strand");
|
||||
ShaderPtr pointcloud_points = shader_clippable("overlay_edit_pointcloud");
|
||||
ShaderPtr sculpt_curves = shader_clippable("overlay_sculpt_curves_selection");
|
||||
ShaderPtr sculpt_curves_cage = shader_clippable("overlay_sculpt_curves_cage");
|
||||
ShaderPtr sculpt_mesh = shader_clippable("overlay_sculpt_mask");
|
||||
ShaderPtr uniform_color = shader_clippable("overlay_uniform_color");
|
||||
ShaderPtr uv_analysis_stretch_angle = shader("overlay_edit_uv_stretching_angle");
|
||||
ShaderPtr uv_analysis_stretch_area = shader("overlay_edit_uv_stretching_area");
|
||||
ShaderPtr uv_brush_stencil = shader("overlay_edit_uv_stencil_image");
|
||||
ShaderPtr uv_edit_edge = shader("overlay_edit_uv_edges");
|
||||
ShaderPtr uv_edit_face = shader("overlay_edit_uv_faces");
|
||||
ShaderPtr uv_edit_facedot = shader("overlay_edit_uv_face_dots");
|
||||
ShaderPtr uv_edit_vert = shader("overlay_edit_uv_verts");
|
||||
ShaderPtr uv_image_borders = shader("overlay_edit_uv_tiled_image_borders");
|
||||
ShaderPtr uv_paint_mask = shader("overlay_edit_uv_mask_image");
|
||||
ShaderPtr uv_wireframe = shader("overlay_wireframe_uv");
|
||||
ShaderPtr xray_fade = shader("overlay_xray_fade");
|
||||
StaticShader paint_weight_fake_shading = shader_clippable("overlay_paint_weight_fake_shading");
|
||||
StaticShader particle_edit_vert = shader_clippable("overlay_edit_particle_point");
|
||||
StaticShader particle_edit_edge = shader_clippable("overlay_edit_particle_strand");
|
||||
StaticShader pointcloud_points = shader_clippable("overlay_edit_pointcloud");
|
||||
StaticShader sculpt_curves = shader_clippable("overlay_sculpt_curves_selection");
|
||||
StaticShader sculpt_curves_cage = shader_clippable("overlay_sculpt_curves_cage");
|
||||
StaticShader sculpt_mesh = shader_clippable("overlay_sculpt_mask");
|
||||
StaticShader uniform_color = shader_clippable("overlay_uniform_color");
|
||||
StaticShader uv_analysis_stretch_angle = {"overlay_edit_uv_stretching_angle"};
|
||||
StaticShader uv_analysis_stretch_area = {"overlay_edit_uv_stretching_area"};
|
||||
StaticShader uv_brush_stencil = {"overlay_edit_uv_stencil_image"};
|
||||
StaticShader uv_edit_edge = {"overlay_edit_uv_edges"};
|
||||
StaticShader uv_edit_face = {"overlay_edit_uv_faces"};
|
||||
StaticShader uv_edit_facedot = {"overlay_edit_uv_face_dots"};
|
||||
StaticShader uv_edit_vert = {"overlay_edit_uv_verts"};
|
||||
StaticShader uv_image_borders = {"overlay_edit_uv_tiled_image_borders"};
|
||||
StaticShader uv_paint_mask = {"overlay_edit_uv_mask_image"};
|
||||
StaticShader uv_wireframe = {"overlay_wireframe_uv"};
|
||||
StaticShader xray_fade = {"overlay_xray_fade"};
|
||||
|
||||
/** Selectable Shaders */
|
||||
ShaderPtr armature_envelope_fill = shader_selectable("overlay_armature_envelope_solid");
|
||||
ShaderPtr armature_envelope_outline = shader_selectable("overlay_armature_envelope_outline");
|
||||
ShaderPtr armature_shape_outline = shader_selectable("overlay_armature_shape_outline");
|
||||
ShaderPtr armature_shape_fill = shader_selectable("overlay_armature_shape_solid");
|
||||
ShaderPtr armature_shape_wire = shader_selectable("overlay_armature_shape_wire");
|
||||
ShaderPtr armature_shape_wire_strip = shader_selectable("overlay_armature_shape_wire_strip");
|
||||
ShaderPtr armature_sphere_outline = shader_selectable("overlay_armature_sphere_outline");
|
||||
ShaderPtr armature_sphere_fill = shader_selectable("overlay_armature_sphere_solid");
|
||||
ShaderPtr armature_stick = shader_selectable("overlay_armature_stick");
|
||||
ShaderPtr armature_wire = shader_selectable("overlay_armature_wire");
|
||||
ShaderPtr depth_curves = shader_selectable("overlay_depth_curves");
|
||||
ShaderPtr depth_grease_pencil = shader_selectable("overlay_depth_gpencil");
|
||||
ShaderPtr depth_mesh = shader_selectable("overlay_depth_mesh");
|
||||
ShaderPtr depth_mesh_conservative = shader_selectable("overlay_depth_mesh_conservative");
|
||||
ShaderPtr depth_pointcloud = shader_selectable("overlay_depth_pointcloud");
|
||||
ShaderPtr extra_shape = shader_selectable("overlay_extra");
|
||||
ShaderPtr extra_point = shader_selectable("overlay_extra_point");
|
||||
ShaderPtr extra_wire = shader_selectable("overlay_extra_wire");
|
||||
ShaderPtr extra_wire_object = shader_selectable("overlay_extra_wire_object");
|
||||
ShaderPtr extra_loose_points = shader_selectable("overlay_extra_loose_point");
|
||||
ShaderPtr extra_grid = shader_selectable("overlay_extra_grid");
|
||||
ShaderPtr extra_ground_line = shader_selectable("overlay_extra_groundline");
|
||||
ShaderPtr image_plane = shader_selectable("overlay_image");
|
||||
ShaderPtr image_plane_depth_bias = shader_selectable("overlay_image_depth_bias");
|
||||
ShaderPtr particle_dot = shader_selectable("overlay_particle_dot");
|
||||
ShaderPtr particle_shape = shader_selectable("overlay_particle_shape");
|
||||
ShaderPtr particle_hair = shader_selectable("overlay_particle_hair");
|
||||
ShaderPtr wireframe_mesh = shader_selectable("overlay_wireframe");
|
||||
StaticShader armature_envelope_fill = shader_selectable("overlay_armature_envelope_solid");
|
||||
StaticShader armature_envelope_outline = shader_selectable("overlay_armature_envelope_outline");
|
||||
StaticShader armature_shape_outline = shader_selectable("overlay_armature_shape_outline");
|
||||
StaticShader armature_shape_fill = shader_selectable("overlay_armature_shape_solid");
|
||||
StaticShader armature_shape_wire = shader_selectable("overlay_armature_shape_wire");
|
||||
StaticShader armature_shape_wire_strip = shader_selectable("overlay_armature_shape_wire_strip");
|
||||
StaticShader armature_sphere_outline = shader_selectable("overlay_armature_sphere_outline");
|
||||
StaticShader armature_sphere_fill = shader_selectable("overlay_armature_sphere_solid");
|
||||
StaticShader armature_stick = shader_selectable("overlay_armature_stick");
|
||||
StaticShader armature_wire = shader_selectable("overlay_armature_wire");
|
||||
StaticShader depth_curves = shader_selectable("overlay_depth_curves");
|
||||
StaticShader depth_grease_pencil = shader_selectable("overlay_depth_gpencil");
|
||||
StaticShader depth_mesh = shader_selectable("overlay_depth_mesh");
|
||||
StaticShader depth_mesh_conservative = shader_selectable("overlay_depth_mesh_conservative");
|
||||
StaticShader depth_pointcloud = shader_selectable("overlay_depth_pointcloud");
|
||||
StaticShader extra_shape = shader_selectable("overlay_extra");
|
||||
StaticShader extra_point = shader_selectable("overlay_extra_point");
|
||||
StaticShader extra_wire = shader_selectable("overlay_extra_wire");
|
||||
StaticShader extra_wire_object = shader_selectable("overlay_extra_wire_object");
|
||||
StaticShader extra_loose_points = shader_selectable("overlay_extra_loose_point");
|
||||
StaticShader extra_grid = shader_selectable("overlay_extra_grid");
|
||||
StaticShader extra_ground_line = shader_selectable("overlay_extra_groundline");
|
||||
StaticShader image_plane = shader_selectable("overlay_image");
|
||||
StaticShader image_plane_depth_bias = shader_selectable("overlay_image_depth_bias");
|
||||
StaticShader particle_dot = shader_selectable("overlay_particle_dot");
|
||||
StaticShader particle_shape = shader_selectable("overlay_particle_shape");
|
||||
StaticShader particle_hair = shader_selectable("overlay_particle_hair");
|
||||
StaticShader wireframe_mesh = shader_selectable("overlay_wireframe");
|
||||
/* Draw objects without edges for the wireframe overlay. */
|
||||
ShaderPtr wireframe_points = shader_selectable("overlay_wireframe_points");
|
||||
ShaderPtr wireframe_curve = shader_selectable("overlay_wireframe_curve");
|
||||
StaticShader wireframe_points = shader_selectable("overlay_wireframe_points");
|
||||
StaticShader wireframe_curve = shader_selectable("overlay_wireframe_curve");
|
||||
|
||||
ShaderPtr fluid_grid_lines_flags = shader_selectable_no_clip("overlay_volume_gridlines_flags");
|
||||
ShaderPtr fluid_grid_lines_flat = shader_selectable_no_clip("overlay_volume_gridlines_flat");
|
||||
ShaderPtr fluid_grid_lines_range = shader_selectable_no_clip("overlay_volume_gridlines_range");
|
||||
ShaderPtr fluid_velocity_streamline = shader_selectable_no_clip(
|
||||
StaticShader fluid_grid_lines_flags = shader_selectable_no_clip(
|
||||
"overlay_volume_gridlines_flags");
|
||||
StaticShader fluid_grid_lines_flat = shader_selectable_no_clip("overlay_volume_gridlines_flat");
|
||||
StaticShader fluid_grid_lines_range = shader_selectable_no_clip(
|
||||
"overlay_volume_gridlines_range");
|
||||
StaticShader fluid_velocity_streamline = shader_selectable_no_clip(
|
||||
"overlay_volume_velocity_streamline");
|
||||
ShaderPtr fluid_velocity_mac = shader_selectable_no_clip("overlay_volume_velocity_mac");
|
||||
ShaderPtr fluid_velocity_needle = shader_selectable_no_clip("overlay_volume_velocity_needle");
|
||||
StaticShader fluid_velocity_mac = shader_selectable_no_clip("overlay_volume_velocity_mac");
|
||||
StaticShader fluid_velocity_needle = shader_selectable_no_clip("overlay_volume_velocity_needle");
|
||||
|
||||
/** Module */
|
||||
/** Only to be used by Instance constructor. */
|
||||
@@ -590,13 +597,9 @@ class ShaderModule {
|
||||
ShaderModule(const SelectionType selection_type, const bool clipping_enabled)
|
||||
: selection_type_(selection_type), clipping_enabled_(clipping_enabled){};
|
||||
|
||||
ShaderPtr shader(const char *create_info_name)
|
||||
{
|
||||
return ShaderPtr(GPU_shader_create_from_info_name(create_info_name));
|
||||
}
|
||||
ShaderPtr shader_clippable(const char *create_info_name);
|
||||
ShaderPtr shader_selectable(const char *create_info_name);
|
||||
ShaderPtr shader_selectable_no_clip(const char *create_info_name);
|
||||
StaticShader shader_clippable(const char *create_info_name);
|
||||
StaticShader shader_selectable(const char *create_info_name);
|
||||
StaticShader shader_selectable_no_clip(const char *create_info_name);
|
||||
};
|
||||
|
||||
struct GreasePencilDepthPlane {
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
ShaderModule *ShaderModule::g_shader_modules[2][2] = {{nullptr}};
|
||||
|
||||
ShaderModule::ShaderPtr ShaderModule::shader_clippable(const char *create_info_name)
|
||||
StaticShader ShaderModule::shader_clippable(const char *create_info_name)
|
||||
{
|
||||
std::string name = create_info_name;
|
||||
|
||||
@@ -20,10 +18,10 @@ ShaderModule::ShaderPtr ShaderModule::shader_clippable(const char *create_info_n
|
||||
name += "_clipped";
|
||||
}
|
||||
|
||||
return ShaderPtr(GPU_shader_create_from_info_name(name.c_str()));
|
||||
return StaticShader(name);
|
||||
}
|
||||
|
||||
ShaderModule::ShaderPtr ShaderModule::shader_selectable(const char *create_info_name)
|
||||
StaticShader ShaderModule::shader_selectable(const char *create_info_name)
|
||||
{
|
||||
std::string name = create_info_name;
|
||||
|
||||
@@ -35,10 +33,10 @@ ShaderModule::ShaderPtr ShaderModule::shader_selectable(const char *create_info_
|
||||
name += "_clipped";
|
||||
}
|
||||
|
||||
return ShaderPtr(GPU_shader_create_from_info_name(name.c_str()));
|
||||
return StaticShader(name);
|
||||
}
|
||||
|
||||
ShaderModule::ShaderPtr ShaderModule::shader_selectable_no_clip(const char *create_info_name)
|
||||
StaticShader ShaderModule::shader_selectable_no_clip(const char *create_info_name)
|
||||
{
|
||||
std::string name = create_info_name;
|
||||
|
||||
@@ -46,7 +44,7 @@ ShaderModule::ShaderPtr ShaderModule::shader_selectable_no_clip(const char *crea
|
||||
name += "_selectable";
|
||||
}
|
||||
|
||||
return ShaderPtr(GPU_shader_create_from_info_name(name.c_str()));
|
||||
return StaticShader(name);
|
||||
}
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
@@ -54,23 +52,15 @@ using namespace blender::gpu::shader;
|
||||
ShaderModule &ShaderModule::module_get(SelectionType selection_type, bool clipping_enabled)
|
||||
{
|
||||
int selection_index = selection_type == SelectionType::DISABLED ? 0 : 1;
|
||||
ShaderModule *&g_shader_module = g_shader_modules[selection_index][clipping_enabled];
|
||||
if (g_shader_module == nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
g_shader_module = new ShaderModule(selection_type, clipping_enabled);
|
||||
}
|
||||
return *g_shader_module;
|
||||
return get_static_cache()[selection_index][clipping_enabled].get(selection_type,
|
||||
clipping_enabled);
|
||||
}
|
||||
|
||||
void ShaderModule::module_free()
|
||||
{
|
||||
for (int i : IndexRange(2)) {
|
||||
for (int j : IndexRange(2)) {
|
||||
if (g_shader_modules[i][j] != nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
delete g_shader_modules[i][j];
|
||||
g_shader_modules[i][j] = nullptr;
|
||||
}
|
||||
get_static_cache()[i][j].release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#include "DRW_engine.hh"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
@@ -29,9 +30,34 @@ struct SELECTIDDEBUG_Data {
|
||||
void *engine_type;
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct GPUShader *select_debug_sh;
|
||||
} e_data = {nullptr}; /* Engine data */
|
||||
namespace blender::draw::SelectDebug {
|
||||
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
class ShaderCache {
|
||||
private:
|
||||
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
||||
{
|
||||
static gpu::StaticShaderCache<ShaderCache> static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
public:
|
||||
static ShaderCache &get()
|
||||
{
|
||||
return get_static_cache().get();
|
||||
}
|
||||
static void release()
|
||||
{
|
||||
get_static_cache().release();
|
||||
}
|
||||
|
||||
StaticShader select_debug = {"select_debug_fullscreen"};
|
||||
};
|
||||
|
||||
} // namespace blender::draw::SelectDebug
|
||||
|
||||
using namespace blender::draw::SelectDebug;
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -46,16 +72,12 @@ static void select_debug_draw_scene(void * /*vedata*/)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e_data.select_debug_sh) {
|
||||
e_data.select_debug_sh = GPU_shader_create_from_info_name("select_debug_fullscreen");
|
||||
}
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
PassSimple pass = {"SelectEngineDebug"};
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
|
||||
pass.shader_set(e_data.select_debug_sh);
|
||||
pass.shader_set(ShaderCache::get().select_debug.get());
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
@@ -65,7 +87,7 @@ static void select_debug_draw_scene(void * /*vedata*/)
|
||||
|
||||
static void select_debug_engine_free()
|
||||
{
|
||||
GPU_SHADER_FREE_SAFE(e_data.select_debug_sh);
|
||||
ShaderCache::release();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DRW_render.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
@@ -20,38 +21,10 @@ extern "C" DrawEngineType draw_engine_workbench;
|
||||
namespace blender::workbench {
|
||||
|
||||
using namespace draw;
|
||||
|
||||
class StaticShader : NonCopyable {
|
||||
private:
|
||||
std::string info_name_;
|
||||
GPUShader *shader_ = nullptr;
|
||||
|
||||
public:
|
||||
StaticShader(std::string info_name) : info_name_(info_name) {}
|
||||
|
||||
StaticShader() = default;
|
||||
StaticShader(StaticShader &&other) = default;
|
||||
StaticShader &operator=(StaticShader &&other) = default;
|
||||
|
||||
~StaticShader()
|
||||
{
|
||||
GPU_SHADER_FREE_SAFE(shader_);
|
||||
}
|
||||
|
||||
GPUShader *get()
|
||||
{
|
||||
if (!shader_) {
|
||||
BLI_assert(!info_name_.empty());
|
||||
shader_ = GPU_shader_create_from_info_name(info_name_.c_str());
|
||||
}
|
||||
return shader_;
|
||||
}
|
||||
};
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
class ShaderCache {
|
||||
private:
|
||||
static ShaderCache *static_cache;
|
||||
|
||||
StaticShader prepass_[geometry_type_len][pipeline_type_len][lighting_type_len][shader_type_len]
|
||||
[2 /*clip*/];
|
||||
StaticShader resolve_[lighting_type_len][2 /*cavity*/][2 /*curvature*/][2 /*shadow*/];
|
||||
@@ -60,9 +33,21 @@ class ShaderCache {
|
||||
|
||||
StaticShader volume_[2 /*smoke*/][3 /*interpolation*/][2 /*coba*/][2 /*slice*/];
|
||||
|
||||
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
||||
{
|
||||
static gpu::StaticShaderCache<ShaderCache> static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
public:
|
||||
static ShaderCache &get();
|
||||
static void release();
|
||||
static ShaderCache &get()
|
||||
{
|
||||
return get_static_cache().get();
|
||||
}
|
||||
static void release()
|
||||
{
|
||||
get_static_cache().release();
|
||||
}
|
||||
|
||||
ShaderCache();
|
||||
|
||||
|
||||
@@ -6,24 +6,6 @@
|
||||
|
||||
namespace blender::workbench {
|
||||
|
||||
ShaderCache *ShaderCache::static_cache = nullptr;
|
||||
|
||||
ShaderCache &ShaderCache::get()
|
||||
{
|
||||
if (!ShaderCache::static_cache) {
|
||||
ShaderCache::static_cache = new ShaderCache();
|
||||
}
|
||||
return *ShaderCache::static_cache;
|
||||
}
|
||||
|
||||
void ShaderCache::release()
|
||||
{
|
||||
if (ShaderCache::static_cache) {
|
||||
delete ShaderCache::static_cache;
|
||||
ShaderCache::static_cache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderCache::ShaderCache()
|
||||
{
|
||||
const std::string geometries[] = {"_mesh", "_curves", "_ptcloud"};
|
||||
|
||||
@@ -16,99 +16,83 @@
|
||||
|
||||
#include "DRW_render.hh"
|
||||
|
||||
extern "C" char datatoc_common_hair_lib_glsl[];
|
||||
namespace blender::draw::Shader {
|
||||
|
||||
#define SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS 4
|
||||
static struct {
|
||||
GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER];
|
||||
GPUShader *debug_print_display_sh;
|
||||
GPUShader *debug_draw_display_sh;
|
||||
GPUShader *draw_visibility_compute_sh;
|
||||
GPUShader *draw_view_finalize_sh;
|
||||
GPUShader *draw_resource_finalize_sh;
|
||||
GPUShader *draw_command_generate_sh;
|
||||
|
||||
GPUShader *subdiv_sh[SUBDIVISION_MAX_SHADERS];
|
||||
GPUShader *subdiv_custom_data_sh[SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS][GPU_COMP_MAX];
|
||||
} e_data = {{nullptr}};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Hair refinement
|
||||
* \{ */
|
||||
|
||||
static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader /*refinement*/)
|
||||
{
|
||||
return GPU_shader_create_from_info_name("draw_hair_refine_compute");
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement)
|
||||
{
|
||||
if (e_data.hair_refine_sh[refinement] == nullptr) {
|
||||
GPUShader *sh = hair_refine_shader_compute_create(refinement);
|
||||
e_data.hair_refine_sh[refinement] = sh;
|
||||
class ShaderCache {
|
||||
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
||||
{
|
||||
static gpu::StaticShaderCache<ShaderCache> static_cache;
|
||||
return static_cache;
|
||||
}
|
||||
|
||||
return e_data.hair_refine_sh[refinement];
|
||||
public:
|
||||
static ShaderCache &get()
|
||||
{
|
||||
return get_static_cache().get();
|
||||
}
|
||||
static void release()
|
||||
{
|
||||
get_static_cache().release();
|
||||
}
|
||||
|
||||
gpu::StaticShader hair_refine = {"draw_hair_refine_compute"};
|
||||
gpu::StaticShader debug_draw_display = {"draw_debug_draw_display"};
|
||||
gpu::StaticShader draw_visibility_compute = {"draw_visibility_compute"};
|
||||
gpu::StaticShader draw_view_finalize = {"draw_view_finalize"};
|
||||
gpu::StaticShader draw_resource_finalize = {"draw_resource_finalize"};
|
||||
gpu::StaticShader draw_command_generate = {"draw_command_generate"};
|
||||
};
|
||||
|
||||
} // namespace blender::draw::Shader
|
||||
|
||||
using namespace blender::draw::Shader;
|
||||
|
||||
GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader /*refinement*/)
|
||||
{
|
||||
return ShaderCache::get().hair_refine.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_curves_refine_get(blender::draw::CurvesEvalShader type)
|
||||
GPUShader *DRW_shader_curves_refine_get(blender::draw::CurvesEvalShader /*type*/)
|
||||
{
|
||||
/* TODO: Implement curves evaluation types (Bezier and Catmull Rom). */
|
||||
if (e_data.hair_refine_sh[type] == nullptr) {
|
||||
GPUShader *sh = hair_refine_shader_compute_create(PART_REFINE_CATMULL_ROM);
|
||||
e_data.hair_refine_sh[type] = sh;
|
||||
}
|
||||
|
||||
return e_data.hair_refine_sh[type];
|
||||
return ShaderCache::get().hair_refine.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_debug_draw_display_get()
|
||||
{
|
||||
if (e_data.debug_draw_display_sh == nullptr) {
|
||||
e_data.debug_draw_display_sh = GPU_shader_create_from_info_name("draw_debug_draw_display");
|
||||
}
|
||||
return e_data.debug_draw_display_sh;
|
||||
return ShaderCache::get().debug_draw_display.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_draw_visibility_compute_get()
|
||||
{
|
||||
if (e_data.draw_visibility_compute_sh == nullptr) {
|
||||
e_data.draw_visibility_compute_sh = GPU_shader_create_from_info_name(
|
||||
"draw_visibility_compute");
|
||||
}
|
||||
return e_data.draw_visibility_compute_sh;
|
||||
return ShaderCache::get().draw_visibility_compute.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_draw_view_finalize_get()
|
||||
{
|
||||
if (e_data.draw_view_finalize_sh == nullptr) {
|
||||
e_data.draw_view_finalize_sh = GPU_shader_create_from_info_name("draw_view_finalize");
|
||||
}
|
||||
return e_data.draw_view_finalize_sh;
|
||||
return ShaderCache::get().draw_view_finalize.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_draw_resource_finalize_get()
|
||||
{
|
||||
if (e_data.draw_resource_finalize_sh == nullptr) {
|
||||
e_data.draw_resource_finalize_sh = GPU_shader_create_from_info_name("draw_resource_finalize");
|
||||
}
|
||||
return e_data.draw_resource_finalize_sh;
|
||||
return ShaderCache::get().draw_resource_finalize.get();
|
||||
}
|
||||
|
||||
GPUShader *DRW_shader_draw_command_generate_get()
|
||||
{
|
||||
if (e_data.draw_command_generate_sh == nullptr) {
|
||||
e_data.draw_command_generate_sh = GPU_shader_create_from_info_name("draw_command_generate");
|
||||
}
|
||||
return e_data.draw_command_generate_sh;
|
||||
return ShaderCache::get().draw_command_generate.get();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Subdivision
|
||||
* \{ */
|
||||
|
||||
#define SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS 4
|
||||
static struct {
|
||||
GPUShader *subdiv_sh[SUBDIVISION_MAX_SHADERS];
|
||||
GPUShader *subdiv_custom_data_sh[SHADER_CUSTOM_DATA_INTERP_MAX_DIMENSIONS][GPU_COMP_MAX];
|
||||
} e_data = {{nullptr}};
|
||||
|
||||
static blender::StringRefNull get_subdiv_shader_info_name(SubdivShaderType shader_type)
|
||||
{
|
||||
switch (shader_type) {
|
||||
@@ -239,15 +223,7 @@ GPUShader *DRW_shader_subdiv_custom_data_get(GPUVertCompType comp_type, int dime
|
||||
|
||||
void DRW_shaders_free()
|
||||
{
|
||||
for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
|
||||
GPU_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]);
|
||||
}
|
||||
GPU_SHADER_FREE_SAFE(e_data.debug_print_display_sh);
|
||||
GPU_SHADER_FREE_SAFE(e_data.debug_draw_display_sh);
|
||||
GPU_SHADER_FREE_SAFE(e_data.draw_visibility_compute_sh);
|
||||
GPU_SHADER_FREE_SAFE(e_data.draw_view_finalize_sh);
|
||||
GPU_SHADER_FREE_SAFE(e_data.draw_resource_finalize_sh);
|
||||
GPU_SHADER_FREE_SAFE(e_data.draw_command_generate_sh);
|
||||
ShaderCache::release();
|
||||
|
||||
for (int i = 0; i < SUBDIVISION_MAX_SHADERS; i++) {
|
||||
GPU_SHADER_FREE_SAFE(e_data.subdiv_sh[i]);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_span.hh"
|
||||
@@ -410,3 +411,125 @@ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
|
||||
shader = nullptr; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
/* GPUShader wrapper that makes compilation threadsafe.
|
||||
* The compilation is deferred until the first get() call.
|
||||
* Concurrently using the shader from multiple threads is still unsafe. */
|
||||
class StaticShader : NonCopyable {
|
||||
private:
|
||||
std::string info_name_;
|
||||
std::atomic<GPUShader *> shader_ = nullptr;
|
||||
/* TODO: Failed compilation detection should be supported by the GPUShader API. */
|
||||
std::atomic_bool failed_ = false;
|
||||
std::mutex mutex_;
|
||||
|
||||
void move(StaticShader &&other)
|
||||
{
|
||||
std::scoped_lock lock1(mutex_);
|
||||
std::scoped_lock lock2(other.mutex_);
|
||||
BLI_assert(shader_ == nullptr && info_name_.empty());
|
||||
std::swap(info_name_, other.info_name_);
|
||||
/* No std::swap support for atomics. */
|
||||
shader_.exchange(other.shader_.exchange(shader_));
|
||||
failed_.exchange(other.failed_.exchange(failed_));
|
||||
}
|
||||
|
||||
public:
|
||||
StaticShader(std::string info_name) : info_name_(info_name) {}
|
||||
|
||||
StaticShader() = default;
|
||||
StaticShader(StaticShader &&other)
|
||||
{
|
||||
move(std::move(other));
|
||||
}
|
||||
StaticShader &operator=(StaticShader &&other)
|
||||
{
|
||||
move(std::move(other));
|
||||
return *this;
|
||||
};
|
||||
|
||||
~StaticShader()
|
||||
{
|
||||
GPU_SHADER_FREE_SAFE(shader_);
|
||||
}
|
||||
|
||||
GPUShader *get()
|
||||
{
|
||||
if (shader_ || failed_) {
|
||||
return shader_;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(mutex_);
|
||||
|
||||
if (!shader_ && !failed_) {
|
||||
BLI_assert(!info_name_.empty());
|
||||
shader_ = GPU_shader_create_from_info_name(info_name_.c_str());
|
||||
failed_ = shader_ != nullptr;
|
||||
}
|
||||
|
||||
return shader_;
|
||||
}
|
||||
|
||||
/* For batch compiled shaders. */
|
||||
/* TODO: Find a better way to handle this. */
|
||||
void set(GPUShader *shader)
|
||||
{
|
||||
std::scoped_lock lock(mutex_);
|
||||
BLI_assert(shader_ == nullptr);
|
||||
shader_ = shader;
|
||||
}
|
||||
};
|
||||
|
||||
/* Thread-safe container for StaticShader cache classes.
|
||||
* The class instance creation is deferred until the first get() call. */
|
||||
template<typename T> class StaticShaderCache {
|
||||
std::atomic<T *> cache_ = nullptr;
|
||||
std::mutex mutex_;
|
||||
|
||||
public:
|
||||
~StaticShaderCache()
|
||||
{
|
||||
BLI_assert(cache_ == nullptr);
|
||||
}
|
||||
|
||||
template<typename... Args> T &get(Args &&...constructor_args)
|
||||
{
|
||||
if (cache_) {
|
||||
return *cache_;
|
||||
}
|
||||
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
if (cache_ == nullptr) {
|
||||
cache_ = new T(std::forward<Args>(constructor_args)...);
|
||||
}
|
||||
return *cache_;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (!cache_) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
if (cache_) {
|
||||
delete cache_;
|
||||
cache_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock_guard()
|
||||
{
|
||||
return std::lock_guard(mutex_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
||||
@@ -974,6 +974,8 @@ ShaderCompilerGeneric::~ShaderCompilerGeneric()
|
||||
|
||||
BatchHandle ShaderCompilerGeneric::batch_compile(Span<const shader::ShaderCreateInfo *> &infos)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
BatchHandle handle = next_batch_handle++;
|
||||
batches.add(handle, {{}, infos, true});
|
||||
Batch &batch = batches.lookup(handle);
|
||||
@@ -986,12 +988,16 @@ BatchHandle ShaderCompilerGeneric::batch_compile(Span<const shader::ShaderCreate
|
||||
|
||||
bool ShaderCompilerGeneric::batch_is_ready(BatchHandle handle)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
bool is_ready = batches.lookup(handle).is_ready;
|
||||
return is_ready;
|
||||
}
|
||||
|
||||
Vector<Shader *> ShaderCompilerGeneric::batch_finalize(BatchHandle &handle)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
Vector<Shader *> shaders = batches.pop(handle).shaders;
|
||||
handle = 0;
|
||||
return shaders;
|
||||
|
||||
@@ -191,8 +191,7 @@ class ShaderCompiler {
|
||||
};
|
||||
};
|
||||
|
||||
/* Generic (fully synchronous) implementation for backends that don't implement their own
|
||||
* ShaderCompiler. Used by Vulkan and Metal. */
|
||||
/* Generic (fully synchronous) implementation used as fallback. */
|
||||
class ShaderCompilerGeneric : public ShaderCompiler {
|
||||
private:
|
||||
struct Batch {
|
||||
@@ -202,6 +201,7 @@ class ShaderCompilerGeneric : public ShaderCompiler {
|
||||
};
|
||||
BatchHandle next_batch_handle = 1;
|
||||
Map<BatchHandle, Batch> batches;
|
||||
std::mutex mutex_;
|
||||
|
||||
public:
|
||||
~ShaderCompilerGeneric() override;
|
||||
|
||||
Reference in New Issue
Block a user