Blender V5.0
workbench_mesh_passes.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7namespace blender::workbench {
8
9/* -------------------------------------------------------------------- */
12
14
16{
17 /* TODO: Move to #draw::Pass. */
18
19 return is_empty_;
20}
21
22void MeshPass::init_pass(SceneResources &resources, DRWState state, int clip_planes)
23{
24 use_custom_ids = true;
25 is_empty_ = true;
27 state_set(state, clip_planes);
34 if (clip_planes > 0) {
36 }
37}
38
39void MeshPass::init_subpasses(ePipelineType pipeline, eLightingType lighting, bool clip)
40{
41 texture_subpass_map_.clear();
42 pipeline_ = pipeline;
43 lighting_ = lighting;
44 clip_ = clip;
45
46 for (auto geom : IndexRange(geometry_type_len)) {
47 for (auto shader : IndexRange(shader_type_len)) {
48 passes_[geom][shader] = nullptr;
49 }
50 }
51}
52
53PassMain::Sub &MeshPass::get_subpass(eGeometryType geometry_type, eShaderType shader_type)
54{
55 static std::string pass_names[geometry_type_len][shader_type_len] = {};
56
57 PassMain::Sub *&sub_pass = passes_[int(geometry_type)][int(shader_type)];
58 if (!sub_pass) {
59 std::string &pass_name = pass_names[int(geometry_type)][int(shader_type)];
60 if (pass_name.empty()) {
61 pass_name = std::string(get_name(geometry_type)) + std::string(get_name(shader_type));
62 }
63 sub_pass = &sub(pass_name.c_str());
64 sub_pass->shader_set(
65 ShaderCache::get().prepass_get(geometry_type, pipeline_, lighting_, shader_type, clip_));
66 }
67
68 return *sub_pass;
69}
70
71PassMain::Sub &MeshPass::get_subpass(eGeometryType geometry_type,
72 const MaterialTexture *texture /* = nullptr */)
73{
74 is_empty_ = false;
75
76 if (texture && texture->gpu.texture && *texture->gpu.texture) {
77 auto add_cb = [&] {
78 PassMain::Sub *sub_pass = &get_subpass(geometry_type, eShaderType::TEXTURE);
79 sub_pass = &sub_pass->sub(texture->name);
80 if (texture->gpu.tile_mapping) {
81 sub_pass->bind_texture(WB_TILE_ARRAY_SLOT, texture->gpu.texture, texture->sampler_state);
82 sub_pass->bind_texture(WB_TILE_DATA_SLOT, texture->gpu.tile_mapping);
83 }
84 else {
85 sub_pass->bind_texture(WB_TEXTURE_SLOT, texture->gpu.texture, texture->sampler_state);
86 }
87 sub_pass->push_constant("is_image_tile", texture->gpu.tile_mapping != nullptr);
88 sub_pass->push_constant("image_premult", texture->premultiplied);
89 /* TODO(@pragma37): This setting should be exposed on the user side,
90 * either as a global parameter (and set it here)
91 * or by reading the Material Clipping Threshold (and set it per material) */
92 float alpha_cutoff = texture->alpha_cutoff ? 0.1f : -FLT_MAX;
93 sub_pass->push_constant("image_transparency_cutoff", alpha_cutoff);
94 return sub_pass;
95 };
96
97 return *texture_subpass_map_.lookup_or_add_cb(
98 {*texture->gpu.texture, texture->sampler_state, geometry_type}, add_cb);
99 }
100
101 return get_subpass(geometry_type, eShaderType::MATERIAL);
102}
103
105
106/* -------------------------------------------------------------------- */
109
110void OpaquePass::sync(const SceneState &scene_state, SceneResources &resources)
111{
114
115 bool clip = scene_state.clip_planes.size() > 0;
116
117 DRWState in_front_state = state | DRW_STATE_STENCIL_ALWAYS;
118 gbuffer_in_front_ps_.init_pass(resources, in_front_state, scene_state.clip_planes.size());
119 gbuffer_in_front_ps_.state_stencil(uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, 0x00);
120 gbuffer_in_front_ps_.init_subpasses(ePipelineType::OPAQUE, scene_state.lighting_type, clip);
121
123 gbuffer_ps_.init_pass(resources, state, scene_state.clip_planes.size());
124 gbuffer_ps_.state_stencil(
125 uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT));
126 gbuffer_ps_.init_subpasses(ePipelineType::OPAQUE, scene_state.lighting_type, clip);
127
128 deferred_ps_.init();
130 deferred_ps_.shader_set(ShaderCache::get().resolve_get(scene_state.lighting_type,
131 scene_state.draw_cavity,
132 scene_state.draw_curvature,
133 scene_state.draw_shadows));
134 deferred_ps_.push_constant("force_shadowing", false);
135 deferred_ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf);
136 deferred_ps_.bind_texture(WB_MATCAP_SLOT, resources.matcap_tx);
137 deferred_ps_.bind_texture("normal_tx", &gbuffer_normal_tx);
138 deferred_ps_.bind_texture("material_tx", &gbuffer_material_tx);
139 deferred_ps_.bind_texture("depth_tx", &resources.depth_tx);
140 deferred_ps_.bind_texture("stencil_tx", &deferred_ps_stencil_tx);
141 resources.cavity.setup_resolve_pass(deferred_ps_, resources);
142 deferred_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
143}
144
146 View &view,
147 SceneResources &resources,
148 int2 resolution,
149 ShadowPass *shadow_pass)
150{
151 if (is_empty()) {
152 return;
153 }
154 gbuffer_material_tx.acquire(resolution,
155 gpu::TextureFormat::SFLOAT_16_16_16_16,
157 gbuffer_normal_tx.acquire(resolution,
158 gpu::TextureFormat::SFLOAT_16_16,
160
161 GPUAttachment object_id_attachment = GPU_ATTACHMENT_NONE;
162 if (resources.object_id_tx.is_valid()) {
163 object_id_attachment = GPU_ATTACHMENT_TEXTURE(resources.object_id_tx);
164 }
165
166 if (!gbuffer_in_front_ps_.is_empty()) {
170 object_id_attachment);
171 gbuffer_in_front_fb.bind();
172
174
175 if (resources.depth_in_front_tx.is_valid()) {
176 GPU_texture_copy(resources.depth_in_front_tx, resources.depth_tx);
177 }
178 }
179
180 if (!gbuffer_ps_.is_empty()) {
184 object_id_attachment);
185 gbuffer_fb.bind();
186
187 manager.submit(gbuffer_ps_, view);
188 }
189
190 if (shadow_pass) {
191 shadow_depth_stencil_tx.ensure_2d(gpu::TextureFormat::SFLOAT_32_DEPTH_UINT_8,
192 resolution,
196
199 clear_fb.bind();
201
202 shadow_pass->draw(
203 manager, view, resources, **&shadow_depth_stencil_tx, !gbuffer_in_front_ps_.is_empty());
205 }
206 else {
208 deferred_ps_stencil_tx = nullptr;
209 }
210
211 if (!shadow_pass || !shadow_pass->is_debug()) {
214 deferred_fb.bind();
215 manager.submit(deferred_ps_, view);
216 }
217
218 gbuffer_normal_tx.release();
219 gbuffer_material_tx.release();
220}
221
223{
224 return gbuffer_ps_.is_empty() && gbuffer_in_front_ps_.is_empty();
225}
226
228
229/* -------------------------------------------------------------------- */
232
233void TransparentPass::sync(const SceneState &scene_state, SceneResources &resources)
234{
236 scene_state.cull_state;
237
238 bool clip = scene_state.clip_planes.size() > 0;
239
240 accumulation_ps_.init_pass(
241 resources, state | DRW_STATE_STENCIL_NEQUAL, scene_state.clip_planes.size());
242 accumulation_ps_.state_stencil(
243 uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT));
244 accumulation_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f));
245 accumulation_ps_.init_subpasses(ePipelineType::TRANSPARENT, scene_state.lighting_type, clip);
246
247 accumulation_in_front_ps_.init_pass(resources, state, scene_state.clip_planes.size());
248 accumulation_in_front_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f));
249 accumulation_in_front_ps_.init_subpasses(
250 ePipelineType::TRANSPARENT, scene_state.lighting_type, clip);
251
252 resolve_ps_.init();
254 resolve_ps_.shader_set(ShaderCache::get().transparent_resolve.get());
255 resolve_ps_.bind_texture("transparent_accum", &accumulation_tx);
256 resolve_ps_.bind_texture("transparent_revealage", &reveal_tx);
257 resolve_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
258}
259
261 View &view,
262 SceneResources &resources,
263 int2 resolution)
264{
265 if (is_empty()) {
266 return;
267 }
268 accumulation_tx.acquire(resolution,
269 gpu::TextureFormat::SFLOAT_16_16_16_16,
271 reveal_tx.acquire(resolution,
272 gpu::TextureFormat::SFLOAT_16,
274
276
277 if (!accumulation_ps_.is_empty()) {
281 transparent_fb.bind();
282 manager.submit(accumulation_ps_, view);
283 resolve_fb.bind();
284 manager.submit(resolve_ps_, view);
285 }
286 if (!accumulation_in_front_ps_.is_empty()) {
290 transparent_fb.bind();
292 resolve_fb.bind();
293 manager.submit(resolve_ps_, view);
294 }
295
296 accumulation_tx.release();
297 reveal_tx.release();
298}
299
301{
302 return accumulation_ps_.is_empty() && accumulation_in_front_ps_.is_empty();
303}
304
306
307/* -------------------------------------------------------------------- */
310
311void TransparentDepthPass::sync(const SceneState &scene_state, SceneResources &resources)
312{
315
316 bool clip = scene_state.clip_planes.size() > 0;
317
318 DRWState in_front_state = state | DRW_STATE_STENCIL_ALWAYS;
319 in_front_ps_.init_pass(resources, in_front_state, scene_state.clip_planes.size());
320 in_front_ps_.state_stencil(uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, 0x00);
322
323 merge_ps_.init();
324 merge_ps_.shader_set(ShaderCache::get().merge_depth.get());
327 merge_ps_.state_stencil(
329 merge_ps_.bind_texture("depth_tx", &resources.depth_in_front_tx);
330 merge_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
331
333 main_ps_.init_pass(resources, state, scene_state.clip_planes.size());
334 main_ps_.state_stencil(
335 uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT));
337}
338
340{
341 if (is_empty()) {
342 return;
343 }
344
345 GPUAttachment object_id_attachment = GPU_ATTACHMENT_NONE;
346 if (resources.object_id_tx.is_valid()) {
347 object_id_attachment = GPU_ATTACHMENT_TEXTURE(resources.object_id_tx);
348 }
349
350 if (!in_front_ps_.is_empty()) {
354 object_id_attachment);
355 in_front_fb.bind();
356 manager.submit(in_front_ps_, view);
357
358 merge_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
359 merge_fb.bind();
360 manager.submit(merge_ps_, view);
361 }
362
363 if (!main_ps_.is_empty()) {
364 main_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
367 object_id_attachment);
368 main_fb.bind();
369 manager.submit(main_ps_, view);
370 }
371}
372
374{
375 return main_ps_.is_empty() && in_front_ps_.is_empty();
376}
377
379
380} // namespace blender::workbench
static AppView * view
#define GPU_ATTACHMENT_TEXTURE(_texture)
void GPU_framebuffer_clear_stencil(blender::gpu::FrameBuffer *fb, uint clear_stencil)
#define GPU_ATTACHMENT_NONE
@ GPU_PRIM_TRIS
void GPU_texture_copy(blender::gpu::Texture *dst, blender::gpu::Texture *src)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_FORMAT_VIEW
void submit(PassSimple &pass, View &view)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void state_set(DRWState state, int clip_plane_count=0)
void bind_ubo(const char *name, gpu::UniformBuf *buffer)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, gpu::StorageBuf *buffer)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
void setup_resolve_pass(PassSimple &pass, SceneResources &resources)
void init_pass(SceneResources &resources, DRWState state, int clip_planes)
void init_subpasses(ePipelineType pipeline, eLightingType lighting, bool clip)
void sync(const SceneState &scene_state, SceneResources &resources)
void draw(Manager &manager, View &view, SceneResources &resources, int2 resolution, class ShadowPass *shadow_pass)
void draw(Manager &manager, View &view, SceneResources &resources, gpu::Texture &depth_stencil_tx, bool force_fail_method)
void draw(Manager &manager, View &view, SceneResources &resources)
void sync(const SceneState &scene_state, SceneResources &resources)
void sync(const SceneState &scene_state, SceneResources &resources)
void draw(Manager &manager, View &view, SceneResources &resources, int2 resolution)
#define DRW_CLIPPING_UBO_SLOT
DRWState
Definition draw_state.hh:25
@ DRW_STATE_STENCIL_EQUAL
Definition draw_state.hh:47
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_STENCIL_ALWAYS
Definition draw_state.hh:46
@ DRW_STATE_DEPTH_LESS
Definition draw_state.hh:37
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_BLEND_OIT
Definition draw_state.hh:59
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_STENCIL_NEQUAL
Definition draw_state.hh:48
@ DRW_STATE_WRITE_STENCIL
Definition draw_state.hh:32
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
static ulong state[N]
detail::Pass< command::DrawMultiBuf > PassMain
static constexpr int geometry_type_len
static constexpr int shader_type_len
static const char * get_name(eGeometryType type)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
const char * name
#define FLT_MAX
Definition stdcycles.h:14
UniformBuffer< WorldData > world_buf
StorageVectorBuffer< Material > material_buf
UniformArrayBuffer< float4, 6 > clip_planes_buf
#define WB_TEXTURE_SLOT
#define WB_MATCAP_SLOT
#define WB_TILE_DATA_SLOT
#define WB_MATERIAL_SLOT
#define WB_WORLD_SLOT
#define WB_TILE_ARRAY_SLOT