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:
Miguel Pozo
2025-02-27 19:20:33 +01:00
parent ac061e3626
commit f930d71a1e
12 changed files with 439 additions and 405 deletions

View File

@@ -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();
}
/** \} */

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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 {

View File

@@ -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();
}
}
}

View File

@@ -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();
}
/** \} */

View File

@@ -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();

View File

@@ -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"};

View File

@@ -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]);

View File

@@ -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

View File

@@ -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;

View File

@@ -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;