Use subpasses to do 3D rendering and resolve in mobile renderer

This commit is contained in:
Bastiaan Olij 2021-06-26 20:49:25 +10:00
parent 2f1bc509dc
commit b920bf05a4
16 changed files with 798 additions and 155 deletions

View file

@ -1148,7 +1148,7 @@
</constant>
<constant name="TEXTURE_USAGE_CAN_COPY_TO_BIT" value="256" enum="TextureUsageBits">
</constant>
<constant name="TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT" value="512" enum="TextureUsageBits">
<constant name="TEXTURE_USAGE_INPUT_ATTACHMENT_BIT" value="512" enum="TextureUsageBits">
</constant>
<constant name="TEXTURE_SWIZZLE_IDENTITY" value="0" enum="TextureSwizzle">
</constant>

View file

@ -1804,6 +1804,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
if (p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
@ -2134,6 +2138,10 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
}
}
if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
@ -3275,8 +3283,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
for (int i = 0; i < p_attachments.size(); i++) {
ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE);
ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE);
ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)),
VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set.");
ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)),
VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set.");
VkAttachmentDescription description = {};
description.flags = 0;
@ -3473,7 +3481,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
} else {
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as input attachment.");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
reference.attachment = attachment;
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@ -3497,12 +3505,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ").");
ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused.");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as resolve attachment.");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;
ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
reference.attachment = attachment;
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
resolve_references.push_back(reference);
@ -3632,8 +3640,10 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
render_pass_create_info.pDependencies = nullptr;
}
// These are only used if we use multiview but we need to define them in scope.
const uint32_t view_mask = (1 << p_view_count) - 1;
const uint32_t correlation_mask = (1 << p_view_count) - 1;
Vector<uint32_t> view_masks;
VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
if (p_view_count > 1) {
@ -3645,10 +3655,15 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// Make sure we limit this to the number of views we support.
ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");
// Set view masks for each subpass
for (uint32_t i = 0; i < subpasses.size(); i++) {
view_masks.push_back(view_mask);
};
render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
render_pass_multiview_create_info.pNext = nullptr;
render_pass_multiview_create_info.subpassCount = 1;
render_pass_multiview_create_info.pViewMasks = &view_mask;
render_pass_multiview_create_info.subpassCount = subpasses.size();
render_pass_multiview_create_info.pViewMasks = view_masks.ptr();
render_pass_multiview_create_info.dependencyCount = 0;
render_pass_multiview_create_info.pViewOffsets = nullptr;
render_pass_multiview_create_info.correlationMaskCount = 1;
@ -4506,6 +4521,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
need_array_dimensions = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
ERR_PRINT("Acceleration structure not supported.");
@ -5490,7 +5506,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.sampler = *sampler;
img_info.imageView = texture->view;
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) {
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
UniformSet::AttachableTexture attachable_texture;
attachable_texture.bind = set_uniform.binding;
attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1];
@ -5543,7 +5559,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.sampler = VK_NULL_HANDLE;
img_info.imageView = texture->view;
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) {
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
UniformSet::AttachableTexture attachable_texture;
attachable_texture.bind = set_uniform.binding;
attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j];
@ -7416,6 +7432,10 @@ void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) {
vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor);
}
uint32_t RenderingDeviceVulkan::draw_list_get_current_pass() {
return draw_list_current_subpass;
}
RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() {
ERR_FAIL_COND_V(draw_list == nullptr, INVALID_ID);
ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);

View file

@ -1149,6 +1149,7 @@ public:
virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
virtual void draw_list_disable_scissor(DrawListID p_list);
virtual uint32_t draw_list_get_current_pass();
virtual DrawListID draw_list_switch_to_next_pass();
virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);

View file

