1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-22 15:06:45 +00:00

Implement Framebuffer Subpass support

* Required for better optimizing mobile platforms
* Will be used by the Vulkan mobile renderer.
This commit is contained in:
reduz
2021-06-24 10:58:36 -03:00
parent 8ccadfabf2
commit bde6f5eed1
10 changed files with 870 additions and 256 deletions

View File

@@ -234,12 +234,87 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct FramebufferFormatKey {
Vector<AttachmentFormat> attachments;
Vector<FramebufferPass> passes;
uint32_t view_count = 1;
bool operator<(const FramebufferFormatKey &p_key) const {
if (view_count != p_key.view_count) {
return view_count < p_key.view_count;
}
uint32_t pass_size = passes.size();
uint32_t key_pass_size = p_key.passes.size();
if (pass_size != key_pass_size) {
return pass_size < key_pass_size;
}
const FramebufferPass *pass_ptr = passes.ptr();
const FramebufferPass *key_pass_ptr = p_key.passes.ptr();
for (uint32_t i = 0; i < pass_size; i++) {
{ //compare color attachments
uint32_t attachment_size = pass_ptr[i].color_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].color_attachments.size();
if (attachment_size != key_attachment_size) {
return attachment_size < key_attachment_size;
}
const int32_t *pass_attachment_ptr = pass_ptr[i].color_attachments.ptr();
const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].color_attachments.ptr();
for (uint32_t j = 0; j < attachment_size; j++) {
if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
}
}
}
{ //compare input attachments
uint32_t attachment_size = pass_ptr[i].input_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].input_attachments.size();
if (attachment_size != key_attachment_size) {
return attachment_size < key_attachment_size;
}
const int32_t *pass_attachment_ptr = pass_ptr[i].input_attachments.ptr();
const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].input_attachments.ptr();
for (uint32_t j = 0; j < attachment_size; j++) {
if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
}
}
}
{ //compare resolve attachments
uint32_t attachment_size = pass_ptr[i].resolve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].resolve_attachments.size();
if (attachment_size != key_attachment_size) {
return attachment_size < key_attachment_size;
}
const int32_t *pass_attachment_ptr = pass_ptr[i].resolve_attachments.ptr();
const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].resolve_attachments.ptr();
for (uint32_t j = 0; j < attachment_size; j++) {
if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
}
}
}
{ //compare preserve attachments
uint32_t attachment_size = pass_ptr[i].preserve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].preserve_attachments.size();
if (attachment_size != key_attachment_size) {
return attachment_size < key_attachment_size;
}
const int32_t *pass_attachment_ptr = pass_ptr[i].preserve_attachments.ptr();
const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].preserve_attachments.ptr();
for (uint32_t j = 0; j < attachment_size; j++) {
if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) {
return pass_attachment_ptr[j] < key_pass_attachment_ptr[j];
}
}
}
if (pass_ptr[i].depth_attachment != key_pass_ptr[i].depth_attachment) {
return pass_ptr[i].depth_attachment < key_pass_ptr[i].depth_attachment;
}
}
int as = attachments.size();
int bs = p_key.attachments.size();
if (as != bs) {
@@ -266,16 +341,14 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
};
VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = nullptr, uint32_t p_view_count = 1);
VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count = 1, Vector<TextureSamples> *r_samples = nullptr);
// This is a cache and it's never freed, it ensures
// IDs for a given format are always unique.
Map<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache;
struct FramebufferFormat {
const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E;
VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec)
int color_attachments = 0; //used for pipeline validation
TextureSamples samples;
Vector<TextureSamples> pass_samples;
uint32_t view_count = 1; // number of views
};
@@ -289,6 +362,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
InitialAction initial_depth_action;
FinalAction final_depth_action;
uint32_t view_count;
bool operator<(const VersionKey &p_key) const {
if (initial_color_action == p_key.initial_color_action) {
if (final_color_action == p_key.final_color_action) {
@@ -316,6 +390,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct Version {
VkFramebuffer framebuffer = VK_NULL_HANDLE;
VkRenderPass render_pass = VK_NULL_HANDLE; //this one is owned
uint32_t subpass_count = 1;
};
Map<VersionKey, Version> framebuffers;
@@ -536,7 +611,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
};
uint32_t vertex_input_mask = 0; //inputs used, this is mostly for validation
int fragment_outputs = 0;
uint32_t fragment_output_mask = 0;
struct PushConstant {
uint32_t push_constant_size = 0;
@@ -680,6 +755,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
#ifdef DEBUG_ENABLED
struct Validation {
FramebufferFormatID framebuffer_format = 0;
uint32_t render_pass = 0;
uint32_t dynamic_state = 0;
VertexFormatID vertex_format = 0;
bool uses_restart_indices = false;
@@ -735,6 +811,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct DrawList {
VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer.
Rect2i viewport;
bool viewport_set = false;
struct SetState {
uint32_t pipeline_expected_format = 0;
@@ -758,7 +835,6 @@ class RenderingDeviceVulkan : public RenderingDevice {
#ifdef DEBUG_ENABLED
struct Validation {
bool active = true; // Means command buffer was not closed, so you can keep adding things.
FramebufferFormatID framebuffer_format = INVALID_ID;
// Actual render pass values.
uint32_t dynamic_state = 0;
VertexFormatID vertex_format = INVALID_ID;
@@ -794,7 +870,15 @@ class RenderingDeviceVulkan : public RenderingDevice {
};
DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split.
uint32_t draw_list_subpass_count = 0;
uint32_t draw_list_count = 0;
VkRenderPass draw_list_render_pass;
VkFramebuffer draw_list_vkframebuffer;
#ifdef DEBUG_ENABLED
FramebufferFormatID draw_list_framebuffer_format = INVALID_ID;
#endif
uint32_t draw_list_current_subpass = 0;
bool draw_list_split = false;
Vector<RID> draw_list_bound_textures;
Vector<RID> draw_list_storage_textures;
@@ -802,10 +886,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool draw_list_unbind_depth_textures = false;
void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count);
Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, uint32_t p_post_barrier);
Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
void _draw_list_free(Rect2i *r_last_viewport = nullptr);
/**********************/
/**** COMPUTE LIST ****/
@@ -951,10 +1037,12 @@ public:
/*********************/
virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
@@ -1005,7 +1093,7 @@ public:
/**** RENDER PIPELINE ****/
/*************************/
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0);
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0);
virtual bool render_pipeline_is_valid(RID p_pipeline);
/**************************/
@@ -1044,6 +1132,9 @@ public:
virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
virtual void draw_list_disable_scissor(DrawListID p_list);
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);
virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL);
/***********************/