/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2021 Blender Foundation. */ /** \file * \ingroup eevee * * Shading passes contain drawcalls specific to shading pipelines. * They are to be shared across views. * This file is only for shading passes. Other passes are declared in their own module. */ #include "eevee_instance.hh" #include "eevee_pipeline.hh" namespace blender::eevee { /* -------------------------------------------------------------------- */ /** \name World Pipeline * * Used to draw background. * \{ */ void WorldPipeline::sync(GPUMaterial *gpumat) { RenderBuffers &rbufs = inst_.render_buffers; DRWState state = DRW_STATE_WRITE_COLOR; world_ps_ = DRW_pass_create("World", state); /* Push a matrix at the same location as the camera. */ float4x4 camera_mat = float4x4::identity(); // copy_v3_v3(camera_mat[3], inst_.camera.data_get().viewinv[3]); DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, world_ps_); DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx); DRW_shgroup_call_obmat(grp, DRW_cache_fullscreen_quad_get(), camera_mat.ptr()); DRW_shgroup_uniform_float_copy(grp, "world_opacity_fade", inst_.film.background_opacity_get()); /* AOVs. */ DRW_shgroup_uniform_image_ref(grp, "aov_color_img", &rbufs.aov_color_tx); DRW_shgroup_uniform_image_ref(grp, "aov_value_img", &rbufs.aov_value_tx); DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info); /* RenderPasses. Cleared by background (even if bad practice). */ DRW_shgroup_uniform_image_ref(grp, "rp_normal_img", &rbufs.normal_tx); DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_light_img", &rbufs.diffuse_light_tx); DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_color_img", &rbufs.diffuse_color_tx); DRW_shgroup_uniform_image_ref(grp, "rp_specular_light_img", &rbufs.specular_light_tx); DRW_shgroup_uniform_image_ref(grp, "rp_specular_color_img", &rbufs.specular_color_tx); DRW_shgroup_uniform_image_ref(grp, "rp_emission_img", &rbufs.emission_tx); /* To allow opaque pass rendering over it. */ DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS); } void WorldPipeline::render() { DRW_draw_pass(world_ps_); } /** \} */ /* -------------------------------------------------------------------- */ /** \name Forward Pass * * NPR materials (using Closure to RGBA) or material using ALPHA_BLEND. * \{ */ void ForwardPipeline::sync() { { DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; prepass_ps_ = DRW_pass_create("Forward.Opaque.Prepass", state); prepass_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity", state | DRW_STATE_WRITE_COLOR); state |= DRW_STATE_CULL_BACK; prepass_culled_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Culled", state); prepass_culled_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity", state | DRW_STATE_WRITE_COLOR); DRW_pass_link(prepass_ps_, prepass_velocity_ps_); DRW_pass_link(prepass_velocity_ps_, prepass_culled_ps_); DRW_pass_link(prepass_culled_ps_, prepass_culled_velocity_ps_); } { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; opaque_ps_ = DRW_pass_create("Forward.Opaque", state); state |= DRW_STATE_CULL_BACK; opaque_culled_ps_ = DRW_pass_create("Forward.Opaque.Culled", state); DRW_pass_link(opaque_ps_, opaque_culled_ps_); } { DRWState state = DRW_STATE_DEPTH_LESS_EQUAL; transparent_ps_ = DRW_pass_create("Forward.Transparent", state); } } DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, GPUMaterial *gpumat) { RenderBuffers &rbufs = inst_.render_buffers; DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? opaque_culled_ps_ : opaque_ps_; // LightModule &lights = inst_.lights; // LightProbeModule &lightprobes = inst_.lightprobes; // RaytracingModule &raytracing = inst_.raytracing; // eGPUSamplerState no_interp = GPU_SAMPLER_DEFAULT; DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, pass); // lights.shgroup_resources(grp); // DRW_shgroup_uniform_block(grp, "sampling_buf", inst_.sampling.ubo_get()); // DRW_shgroup_uniform_block(grp, "grids_buf", lightprobes.grid_ubo_get()); // DRW_shgroup_uniform_block(grp, "cubes_buf", lightprobes.cube_ubo_get()); // DRW_shgroup_uniform_block(grp, "probes_buf", lightprobes.info_ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_grid_tx", lightprobes.grid_tx_ref_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_cube_tx", lightprobes.cube_tx_ref_get()); DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx); /* AOVs. */ DRW_shgroup_uniform_image_ref(grp, "aov_color_img", &rbufs.aov_color_tx); DRW_shgroup_uniform_image_ref(grp, "aov_value_img", &rbufs.aov_value_tx); DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info); /* RenderPasses. */ DRW_shgroup_uniform_image_ref(grp, "rp_normal_img", &rbufs.normal_tx); DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_light_img", &rbufs.diffuse_light_tx); DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_color_img", &rbufs.diffuse_color_tx); DRW_shgroup_uniform_image_ref(grp, "rp_specular_light_img", &rbufs.specular_light_tx); DRW_shgroup_uniform_image_ref(grp, "rp_specular_color_img", &rbufs.specular_color_tx); DRW_shgroup_uniform_image_ref(grp, "rp_emission_img", &rbufs.emission_tx); /* TODO(fclem): Make this only needed if material uses it ... somehow. */ // if (true) { // DRW_shgroup_uniform_texture_ref( // grp, "sss_transmittance_tx", inst_.subsurface.transmittance_ref_get()); // } // if (raytracing.enabled()) { // DRW_shgroup_uniform_block(grp, "rt_diffuse_buf", raytracing.diffuse_data); // DRW_shgroup_uniform_block(grp, "rt_reflection_buf", raytracing.reflection_data); // DRW_shgroup_uniform_block(grp, "rt_refraction_buf", raytracing.refraction_data); // DRW_shgroup_uniform_texture_ref_ex(grp, "radiance_tx", &input_screen_radiance_tx_, // no_interp); // } // if (raytracing.enabled()) { // DRW_shgroup_uniform_block(grp, "hiz_buf", inst_.hiz.ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", inst_.hiz_front.texture_ref_get()); // } return grp; } DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion) { DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? (has_motion ? prepass_culled_velocity_ps_ : prepass_culled_ps_) : (has_motion ? prepass_velocity_ps_ : prepass_ps_); DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, pass); if (has_motion) { inst_.velocity.bind_resources(grp); } return grp; } DRWShadingGroup *ForwardPipeline::material_transparent_add(::Material *blender_mat, GPUMaterial *gpumat) { // LightModule &lights = inst_.lights; // LightProbeModule &lightprobes = inst_.lightprobes; // RaytracingModule &raytracing = inst_.raytracing; // eGPUSamplerState no_interp = GPU_SAMPLER_DEFAULT; DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, transparent_ps_); // lights.shgroup_resources(grp); // DRW_shgroup_uniform_block(grp, "sampling_buf", inst_.sampling.ubo_get()); // DRW_shgroup_uniform_block(grp, "grids_buf", lightprobes.grid_ubo_get()); // DRW_shgroup_uniform_block(grp, "cubes_buf", lightprobes.cube_ubo_get()); // DRW_shgroup_uniform_block(grp, "probes_buf", lightprobes.info_ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_grid_tx", lightprobes.grid_tx_ref_get()); // DRW_shgroup_uniform_texture_ref(grp, "lightprobe_cube_tx", lightprobes.cube_tx_ref_get()); // DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx); /* TODO(fclem): Make this only needed if material uses it ... somehow. */ // if (true) { // DRW_shgroup_uniform_texture_ref( // grp, "sss_transmittance_tx", inst_.subsurface.transmittance_ref_get()); // } // if (raytracing.enabled()) { // DRW_shgroup_uniform_block(grp, "rt_diffuse_buf", raytracing.diffuse_data); // DRW_shgroup_uniform_block(grp, "rt_reflection_buf", raytracing.reflection_data); // DRW_shgroup_uniform_block(grp, "rt_refraction_buf", raytracing.refraction_data); // DRW_shgroup_uniform_texture_ref_ex( // grp, "rt_radiance_tx", &input_screen_radiance_tx_, no_interp); // } // if (raytracing.enabled()) { // DRW_shgroup_uniform_block(grp, "hiz_buf", inst_.hiz.ubo_get()); // DRW_shgroup_uniform_texture_ref(grp, "hiz_tx", inst_.hiz_front.texture_ref_get()); // } DRWState state_disable = DRW_STATE_WRITE_DEPTH; DRWState state_enable = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state_enable |= DRW_STATE_CULL_BACK; } DRW_shgroup_state_disable(grp, state_disable); DRW_shgroup_state_enable(grp, state_enable); return grp; } DRWShadingGroup *ForwardPipeline::prepass_transparent_add(::Material *blender_mat, GPUMaterial *gpumat) { if ((blender_mat->blend_flag & MA_BL_HIDE_BACKFACE) == 0) { return nullptr; } DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, transparent_ps_); DRWState state_disable = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; DRWState state_enable = DRW_STATE_WRITE_DEPTH; if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) { state_enable |= DRW_STATE_CULL_BACK; } DRW_shgroup_state_disable(grp, state_disable); DRW_shgroup_state_enable(grp, state_enable); return grp; } void ForwardPipeline::render(const DRWView *view, Framebuffer &prepass_fb, Framebuffer &combined_fb, GPUTexture *depth_tx, GPUTexture *UNUSED(combined_tx)) { UNUSED_VARS(view, depth_tx, prepass_fb, combined_fb); // HiZBuffer &hiz = inst_.hiz_front; DRW_stats_group_start("ForwardOpaque"); GPU_framebuffer_bind(prepass_fb); DRW_draw_pass(prepass_ps_); // hiz.set_dirty(); // if (inst_.raytracing.enabled()) { // rt_buffer.radiance_copy(combined_tx); // hiz.update(depth_tx); // } // inst_.shadows.set_view(view, depth_tx); GPU_framebuffer_bind(combined_fb); DRW_draw_pass(opaque_ps_); DRW_stats_group_end(); DRW_stats_group_start("ForwardTransparent"); /* TODO(fclem) This is suboptimal. We could sort during sync. */ /* FIXME(fclem) This wont work for panoramic, where we need * to sort by distance to camera, not by z. */ DRW_pass_sort_shgroup_z(transparent_ps_); DRW_draw_pass(transparent_ps_); DRW_stats_group_end(); // if (inst_.raytracing.enabled()) { // gbuffer.ray_radiance_tx.release(); // } } /** \} */ } // namespace blender::eevee