@ -70,6 +70,28 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) {
return uniform_set;
}
RID EffectsRD::_get_uniform_set_for_input(RID p_texture) {
if (input_to_uniform_set_cache.has(p_texture)) {
RID uniform_set = input_to_uniform_set_cache[p_texture];
if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
return uniform_set;
}
}
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT;
u.binding = 0;
u.ids.push_back(p_texture);
uniforms.push_back(u);
// This is specific to our subpass shader
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, TONEMAP_MODE_SUBPASS), 0);
input_to_uniform_set_cache[p_texture] = uniform_set;
return uniform_set;
}
RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
if (texture_to_uniform_set_cache.has(p_texture)) {
RID uniform_set = texture_to_uniform_set_cache[p_texture];
@ -85,7 +107,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps)
u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
u.ids.push_back(p_texture);
uniforms.push_back(u);
//anything with the same configuration (one texture in binding 0 for set 0), is good
// anything with the same configuration (one texture in binding 0 for set 0), is good
RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0);
texture_to_uniform_set_cache[p_texture] = uniform_set;
@ -778,11 +800,11 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
if (p_settings.view_count > 1) {
// Use MULTIVIEW versions
mode += 4;
mode += 6;
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2);
@ -794,6 +816,45 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
RD::get_singleton()->draw_list_end();
}
void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) {
memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
tonemap.push_constant.use_bcs = p_settings.use_bcs;
tonemap.push_constant.bcs[0] = p_settings.brightness;
tonemap.push_constant.bcs[1] = p_settings.contrast;
tonemap.push_constant.bcs[2] = p_settings.saturation;
ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses.");
tonemap.push_constant.use_glow = p_settings.use_glow;
int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS;
if (p_settings.view_count > 1) {
// Use MULTIVIEW versions
mode += 6;
}
tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
tonemap.push_constant.exposure = p_settings.exposure;
tonemap.push_constant.white = p_settings.white;
tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
tonemap.push_constant.use_debanding = p_settings.use_debanding;
RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0);
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored
RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3);
RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array);
RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true);
}
void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer.");
@ -1813,12 +1874,16 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n");
// multiview versions of our shaders
tonemap_modes.push_back("\n#define MULTIVIEW\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n");
tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n");
tonemap.shader.initialize(tonemap_modes);
@ -1827,6 +1892,8 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false);
}
tonemap.shader_version = tonemap.shader.version_create();

View file

@ -238,11 +238,15 @@ private:
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
TONEMAP_MODE_1D_LUT,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
TONEMAP_MODE_SUBPASS,
TONEMAP_MODE_SUBPASS_1D_LUT,
TONEMAP_MODE_NORMAL_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW,
TONEMAP_MODE_1D_LUT_MULTIVIEW,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW,
TONEMAP_MODE_SUBPASS_MULTIVIEW,
TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW,
TONEMAP_MODE_MAX
};
@ -718,6 +722,7 @@ private:
RID index_array;
Map<RID, RID> texture_to_uniform_set_cache;
Map<RID, RID> input_to_uniform_set_cache;
Map<RID, RID> image_to_uniform_set_cache;
@ -751,6 +756,7 @@ private:
Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache;
RID _get_uniform_set_from_image(RID p_texture);
RID _get_uniform_set_for_input(RID p_texture);
RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler);
@ -842,6 +848,7 @@ public:
};
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings);
void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set);

View file

@ -183,7 +183,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
}
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support");
@ -1555,6 +1555,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
RD::get_singleton()->draw_command_end_label();
if (p_render_data->render_buffers.is_valid()) {
_debug_draw_cluster(p_render_data->render_buffers);
RENDER_TIMESTAMP("Tonemap");
_render_buffers_post_process_and_tonemap(p_render_data);
}
}
void RenderForwardClustered::_render_shadow_begin() {

View file

@ -112,7 +112,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void ensure_specular();
void ensure_voxelgi();
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardClustered();
};

View file

