Blender V4.5
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
13MeshPass::MeshPass(const char *name) : PassMain(name){};
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 TextureSubPassKey(*texture->gpu.texture, 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(
156 gbuffer_normal_tx.acquire(
158
159 GPUAttachment object_id_attachment = GPU_ATTACHMENT_NONE;
160 if (resources.object_id_tx.is_valid()) {
161 object_id_attachment = GPU_ATTACHMENT_TEXTURE(resources.object_id_tx);
162 }
163
164 if (!gbuffer_in_front_ps_.is_empty()) {
168 object_id_attachment);
169 gbuffer_in_front_fb.bind();
170
172
173 if (resources.depth_in_front_tx.is_valid()) {
174 GPU_texture_copy(resources.depth_in_front_tx, resources.depth_tx);
175 }
176 }
177
178 if (!gbuffer_ps_.is_empty()) {
182 object_id_attachment);
183 gbuffer_fb.bind();
184
185 manager.submit(gbuffer_ps_, view);
186 }
187
188 if (shadow_pass) {
190 resolution,
194
197 clear_fb.bind();
199
200 shadow_pass->draw(
201 manager, view, resources, **&shadow_depth_stencil_tx, !gbuffer_in_front_ps_.is_empty());
203 }
204 else {
206 deferred_ps_stencil_tx = nullptr;
207 }
208
209 if (!shadow_pass || !shadow_pass->is_debug()) {
212 deferred_fb.bind();
213 manager.submit(deferred_ps_, view);
214 }
215
216 gbuffer_normal_tx.release();
217 gbuffer_material_tx.release();
218}
219
221{
222 return gbuffer_ps_.is_empty() && gbuffer_in_front_ps_.is_empty();
223}
224
226
227/* -------------------------------------------------------------------- */
230
231void TransparentPass::sync(const SceneState &scene_state, SceneResources &resources)
232{
234 scene_state.cull_state;
235
236 bool clip = scene_state.clip_planes.size() > 0;
237
238 accumulation_ps_.init_pass(
239 resources, state | DRW_STATE_STENCIL_NEQUAL, scene_state.clip_planes.size());
240 accumulation_ps_.state_stencil(
241 uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT));
242 accumulation_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f));
243 accumulation_ps_.init_subpasses(ePipelineType::TRANSPARENT, scene_state.lighting_type, clip);
244
245 accumulation_in_front_ps_.init_pass(resources, state, scene_state.clip_planes.size());
246 accumulation_in_front_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f));
247 accumulation_in_front_ps_.init_subpasses(
248 ePipelineType::TRANSPARENT, scene_state.lighting_type, clip);
249
250 resolve_ps_.init();
252 resolve_ps_.shader_set(ShaderCache::get().transparent_resolve.get());
253 resolve_ps_.bind_texture("transparent_accum", &accumulation_tx);
254 resolve_ps_.bind_texture("transparent_revealage", &reveal_tx);
255 resolve_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
256}
257
259 View &view,
260 SceneResources &resources,
261 int2 resolution)
262{
263 if (is_empty()) {
264 return;
265 }
266 accumulation_tx.acquire(
268 reveal_tx.acquire(
270
272
273 if (!accumulation_ps_.is_empty()) {
277 transparent_fb.bind();
278 manager.submit(accumulation_ps_, view);
279 resolve_fb.bind();
280 manager.submit(resolve_ps_, view);
281 }
282 if (!accumulation_in_front_ps_.is_empty()) {
286 transparent_fb.bind();
288 resolve_fb.bind();
289 manager.submit(resolve_ps_, view);
290 }
291
292 accumulation_tx.release();
293 reveal_tx.release();
294}
295
297{
298 return accumulation_ps_.is_empty() && accumulation_in_front_ps_.is_empty();
299}
300
302
303/* -------------------------------------------------------------------- */
306
307void TransparentDepthPass::sync(const SceneState &scene_state, SceneResources &resources)
308{
311
312 bool clip = scene_state.clip_planes.size() > 0;
313
314 DRWState in_front_state = state | DRW_STATE_STENCIL_ALWAYS;
315 in_front_ps_.init_pass(resources, in_front_state, scene_state.clip_planes.size());
316 in_front_ps_.state_stencil(uint8_t(StencilBits::OBJECT_IN_FRONT), 0xFF, 0x00);
318
319 merge_ps_.init();
320 merge_ps_.shader_set(ShaderCache::get().merge_depth.get());
323 merge_ps_.state_stencil(
325 merge_ps_.bind_texture("depth_tx", &resources.depth_in_front_tx);
326 merge_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
327
329 main_ps_.init_pass(resources, state, scene_state.clip_planes.size());
330 main_ps_.state_stencil(
331 uint8_t(StencilBits::OBJECT), 0xFF, uint8_t(StencilBits::OBJECT_IN_FRONT));
333}
334
336{
337 if (is_empty()) {
338 return;
339 }
340
341 GPUAttachment object_id_attachment = GPU_ATTACHMENT_NONE;
342 if (resources.object_id_tx.is_valid()) {
343 object_id_attachment = GPU_ATTACHMENT_TEXTURE(resources.object_id_tx);
344 }
345
346 if (!in_front_ps_.is_empty()) {
350 object_id_attachment);
351 in_front_fb.bind();
352 manager.submit(in_front_ps_, view);
353
354 merge_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
355 merge_fb.bind();
356 manager.submit(merge_ps_, view);
357 }
358
359 if (!main_ps_.is_empty()) {
360 main_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
363 object_id_attachment);
364 main_fb.bind();
365 manager.submit(main_ps_, view);
366 }
367}
368
370{
371 return main_ps_.is_empty() && in_front_ps_.is_empty();
372}
373
375
376} // namespace blender::workbench
static AppView * view
#define GPU_ATTACHMENT_TEXTURE(_texture)
void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
#define GPU_ATTACHMENT_NONE
@ GPU_PRIM_TRIS
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_FORMAT_VIEW
@ GPU_RG16F
@ GPU_DEPTH24_STENCIL8
@ GPU_R16F
@ GPU_RGBA16F
void submit(PassSimple &pass, View &view)
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state=sampler_auto)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:681
void state_set(DRWState state, int clip_plane_count=0)
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:490
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, GPUTexture &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
#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