From bde6f5eed1cec3639e5c81d1e5ee34ecf3fe7486 Mon Sep 17 00:00:00 2001 From: reduz Date: Thu, 24 Jun 2021 10:58:36 -0300 Subject: Implement Framebuffer Subpass support * Required for better optimizing mobile platforms * Will be used by the Vulkan mobile renderer. --- .../rendering/renderer_rd/pipeline_cache_rd.cpp | 7 ++- servers/rendering/renderer_rd/pipeline_cache_rd.h | 9 +-- servers/rendering/rendering_device.cpp | 72 +++++++++++++++++++--- servers/rendering/rendering_device.h | 30 +++++++-- servers/rendering/rendering_device_binds.h | 28 +++++++++ 5 files changed, 124 insertions(+), 22 deletions(-) (limited to 'servers/rendering') diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index b2b919c40e..22888ddbe5 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -31,20 +31,21 @@ #include "pipeline_cache_rd.h" #include "core/os/memory.h" -RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { +RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass) { RD::PipelineMultisampleState multisample_state_version = multisample_state; - multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id); + multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id, p_render_pass); RD::PipelineRasterizationState raster_state_version = rasterization_state; raster_state_version.wireframe = p_wireframe; - RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags); + RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags, p_render_pass); ERR_FAIL_COND_V(pipeline.is_null(), RID()); versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1)); versions[version_count].framebuffer_id = p_framebuffer_format_id; versions[version_count].vertex_id = p_vertex_format_id; versions[version_count].wireframe = p_wireframe; versions[version_count].pipeline = pipeline; + versions[version_count].render_pass = p_render_pass; version_count++; return pipeline; } diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index b1c8f21ecc..387a8a038f 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -50,6 +50,7 @@ class PipelineCacheRD { struct Version { RD::VertexFormatID vertex_id; RD::FramebufferFormatID framebuffer_id; + uint32_t render_pass; bool wireframe; RID pipeline; }; @@ -57,7 +58,7 @@ class PipelineCacheRD { Version *versions; uint32_t version_count; - RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe); + RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass); void _clear(); @@ -65,7 +66,7 @@ public: void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); void update_shader(RID p_shader); - _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false) { + _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false, uint32_t p_render_pass = 0) { #ifdef DEBUG_ENABLED ERR_FAIL_COND_V_MSG(shader.is_null(), RID(), "Attempted to use an unused shader variant (shader is null),"); @@ -74,13 +75,13 @@ public: spin_lock.lock(); RID result; for (uint32_t i = 0; i < version_count; i++) { - if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe) { + if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe && versions[i].render_pass == p_render_pass) { result = versions[i].pipeline; spin_lock.unlock(); return result; } } - result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe); + result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe, p_render_pass); spin_lock.unlock(); return result; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index ddf2ee9fe3..c52d97a3de 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -98,7 +98,7 @@ RID RenderingDevice::_texture_create_shared_from_slice(const Ref return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_slice_type); } -RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray &p_attachments) { +RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray &p_attachments, uint32_t p_view_count) { Vector attachments; attachments.resize(p_attachments.size()); @@ -107,12 +107,43 @@ RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); attachments.write[i] = af->base; } - return framebuffer_format_create(attachments); + return framebuffer_format_create(attachments, p_view_count); } -RID RenderingDevice::_framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check) { +RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray &p_attachments, const TypedArray &p_passes, uint32_t p_view_count) { + Vector attachments; + attachments.resize(p_attachments.size()); + + for (int i = 0; i < p_attachments.size(); i++) { + Ref af = p_attachments[i]; + ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); + attachments.write[i] = af->base; + } + + Vector passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref pass = p_passes[i]; + ERR_CONTINUE(pass.is_null()); + passes.push_back(pass->base); + } + + return framebuffer_format_create_multipass(attachments, passes, p_view_count); +} + +RID RenderingDevice::_framebuffer_create(const TypedArray &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) { Vector textures = Variant(p_textures); - return framebuffer_create(textures, p_format_check); + return framebuffer_create(textures, p_format_check, p_view_count); +} + +RID RenderingDevice::_framebuffer_create_multipass(const TypedArray &p_textures, const TypedArray &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { + Vector textures = Variant(p_textures); + Vector passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref pass = p_passes[i]; + ERR_CONTINUE(pass.is_null()); + passes.push_back(pass->base); + } + return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count); } RID RenderingDevice::_sampler_create(const Ref &p_state) { @@ -190,7 +221,7 @@ Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } -RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, int p_dynamic_state_flags) { +RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) { PipelineRasterizationState rasterization_state; if (p_rasterization_state.is_valid()) { rasterization_state = p_rasterization_state->base; @@ -221,7 +252,7 @@ RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p } } - return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags); + return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass); } Vector RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray &p_storage_textures) { @@ -242,6 +273,22 @@ Vector RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint3 return split_ids; } +Vector RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { + Vector splits; + splits.resize(p_splits); + + Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw()); + ERR_FAIL_COND_V(err != OK, Vector()); + + Vector split_ids; + split_ids.resize(splits.size()); + for (int i = 0; i < splits.size(); i++) { + split_ids.write[i] = splits[i]; + } + + return split_ids; +} + void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector &p_data, uint32_t p_data_size) { ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size); @@ -269,10 +316,12 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments"), &RenderingDevice::_framebuffer_format_create); + ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1)); + ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1)); ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1)); - ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format"), &RenderingDevice::framebuffer_format_get_texture_samples); - ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID)); + ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format", "render_pass"), &RenderingDevice::framebuffer_format_get_texture_samples, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1)); ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID)); ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format); @@ -299,7 +348,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); - ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags"), &RenderingDevice::_render_pipeline_create, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid); ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader"), &RenderingDevice::compute_pipeline_create); @@ -325,6 +374,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); + ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass); + ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split); + ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false)); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index c13dc01dd7..be7e127491 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -47,6 +47,7 @@ class RDPipelineRasterizationState; class RDPipelineMultisampleState; class RDPipelineDepthStencilState; class RDPipelineColorBlendState; +class RDFramebufferPass; class RenderingDevice : public Object { GDCLASS(RenderingDevice, Object) @@ -517,10 +518,23 @@ public: // This ID is warranted to be unique for the same formats, does not need to be freed virtual FramebufferFormatID framebuffer_format_create(const Vector &p_format, uint32_t p_view_count = 1) = 0; + struct FramebufferPass { + enum { + ATTACHMENT_UNUSED = -1 + }; + Vector color_attachments; + Vector input_attachments; + Vector resolve_attachments; + Vector preserve_attachments; + int32_t depth_attachment = ATTACHMENT_UNUSED; + }; + + virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector &p_attachments, Vector &p_passes, uint32_t p_view_count = 1) = 0; virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0; - virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0; + virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0) = 0; virtual RID framebuffer_create(const Vector &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0; + virtual RID framebuffer_create_multipass(const Vector &p_texture_attachments, Vector &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0; virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0; virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0; @@ -962,7 +976,7 @@ public: }; virtual bool render_pipeline_is_valid(RID p_pipeline) = 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) = 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) = 0; /**************************/ /**** COMPUTE PIPELINE ****/ @@ -1018,6 +1032,9 @@ 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 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; + virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /***********************/ @@ -1134,8 +1151,10 @@ protected: RID _texture_create_shared(const Ref &p_view, RID p_with_texture); RID _texture_create_shared_from_slice(const Ref &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); - FramebufferFormatID _framebuffer_format_create(const TypedArray &p_attachments); - RID _framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check = INVALID_ID); + FramebufferFormatID _framebuffer_format_create(const TypedArray &p_attachments, uint32_t p_view_count); + FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray &p_attachments, const TypedArray &p_passes, uint32_t p_view_count); + RID _framebuffer_create(const TypedArray &p_textures, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); + RID _framebuffer_create_multipass(const TypedArray &p_textures, const TypedArray &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); RID _sampler_create(const Ref &p_state); VertexFormatID _vertex_format_create(const TypedArray &p_vertex_formats); RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray &p_src_buffers); @@ -1146,11 +1165,12 @@ protected: Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); - RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, int p_dynamic_state_flags = 0); + RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref &p_rasterization_state, const Ref &p_multisample_state, const Ref &p_depth_stencil_state, const Ref &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0); Vector _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray &p_storage_textures = TypedArray()); void _draw_list_set_push_constant(DrawListID p_list, const Vector &p_data, uint32_t p_data_size); void _compute_list_set_push_constant(ComputeListID p_list, const Vector &p_data, uint32_t p_data_size); + Vector _draw_list_switch_to_next_pass_split(uint32_t p_splits); }; VARIANT_ENUM_CAST(RenderingDevice::ShaderStage) diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 912674e309..dc59568ce9 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -128,6 +128,34 @@ protected: } }; +class RDFramebufferPass : public RefCounted { + GDCLASS(RDFramebufferPass, RefCounted) + friend class RenderingDevice; + + RD::FramebufferPass base; + +public: + RD_SETGET(PackedInt32Array, color_attachments) + RD_SETGET(PackedInt32Array, input_attachments) + RD_SETGET(PackedInt32Array, resolve_attachments) + RD_SETGET(PackedInt32Array, preserve_attachments) + RD_SETGET(int32_t, depth_attachment) +protected: + enum { + ATTACHMENT_UNUSED = -1 + }; + + static void _bind_methods() { + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, color_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, input_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, resolve_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, preserve_attachments); + RD_BIND(Variant::INT, RDFramebufferPass, depth_attachment); + + BIND_CONSTANT(ATTACHMENT_UNUSED); + } +}; + class RDSamplerState : public RefCounted { GDCLASS(RDSamplerState, RefCounted) friend class RenderingDevice; -- cgit v1.2.3