@ -78,12 +78,16 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
color = RID();
depth = RID();
color_fb = RID();
for (int i = 0; i < FB_CONFIG_MAX; i++) {
color_fbs[i] = RID();
}
}
void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
bool is_half_resolution = false; // Set this once we support this feature.
msaa = p_msaa;
width = p_width;
@ -93,15 +97,50 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
color = p_color_buffer;
depth = p_depth_buffer;
RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();
// We are creating 4 configurations here for our framebuffers.
if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
Vector<RID> fb;
fb.push_back(p_color_buffer);
fb.push_back(depth);
fb.push_back(p_color_buffer); // 0 - color buffer
fb.push_back(depth); // 1 - depth buffer
color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
// Now define our subpasses
Vector<RD::FramebufferPass> passes;
RD::FramebufferPass pass;
// re-using the same attachments
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
// - opaque pass
passes.push_back(pass);
color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
// - add sky pass
passes.push_back(pass);
color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
// - add alpha pass
passes.push_back(pass);
color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
if (!is_half_resolution) {
// - add blit to 2D pass
fb.push_back(p_target_buffer); // 2 - target buffer
RD::FramebufferPass blit_pass;
blit_pass.color_attachments.push_back(2);
blit_pass.input_attachments.push_back(0);
passes.push_back(blit_pass);
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
} else {
// can't do our blit pass if resolutions don't match
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
}
} else {
RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format();
RD::TextureFormat tf;
if (view_count > 1) {
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
@ -134,14 +173,87 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b
{
Vector<RID> fb;
fb.push_back(color_msaa);
fb.push_back(depth_msaa);
fb.push_back(color_msaa); // 0 - msaa color buffer
fb.push_back(depth_msaa); // 1 - msaa depth buffer
color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
// Now define our subpasses
Vector<RD::FramebufferPass> passes;
RD::FramebufferPass pass;
// re-using the same attachments
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
// - opaque pass
passes.push_back(pass);
// - add sky pass
fb.push_back(color); // 2 - color buffer
passes.push_back(pass); // without resolve for our 3 + 4 subpass config
{
// but with resolve for our 2 subpass config
Vector<RD::FramebufferPass> two_passes;
two_passes.push_back(pass); // opaque subpass without resolve
pass.resolve_attachments.push_back(2);
two_passes.push_back(pass); // sky subpass with resolve
color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count);
}
// - add alpha pass (with resolve, we just added that above)
passes.push_back(pass);
color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
{
// we also need our one pass with resolve
Vector<RD::FramebufferPass> one_pass_with_resolve;
one_pass_with_resolve.push_back(pass); // note our pass configuration already has resolve..
color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, one_pass_with_resolve, RenderingDevice::INVALID_ID, view_count);
}
if (!is_half_resolution) {
// - add blit to 2D pass
fb.push_back(p_target_buffer); // 3 - target buffer
RD::FramebufferPass blit_pass;
blit_pass.color_attachments.push_back(3);
blit_pass.input_attachments.push_back(2);
passes.push_back(blit_pass);
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count);
} else {
// can't do our blit pass if resolutions don't match
color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID();
}
}
}
}
RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
// Our attachments
Vector<RID> fb;
fb.push_back(p_color); // 0
fb.push_back(p_depth); // 1
// Now define our subpasses
Vector<RD::FramebufferPass> passes;
RD::FramebufferPass pass;
// re-using the same attachments
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
// - opaque pass
passes.push_back(pass);
// - sky pass
passes.push_back(pass);
// - alpha pass
passes.push_back(pass);
return RD::get_singleton()->framebuffer_create_multipass(fb, passes);
}
RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
clear();
}
@ -365,14 +477,29 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
scene_state.ubo.viewport_size[1] = vp_he.y;
scene_state.ubo.directional_light_count = 0;
Size2i screen_size;
RID opaque_framebuffer;
RID alpha_framebuffer;
bool reverse_cull = false;
// We can only use our full subpass approach if we're:
// - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
// - not using ssr/sss (currently not supported)
// - not using glow or other post effects (can't do 4th subpass)
// - rendering to a half sized render buffer (can't do 4th subpass)
// We'll need to restrict how far we're going with subpasses based on this.
// I don't think we support either of these in our mobile renderer so probably should phase them out
bool using_ssr = false;
bool using_sss = false;
Size2i screen_size;
RID framebuffer;
bool reverse_cull = false;
bool using_subpass_transparent = true;
bool using_subpass_post_process = true;
bool is_half_resolution = false; // Set this once we support this feature.
bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out
bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out
// fill our render lists early so we can find out if we use various features
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
_fill_element_info(RENDER_LIST_OPAQUE);
_fill_element_info(RENDER_LIST_ALPHA);
if (p_render_data->render_info) {
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size();
@ -384,15 +511,36 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
screen_size.x = render_buffer->width;
screen_size.y = render_buffer->height;
opaque_framebuffer = render_buffer->color_fb;
alpha_framebuffer = opaque_framebuffer;
if (is_half_resolution) {
// can't do blit subpass
using_subpass_post_process = false;
} else if (env && (env->glow_enabled || env->auto_exposure || camera_effects_uses_dof(p_render_data->camera_effects))) {
// can't do blit subpass
using_subpass_post_process = false;
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
// can't use our last two subpasses
using_subpass_transparent = false;
using_subpass_post_process = false;
}
if (using_subpass_post_process) {
// all as subpasses
framebuffer = render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES];
} else if (using_subpass_transparent) {
// our tonemap pass is separate
framebuffer = render_buffer->color_fbs[FB_CONFIG_THREE_SUBPASSES];
} else {
// only opaque and sky as subpasses
framebuffer = render_buffer->color_fbs[FB_CONFIG_TWO_SUBPASSES];
}
} else if (p_render_data->reflection_probe.is_valid()) {
uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
alpha_framebuffer = opaque_framebuffer;
framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
@ -400,6 +548,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
reverse_cull = true;
using_subpass_transparent = true; // we ignore our screen/depth texture here
using_subpass_post_process = false; // not applicable at all for reflection probes.
} else {
ERR_FAIL(); //bug?
}
@ -411,17 +561,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
// we no longer use this...
_fill_instance_data(RENDER_LIST_OPAQUE);
_fill_instance_data(RENDER_LIST_ALPHA);
RD::get_singleton()->draw_command_end_label();
// note, no depth prepass here!
RD::get_singleton()->draw_command_end_label(); // Render Setup
// setup environment
RID radiance_texture;
@ -496,97 +636,199 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// do not try to draw sky if invalid
draw_sky = false;
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_command_end_label(); // Setup Sky
}
} else {
clear_color = p_default_bg_color;
}
// opaque pass
// !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here
// does trigger shadow map rendering so kinda important
_pre_opaque_render(p_render_data, false, false, RID(), RID());
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
RENDER_TIMESTAMP("Render Opaque Pass");
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
// regular forward for now
Vector<Color> c;
c.push_back(clear_color.to_linear());
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
_render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
}
RD::get_singleton()->draw_command_end_label();
// update sky buffers (if required)
if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky");
// !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render
// and change Forward Clustered in the same way as we have here (but without using subpasses)
RENDER_TIMESTAMP("Setup Sky resolution buffers");
RD::get_singleton()->draw_command_begin_label("Draw Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky resolution buffers");
if (p_render_data->reflection_probe.is_valid()) {
CameraMatrix correction;
correction.set_depth_correction(true);
CameraMatrix projection = correction * p_render_data->cam_projection;
sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time);
sky.update_res_buffers(env, 1, &projection, p_render_data->cam_transform, time);
} else {
sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
sky.update_res_buffers(env, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
}
if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
/*
if (using_separate_specular) {
RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
}
*/
}
if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
}
// transparent pass
RENDER_TIMESTAMP("Render Transparent Pass");
RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_pre_opaque_render(p_render_data, false, false, RID(), RID());
{
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
if (render_buffer) {
RD::get_singleton()->draw_command_begin_label("Render 3D Pass");
} else {
RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass");
}
// opaque pass
RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
RENDER_TIMESTAMP("Render Opaque Subpass");
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
// regular forward for now
Vector<Color> c;
c.push_back(clear_color.to_linear()); // our render buffer
if (render_buffer) {
if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
c.push_back(clear_color.to_linear()); // our resolve buffer
}
if (using_subpass_post_process) {
c.push_back(Color()); // our 2D buffer we're copying into
}
}
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
//multi threaded
thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
} else {
//single threaded
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
}
}
RD::get_singleton()->draw_command_end_label(); //Render Opaque Subpass
if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky Subpass");
RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
if (p_render_data->reflection_probe.is_valid()) {
CameraMatrix correction;
correction.set_depth_correction(true);
CameraMatrix projection = correction * p_render_data->cam_projection;
sky.draw(draw_list, env, framebuffer, 1, &projection, p_render_data->cam_transform, time);
} else {
sky.draw(draw_list, env, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
}
RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
// note, if MSAA is used in 2-subpass approach we should get an automatic resolve here
} else {
// switch to subpass but we do nothing here so basically we skip (though this should trigger resolve with 2-subpass MSAA).
RD::get_singleton()->draw_list_switch_to_next_pass();
}
if (!using_subpass_transparent) {
// We're done with our subpasses so end our container pass
RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
}
// transparent pass
RENDER_TIMESTAMP("Render Transparent Subpass");
RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass");
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
if (using_subpass_transparent) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
//multi threaded
thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
RD::get_singleton()->draw_list_switch_to_next_pass_split(thread_draw_lists.size(), thread_draw_lists.ptr());
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
} else {
//single threaded
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass();
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
}
RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
// note if we are using MSAA we should get an automatic resolve through our subpass configuration.
// blit to tonemap
if (render_buffer && using_subpass_post_process) {
_post_process_subpass(render_buffer->color, framebuffer, p_render_data);
}
RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass
RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
} else {
framebuffer = render_buffer->color_fbs[FB_CONFIG_ONE_PASS];
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
//multi threaded
thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params);
RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
} else {
//single threaded
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
_render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL);
}
RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass
}
}
RD::get_singleton()->draw_command_end_label();
if (render_buffer && !using_subpass_post_process) {
RD::get_singleton()->draw_command_begin_label("Post process pass");
RD::get_singleton()->draw_command_begin_label("Resolve");
// If we need extra effects we do this in its own pass
RENDER_TIMESTAMP("Tonemap");
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
_render_buffers_post_process_and_tonemap(p_render_data);
RD::get_singleton()->draw_command_end_label(); // Post process pass
}
RD::get_singleton()->draw_command_end_label();
if (render_buffer) {
_disable_clear_request(p_render_data);
}
}
/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
@ -635,7 +877,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
_fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
_fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size);
{
//regular forward for now
@ -713,7 +955,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
_fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@ -754,7 +996,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
_fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@ -827,7 +1069,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
_fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
_fill_element_info(RENDER_LIST_SECONDARY);
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
@ -1413,9 +1655,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
// !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer?
void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
@ -1669,7 +1909,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_index_array_rd = index_array_rd;
}
RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass);
if (pipeline_rd != prev_pipeline_rd) {
// checking with prev shader does not make so much sense, as

View file

@ -92,6 +92,18 @@ protected:
/* Render Buffer */
// We can have:
// - 4 subpasses combining the full render cycle
// - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
// - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer)
enum RenderBufferMobileFramebufferConfigType {
FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass
FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass
FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass
FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass
FB_CONFIG_MAX
};
struct RenderBufferDataForwardMobile : public RenderBufferData {
RID color;
RID depth;
@ -104,12 +116,12 @@ protected:
RID depth_msaa;
// RID normal_roughness_buffer_msaa;
RID color_fb;
RID color_fbs[FB_CONFIG_MAX];
int width, height;
uint32_t view_count;
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardMobile();
};
@ -152,6 +164,7 @@ protected:
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t barrier = RD::BARRIER_MASK_ALL;
uint32_t subpass = 0;
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
@ -195,7 +208,7 @@ protected:
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
// void _update_instance_data_buffer(RenderListType p_render_list);
static RenderForwardMobile *singleton;
@ -576,6 +589,8 @@ protected:
void _update_shader_quality_settings() override;
public:
virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override;
static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);

