From 3ca0b5f49ee8b34a68827970e093c10984a85ba5 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Thu, 26 Oct 2023 12:10:38 +1100 Subject: [PATCH] Add MSAA and scaling support to GLES3 --- drivers/gles3/rasterizer_scene_gles3.cpp | 76 +++++- drivers/gles3/rasterizer_scene_gles3.h | 3 +- .../storage/render_scene_buffers_gles3.cpp | 232 +++++++++++++++++- .../storage/render_scene_buffers_gles3.h | 47 +++- drivers/gles3/storage/texture_storage.cpp | 40 ++- drivers/gles3/storage/texture_storage.h | 9 +- 6 files changed, 372 insertions(+), 35 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1f10f4b3539e71..1c011b865f3cf7 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2233,9 +2233,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ bool fb_cleared = false; - Size2i screen_size; - screen_size.x = rb->width; - screen_size.y = rb->height; + Size2i screen_size = rb->internal_size; bool use_wireframe = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME; @@ -2355,8 +2353,10 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ } } - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - glViewport(0, 0, rb->width, rb->height); + GLuint fbo = rb->get_render_fbo(); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glViewport(0, 0, rb->internal_size.x, rb->internal_size.y); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); @@ -2458,8 +2458,11 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ } if (scene_state.used_screen_texture || scene_state.used_depth_texture) { - texture_storage->copy_scene_to_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture); - glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + // TODO *must fix* need to change this if we're using scaled buffers, we need to source our back buffer from our render scene buffers + + texture_storage->copy_scene_to_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture); // note, badly names, this just allocates! + + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rt->backbuffer_fbo); if (scene_state.used_screen_texture) { @@ -2476,7 +2479,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6); glBindTexture(GL_TEXTURE_2D, rt->backbuffer_depth); } - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); } RENDER_TIMESTAMP("Render 3D Transparent Pass"); @@ -2493,12 +2496,58 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ } if (rb.is_valid()) { - _render_buffers_debug_draw(rb, p_shadow_atlas); + _render_buffers_debug_draw(rb, p_shadow_atlas, fbo); } glDisable(GL_BLEND); + + _render_post_processing(&render_data); + texture_storage->render_target_disable_clear_request(rb->render_target); } +void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_render_data) { + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + Ref rb = p_render_data->render_buffers; + ERR_FAIL_COND(rb.is_null()); + + GLuint fbo_3d = rb->get_render_fbo(); + GLuint fbo_rt = texture_storage->render_target_get_fbo(rb->get_render_target()); // TODO if MSAA 2D is enabled, we should be getting that FBO here + + if (fbo_3d == fbo_rt) { + // We're already rendering into the render target + return; + } + + RS::ViewportScaling3DMode scaling_mode = rb->get_scaling_3d_mode(); + RS::ViewportMSAA msaa3d = rb->get_msaa_3d(); + Size2i internal_size = rb->get_internal_size(); + Size2i target_size = rb->get_target_size(); + + // Resolve, post-process, scale if needed. + if (msaa3d != RS::VIEWPORT_MSAA_DISABLED) { + // We can use blit to copy things over + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_3d); + + if (scaling_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF) { + // We can't combine resolve and scaling, so resolve into our internal buffer + GLuint fbo_int = rb->get_internal_fbo(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_int); + fbo_3d = fbo_int; // use this as our input for upscaling... + } else { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt); + } + glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + if (scaling_mode == RS::VIEWPORT_SCALING_3D_MODE_BILINEAR) { + // TODO If we have glow or other post processing, we upscale only depth here, post processing will also do scaling. + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_3d); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt); + glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } +} + template void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) { GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton(); @@ -3116,7 +3165,7 @@ Ref RasterizerSceneGLES3::render_buffers_create() { return rb; } -void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas) { +void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, GLuint p_fbo) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton(); GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton(); @@ -3193,8 +3242,11 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Reffbo); - glViewport(0, 0, rt->size.width, rt->size.height); + + // Set back to FBO + glBindFramebuffer(GL_FRAMEBUFFER, p_fbo); + Size2i size = p_render_buffers->get_internal_size(); + glViewport(0, 0, size.width, size.height); glBindTexture(GL_TEXTURE_2D, shadow_atlas_texture); copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5))); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index da60d571bfbf29..cdc0790bbbb5fb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -518,6 +518,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false); void _render_shadows(const RenderDataGLES3 *p_render_data); void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, RenderingMethod::RenderInfo *p_render_info = nullptr); + void _render_post_processing(const RenderDataGLES3 *p_render_data); template _FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false); @@ -530,7 +531,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { float screen_space_roughness_limiter_amount = 0.25; float screen_space_roughness_limiter_limit = 0.18; - void _render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas); + void _render_buffers_debug_draw(Ref p_render_buffers, RID p_shadow_atlas, GLuint p_fbo); /* Camera Attributes */ diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 829574cae04a99..72c19b3ddc8bfc 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -31,30 +31,248 @@ #ifdef GLES3_ENABLED #include "render_scene_buffers_gles3.h" +#include "config.h" #include "texture_storage.h" +#include "utilities.h" RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() { free_render_buffer_data(); } void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p_config) { - //internal_size.x = p_config->get_internal_size().x; // ignore for now - //internal_size.y = p_config->get_internal_size().y; - width = p_config->get_target_size().x; - height = p_config->get_target_size().y; - //scaling_3d_mode = p_config->get_scaling_3d_mode() + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + + free_render_buffer_data(); + + internal_size = p_config->get_internal_size(); + target_size = p_config->get_target_size(); + scaling_3d_mode = p_config->get_scaling_3d_mode(); //fsr_sharpness = p_config->get_fsr_sharpness(); //texture_mipmap_bias = p_config->get_texture_mipmap_bias(); render_target = p_config->get_render_target(); - //msaa = p_config->get_msaa_3d(); + msaa3d.mode = p_config->get_msaa_3d(); //screen_space_aa = p_config->get_screen_space_aa(); //use_debanding = p_config->get_use_debanding(); view_count = p_config->get_view_count(); - free_render_buffer_data(); + if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size == target_size) { + // If size matches, we won't use scaling. + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; + target_size = internal_size; + } + + if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR) { + // We only support bilinear scaling atm. + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR; + } + + if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x > 0 && internal_size.y > 0) { + // Setup our internal buffer for MSAA + const GLsizei samples[] = { 1, 2, 4, 8 }; + msaa3d.samples = samples[msaa3d.mode]; + + // Note: seeing our render target and scene buffers are separate, we've made our life hard + // but a future improvement would be that is 2D MSAA is enabled and set to the same setting. + // we use our 2D MSAA color buffer here and skip a copy + + bool is_transparent = texture_storage->render_target_get_transparent(render_target); + GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2; + + bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported; + GLenum texture_target = use_multiview ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_MULTISAMPLE; + + glGenFramebuffers(1, &msaa3d.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo); + + glGenTextures(1, &msaa3d.color); + glBindTexture(texture_target, msaa3d.color); + + if (use_multiview) { + glTexImage3DMultisample(texture_target, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE); + } else { + glTexImage2DMultisample(texture_target, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, GL_TRUE); + } + + glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * 4, "Render target color texture"); + +#ifndef IOS_ENABLED + if (use_multiview) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa3d.color, 0, 0, view_count); + } else { +#else + { +#endif + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, msaa3d.color, 0); + } + + glGenTextures(1, &msaa3d.depth); + glBindTexture(texture_target, msaa3d.depth); + + if (use_multiview) { + glTexImage3DMultisample(texture_target, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE); + } else { + glTexImage2DMultisample(texture_target, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, GL_TRUE); + } + + glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * 3 * 4, "Render target depth texture"); + +#ifndef IOS_ENABLED + if (use_multiview) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, msaa3d.depth, 0, 0, view_count); + } else { +#else + { +#endif + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, msaa3d.depth, 0); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + _clear_msaa3d_buffers(); + WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status)); + } + + glBindTexture(texture_target, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size.x > 0 && internal_size.y > 0) { // upscaling or glow (later) + // Setup our internal buffer for normal + bool is_transparent = texture_storage->render_target_get_transparent(render_target); + GLuint color_internal_format = is_transparent ? GL_RGBA8 : GL_RGB10_A2; + GLuint color_format = GL_RGBA; + GLuint color_type = is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV; + + bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported; + GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; + + glGenFramebuffers(1, &internal3d.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, internal3d.fbo); + + glGenTextures(1, &internal3d.color); + glBindTexture(texture_target, internal3d.color); + + if (use_multiview) { + glTexImage3D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, view_count, 0, color_format, color_type, nullptr); + } else { + glTexImage2D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, 0, color_format, color_type, nullptr); + } + + glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * 4, "Render target color texture"); + +#ifndef IOS_ENABLED + if (use_multiview) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, 0, view_count); + } else { +#else + { +#endif + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, internal3d.color, 0); + } + + glGenTextures(1, &internal3d.depth); + glBindTexture(texture_target, internal3d.depth); + + if (use_multiview) { + glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + } else { + glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + } + + glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * 3, "Render target depth texture"); + +#ifndef IOS_ENABLED + if (use_multiview) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, internal3d.depth, 0, 0, view_count); + } else { +#else + { +#endif + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, internal3d.depth, 0); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + _clear_intermediate_buffers(); + WARN_PRINT("Could not create 3D buffers, status: " + texture_storage->get_framebuffer_error(status)); + } + + glBindTexture(texture_target, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } +} + +void RenderSceneBuffersGLES3::_clear_msaa3d_buffers() { + if (msaa3d.fbo) { + glDeleteFramebuffers(1, &msaa3d.fbo); + msaa3d.fbo = 0; + } + + if (msaa3d.color != 0) { + GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.color); + msaa3d.color = 0; + } + + if (msaa3d.depth != 0) { + GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.depth); + msaa3d.depth = 0; + } +} + +void RenderSceneBuffersGLES3::_clear_intermediate_buffers() { + if (internal3d.fbo) { + glDeleteFramebuffers(1, &internal3d.fbo); + internal3d.fbo = 0; + } + + if (internal3d.color != 0) { + GLES3::Utilities::get_singleton()->texture_free_data(internal3d.color); + internal3d.color = 0; + } + + if (internal3d.depth != 0) { + GLES3::Utilities::get_singleton()->texture_free_data(internal3d.depth); + internal3d.depth = 0; + } } void RenderSceneBuffersGLES3::free_render_buffer_data() { + _clear_msaa3d_buffers(); + _clear_intermediate_buffers(); +} + +GLuint RenderSceneBuffersGLES3::get_render_fbo() const { + if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && msaa3d.fbo != 0) { + // MSAA is enabled, render to our MSAA buffer + return msaa3d.fbo; + } else if (internal3d.fbo != 0) { + // We have an internal buffer, render to our internal buffer! + return internal3d.fbo; + } else { + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + + return texture_storage->render_target_get_fbo(render_target); + } } #endif // GLES3_ENABLED diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h index 543e1aeb152beb..4f6fb435d84c05 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.h +++ b/drivers/gles3/storage/render_scene_buffers_gles3.h @@ -41,21 +41,32 @@ class RenderSceneBuffersGLES3 : public RenderSceneBuffers { GDCLASS(RenderSceneBuffersGLES3, RenderSceneBuffers); public: - // Original implementation, need to investigate which ones we'll keep like this and what we'll change... - - int internal_width = 0; - int internal_height = 0; - int width = 0; - int height = 0; + Size2i internal_size; // Size of the buffer we render 3D content to. + Size2i target_size; // Size of our output buffer (render target). + RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF; //float fsr_sharpness = 0.2f; - RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; + //bool use_taa = false; //bool use_debanding = false; uint32_t view_count = 1; RID render_target; - //built-in textures used for ping pong image processing and blurring + struct RTMSAA3D { + RS::ViewportMSAA mode = RS::VIEWPORT_MSAA_DISABLED; + GLsizei samples = 1; + GLuint color = 0; + GLuint depth = 0; + GLuint fbo = 0; + } msaa3d; // MSAA buffers used to render 3D + + struct RBINTERNAL3D { + GLuint color = 0; + GLuint depth = 0; + GLuint fbo = 0; + } internal3d; // buffers used to either render 3D (scaled/post) or to resolve MSAA into + + // Built-in textures used for ping pong image processing and blurring. struct Blur { RID texture; @@ -72,6 +83,9 @@ class RenderSceneBuffersGLES3 : public RenderSceneBuffers { Blur blur[2]; //the second one starts from the first mipmap private: + void _clear_msaa3d_buffers(); + void _clear_intermediate_buffers(); + public: virtual ~RenderSceneBuffersGLES3(); virtual void configure(const RenderSceneBuffersConfiguration *p_config) override; @@ -81,6 +95,23 @@ class RenderSceneBuffersGLES3 : public RenderSceneBuffers { virtual void set_use_debanding(bool p_use_debanding) override{}; void free_render_buffer_data(); + + GLuint get_render_fbo() const; + GLuint get_msaa3d_fbo() const { return msaa3d.fbo; } + GLuint get_internal_fbo() const { return internal3d.fbo; } + + // Getters + + _FORCE_INLINE_ RID get_render_target() const { return render_target; } + _FORCE_INLINE_ uint32_t get_view_count() const { return view_count; } + _FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; } + _FORCE_INLINE_ Size2i get_target_size() const { return target_size; } + _FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; } + //_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; } + _FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa3d.mode; } + //_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; } + //_FORCE_INLINE_ bool get_use_taa() const { return use_taa; } + //_FORCE_INLINE_ bool get_use_debanding() const { return use_debanding; } }; #endif // GLES3_ENABLED diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index b7b62d78a0d674..632ee6a6d066f5 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1690,6 +1690,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { glColorMask(1, 1, 1, 1); glDepthMask(GL_FALSE); + if (rt->view_count == 1 && rt->msaa_2d.mode != RS::VIEWPORT_MSAA_DISABLED) { + /* MSAA 2D FBO */ + + // We don't support 2D in multiview, + + // Texture *texture; + // GLenum texture_target = GL_TEXTURE_2D; + } + { Texture *texture; bool use_multiview = rt->view_count > 1 && config->multiview_supported; @@ -1732,7 +1741,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { #else { #endif - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, rt->color, 0); } // depth @@ -1765,7 +1774,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { #else { #endif - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, rt->depth, 0); } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -1935,7 +1944,7 @@ void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const boo } } void TextureStorage::_clear_render_target(RenderTarget *rt) { - // there is nothing to clear when DIRECT_TO_SCREEN is used + // there is nothing else to clear when DIRECT_TO_SCREEN is used if (rt->direct_to_screen) { return; } @@ -1955,6 +1964,16 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) { rt->fbo = 0; } + if (rt->msaa_2d.fbo) { + glDeleteFramebuffers(1, &rt->msaa_2d.fbo); + rt->msaa_2d.fbo = 0; + } + + if (rt->msaa_2d.color != 0) { + GLES3::Utilities::get_singleton()->texture_free_data(rt->msaa_2d.color); + rt->msaa_2d.color = 0; + } + if (rt->overridden.color.is_null()) { if (rt->texture.is_valid()) { Texture *tex = get_texture(rt->texture); @@ -2198,6 +2217,7 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo _clear_render_target(rt); rt->direct_to_screen = p_direct_to_screen; if (rt->direct_to_screen) { + rt->msaa_2d.mode = RS::VIEWPORT_MSAA_DISABLED; rt->overridden.color = RID(); rt->overridden.depth = RID(); rt->overridden.velocity = RID(); @@ -2229,14 +2249,15 @@ void TextureStorage::render_target_clear_used(RID p_render_target) { void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); - if (p_msaa == rt->msaa) { + ERR_FAIL_COND(rt->direct_to_screen); + if (p_msaa == rt->msaa_2d.mode) { return; } WARN_PRINT("2D MSAA is not yet supported for GLES3."); _clear_render_target(rt); - rt->msaa = p_msaa; + rt->msaa_2d.mode = p_msaa; _update_render_target(rt); } @@ -2244,7 +2265,7 @@ RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) con RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL_V(rt, RS::VIEWPORT_MSAA_DISABLED); - return rt->msaa; + return rt->msaa_2d.mode; } void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { @@ -2284,6 +2305,13 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); } +GLuint TextureStorage::render_target_get_fbo(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_NULL_V(rt, 0); + + return rt->fbo; +} + void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 87a07ebb36824b..51c516934bc27d 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -364,7 +364,12 @@ struct RenderTarget { bool direct_to_screen = false; bool used_in_frame = false; - RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; + + struct RTmsaa2d { + RS::ViewportMSAA mode = RS::VIEWPORT_MSAA_DISABLED; + GLuint color = 0; + GLuint fbo = 0; + } msaa_2d; struct RTOverridden { bool is_overridden = false; @@ -633,6 +638,8 @@ class TextureStorage : public RendererTextureStorage { void render_target_disable_clear_request(RID p_render_target) override; void render_target_do_clear_request(RID p_render_target) override; + GLuint render_target_get_fbo(RID p_render_target) const; + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override; virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override; GLuint render_target_get_sdf_texture(RID p_render_target);