View file

@ -679,10 +679,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
for (int i = 0; i < atlas->count; i++) {
atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format());
for (int j = 0; j < 6; j++) {
Vector<RID> fb;
fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
fb.push_back(atlas->depth_buffer);
atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer);
}
}
@ -728,6 +725,13 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
return true;
}
RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
Vector<RID> fb;
fb.push_back(p_color);
fb.push_back(p_depth);
return RD::get_singleton()->framebuffer_create(fb);
}
bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
@ -1996,6 +2000,75 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
storage->render_target_disable_clear_request(rb->render_target);
}
void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) {
RD::get_singleton()->draw_command_begin_label("Post Process Subpass");
RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(!rb);
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
bool can_use_effects = rb->width >= 8 && rb->height >= 8;
RENDER_TIMESTAMP("Tonemap");
RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
EffectsRD::TonemapSettings tonemap;
if (env) {
tonemap.tonemap_mode = env->tone_mapper;
tonemap.exposure = env->exposure;
tonemap.white = env->white;
}
// We don't support glow or auto exposure here, if they are needed, don't use subpasses!
// The problem is that we need to use the result so far and process them before we can
// apply this to our results.
if (can_use_effects && env && env->glow_enabled) {
ERR_FAIL_MSG("Glow is not supported when using subpasses.");
}
if (can_use_effects && env && env->auto_exposure) {
ERR_FAIL_MSG("Glow is not supported when using subpasses.");
}
tonemap.use_glow = false;
tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
tonemap.use_auto_exposure = false;
tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
if (can_use_effects && env) {
tonemap.use_bcs = env->adjustments_enabled;
tonemap.brightness = env->adjustments_brightness;
tonemap.contrast = env->adjustments_contrast;
tonemap.saturation = env->adjustments_saturation;
if (env->adjustments_enabled && env->color_correction.is_valid()) {
tonemap.use_color_correction = true;
tonemap.use_1d_color_correction = env->use_1d_color_correction;
tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction);
}
}
tonemap.use_debanding = rb->use_debanding;
tonemap.texture_size = Vector2i(rb->width, rb->height);
tonemap.view_count = p_render_data->view_count;
storage->get_effects()->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap);
RD::get_singleton()->draw_command_end_label();
}
void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(!rb);
storage->render_target_disable_clear_request(rb->render_target);
}
void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
EffectsRD *effects = storage->get_effects();
@ -2283,12 +2356,11 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
tf.width = rb->width;
tf.height = rb->height;
tf.array_layers = rb->view_count; // create a layer for every view
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
} else {
tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
}
tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
@ -2326,7 +2398,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count);
}
rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count);
RID target_texture = storage->render_target_get_rd_texture(rb->render_target);
rb->data->configure(rb->texture, rb->depth_texture, target_texture, p_width, p_height, p_msaa, p_view_count);
if (is_clustered_enabled()) {
rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
@ -3846,9 +3919,28 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
_render_scene(&render_data, clear_color);
if (p_render_buffers.is_valid()) {
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
/*
_debug_draw_cluster(p_render_buffers);
RENDER_TIMESTAMP("Tonemap");
_render_buffers_post_process_and_tonemap(&render_data);
*/
_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
}
}
}
void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) {
if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
RS::ViewportDebugDraw dd = get_debug_draw_mode();
if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
switch (debug_draw) {
switch (dd) {
case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
break;
@ -3864,17 +3956,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
default: {
}
}
if (current_cluster_builder != nullptr) {
current_cluster_builder->debug(elem_type);
}
}
RENDER_TIMESTAMP("Tonemap");
_render_buffers_post_process_and_tonemap(&render_data);
_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
current_cluster_builder->debug(elem_type);
}
}
}

View file

@ -95,7 +95,7 @@ protected:
double time_step = 0;
struct RenderBufferData {
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
virtual ~RenderBufferData() {}
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
@ -117,6 +117,7 @@ protected:
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
void _debug_draw_cluster(RID p_render_buffers);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
@ -133,6 +134,10 @@ protected:
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer);
void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data);
void _disable_clear_request(const RenderDataRD *p_render_data);
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
PagedArray<GeometryInstance *> cull_argument; //need this to exist
@ -146,7 +151,7 @@ protected:
} else {
return nullptr;
}
}
};
//used for mobile renderer mostly
@ -524,7 +529,6 @@ private:
void _allocate_luminance_textures(RenderBuffers *rb);
void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
/* Cluster */
@ -923,6 +927,12 @@ public:
virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override;
virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override;
bool camera_effects_uses_dof(RID p_camera_effects) {
CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0;
}
virtual RID light_instance_create(RID p_light) override;
virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
@ -1065,6 +1075,7 @@ public:
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
uint32_t reflection_probe_instance_get_resolution(RID p_instance);

View file

@ -283,7 +283,7 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_
RD::DrawListID draw_list = p_list;
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format));
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass()));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
if (p_uniform_set.is_valid()) { //material may not have uniform set
@ -1467,6 +1467,179 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
RD::get_singleton()->draw_list_end();
}
void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
ERR_FAIL_COND(!p_env);
ERR_FAIL_COND(p_view_count == 0);
ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
Sky *sky = get_sky(p_env->sky);
ERR_FAIL_COND(!sky);
SkyMaterialData *material = nullptr;
RID sky_material;
RS::EnvironmentBG background = p_env->background;
if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
ERR_FAIL_COND(!sky);
sky_material = sky_get_material(p_env->sky);
if (sky_material.is_valid()) {
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
if (!material || !material->shader_data->valid) {
material = nullptr;
}
}
if (!material) {
sky_material = sky_shader.default_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
}
}
if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
sky_material = sky_scene_state.fog_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
}
ERR_FAIL_COND(!material);
SkyShaderData *shader_data = material->shader_data;
ERR_FAIL_COND(!shader_data);
Basis sky_transform = p_env->sky_orientation;
sky_transform.invert();
float multiplier = p_env->bg_energy;
float custom_fov = p_env->sky_custom_fov;
// Camera
CameraMatrix camera;
uint32_t view_count = p_view_count;
const CameraMatrix *projections = p_projections;
if (custom_fov) {
// With custom fov we don't support stereo...
float near_plane = p_projections[0].get_z_near();
float far_plane = p_projections[0].get_z_far();
float aspect = p_projections[0].get_aspect();
camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
view_count = 1;
projections = &camera;
}
sky_transform = p_transform.basis * sky_transform;
if (shader_data->uses_quarter_res) {
PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
Vector<Color> clear_colors;
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
_render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
if (shader_data->uses_half_res) {
PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
Vector<Color> clear_colors;
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
_render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
ERR_FAIL_COND(!p_env);
ERR_FAIL_COND(p_view_count == 0);
ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
Sky *sky = get_sky(p_env->sky);
ERR_FAIL_COND(!sky);
SkyMaterialData *material = nullptr;
RID sky_material;
RS::EnvironmentBG background = p_env->background;
if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
ERR_FAIL_COND(!sky);
sky_material = sky_get_material(p_env->sky);
if (sky_material.is_valid()) {
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
if (!material || !material->shader_data->valid) {
material = nullptr;
}
}
if (!material) {
sky_material = sky_shader.default_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
}
}
if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
sky_material = sky_scene_state.fog_material;
material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
}
ERR_FAIL_COND(!material);
SkyShaderData *shader_data = material->shader_data;
ERR_FAIL_COND(!shader_data);
Basis sky_transform = p_env->sky_orientation;
sky_transform.invert();
float multiplier = p_env->bg_energy;
float custom_fov = p_env->sky_custom_fov;
// Camera
CameraMatrix camera;
uint32_t view_count = p_view_count;
const CameraMatrix *projections = p_projections;
if (custom_fov) {
// With custom fov we don't support stereo...
float near_plane = p_projections[0].get_z_near();
float far_plane = p_projections[0].get_z_far();
float aspect = p_projections[0].get_aspect();
camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
view_count = 1;
projections = &camera;
}
sky_transform = p_transform.basis * sky_transform;
PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
RID texture_uniform_set;
if (sky) {
texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
} else {
texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
}
_render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
}
void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) {
if (!p_sky->dirty) {
p_sky->dirty = true;

View file

@ -295,6 +295,8 @@ public:
void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time);
void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();

View file

@ -35,11 +35,15 @@ void main() {
layout(location = 0) in vec2 uv_interp;
#ifdef MULTIVIEW
#ifdef SUBPASS
layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color;
#else
#if MULTIVIEW
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
#endif
#endif
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
#ifdef USE_1D_LUT
@ -291,6 +295,7 @@ vec3 apply_color_correction(vec3 color) {
}
#endif
#ifndef SUBPASS
vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
const float FXAA_REDUCE_MIN = (1.0 / 128.0);
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
@ -346,6 +351,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
return rgbB;
}
}
#endif // !SUBPASS
// From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
@ -360,7 +366,10 @@ vec3 screen_space_dither(vec2 frag_coord) {
}
void main() {
#ifdef MULTIVIEW
#ifdef SUBPASS
// SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer
vec3 color = subpassLoad(input_color).rgb;
#elif MULTIVIEW
vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb;
#else
vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
@ -370,14 +379,16 @@ void main() {
float exposure = params.exposure;
#ifndef SUBPASS
if (params.use_auto_exposure) {
exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey);
}
#endif
color *= exposure;
// Early Tonemap & SRGB Conversion
#ifndef SUBPASS
if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp);
color.rgb = mix(color.rgb, glow, params.glow_intensity);
@ -386,15 +397,19 @@ void main() {
if (params.use_fxaa) {
color = do_fxaa(color, exposure, uv_interp);
}
#endif
if (params.use_debanding) {
// For best results, debanding should be done before tonemapping.
// Otherwise, we're adding noise to an already-quantized image.
color += screen_space_dither(gl_FragCoord.xy);
}
color = apply_tonemapping(color, params.white);
color = linear_to_srgb(color); // regular linear -> SRGB conversion
#ifndef SUBPASS
// Glow
if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
@ -406,6 +421,7 @@ void main() {
color = apply_glow(color, glow);
}
#endif
// Additional effects

View file

@ -739,7 +739,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_UPDATE_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_FROM_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_TO_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT);
BIND_ENUM_CONSTANT(TEXTURE_USAGE_INPUT_ATTACHMENT_BIT);
BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_IDENTITY);
BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ZERO);

View file

@ -422,7 +422,7 @@ public:
TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9),
TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9),
};
enum TextureSwizzle {
@ -1065,6 +1065,7 @@ public:
virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
virtual uint32_t draw_list_get_current_pass() = 0;
virtual DrawListID draw_list_switch_to_next_pass() = 0;
virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0;