Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 3D MSAA and scaling support to GLES3 #83976

Merged
merged 1 commit into from Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/classes/ProjectSettings.xml
Expand Up @@ -2778,9 +2778,11 @@
</member>
<member name="xr/openxr/foveation_dynamic" type="bool" setter="" getter="" default="false">
If true and foveation is supported, will automatically adjust foveation level based on framerate up to the level set on [member xr/openxr/foveation_level].
[b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="xr/openxr/foveation_level" type="int" setter="" getter="" default="&quot;0&quot;">
Applied foveation level if supported: 0 = off, 1 = low, 2 = medium, 3 = high.
[b]Note:[/b] Only works on compatibility renderer.
</member>
<member name="xr/openxr/reference_space" type="int" setter="" getter="" default="&quot;1&quot;">
Specify the default reference space.
Expand Down
178 changes: 150 additions & 28 deletions drivers/gles3/rasterizer_scene_gles3.cpp
Expand Up @@ -2238,9 +2238,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &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;

Expand Down Expand Up @@ -2360,8 +2358,10 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &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);
Expand Down Expand Up @@ -2463,25 +2463,48 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &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);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rt->backbuffer_fbo);
if (scene_state.used_screen_texture) {
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
0, 0, rt->size.x, rt->size.y,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
}
if (scene_state.used_depth_texture) {
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
0, 0, rt->size.x, rt->size.y,
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
glBindTexture(GL_TEXTURE_2D, rt->backbuffer_depth);
}
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
Size2i size;
GLuint backbuffer_fbo = 0;
GLuint backbuffer = 0;
GLuint backbuffer_depth = 0;

if (rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_OFF) {
texture_storage->check_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture); // note, badly names, this just allocates!

size = rt->size;
backbuffer_fbo = rt->backbuffer_fbo;
backbuffer = rt->backbuffer;
backbuffer_depth = rt->backbuffer_depth;
} else {
rb->check_backbuffer(scene_state.used_screen_texture, scene_state.used_depth_texture);
size = rb->get_internal_size();
backbuffer_fbo = rb->get_backbuffer_fbo();
backbuffer = rb->get_backbuffer();
backbuffer_depth = rb->get_backbuffer_depth();
}

if (backbuffer_fbo != 0) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backbuffer_fbo);
if (scene_state.used_screen_texture) {
glBlitFramebuffer(0, 0, size.x, size.y,
0, 0, size.x, size.y,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
glBindTexture(GL_TEXTURE_2D, backbuffer);
}
if (scene_state.used_depth_texture) {
glBlitFramebuffer(0, 0, size.x, size.y,
0, 0, size.x, size.y,
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
}
}

// Bound framebuffer may have changed, so change it back
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}

RENDER_TIMESTAMP("Render 3D Transparent Pass");
Expand All @@ -2498,14 +2521,110 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &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);

glActiveTexture(GL_TEXTURE0);
}

void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_render_data) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
Ref<RenderSceneBuffersGLES3> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());

RID render_target = rb->get_render_target();
Size2i internal_size = rb->get_internal_size();
Size2i target_size = rb->get_target_size();
uint32_t view_count = rb->get_view_count();

// bool msaa2d_needs_resolve = texture_storage->render_target_get_msaa(render_target) != RS::VIEWPORT_MSAA_DISABLED && !GLES3::Config::get_singleton()->rt_msaa_supported;
bool msaa3d_needs_resolve = rb->get_msaa_needs_resolve();
GLuint fbo_msaa_3d = rb->get_msaa3d_fbo();
GLuint fbo_int = rb->get_internal_fbo();
GLuint fbo_rt = texture_storage->render_target_get_fbo(render_target); // TODO if MSAA 2D is enabled and we're not using rt_msaa, get 2D render target here.

if (view_count == 1) {
// Resolve if needed.
if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
// We can use blit to copy things over
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_msaa_3d);

if (fbo_int != 0) {
// We can't combine resolve and scaling, so resolve into our internal buffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_int);
} 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 (fbo_int != 0) {
// 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_int);
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);
}

glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
} else if ((fbo_msaa_3d != 0 && msaa3d_needs_resolve) || (fbo_int != 0)) {
// TODO investigate if it's smarter to cache these FBOs
GLuint fbos[2]; // read and write
glGenFramebuffers(2, fbos);

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);

if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) {
GLuint read_color = rb->get_msaa3d_color();
GLuint read_depth = rb->get_msaa3d_depth();
GLuint write_color = 0;
GLuint write_depth = 0;

if (fbo_int != 0) {
write_color = rb->get_internal_color();
write_depth = rb->get_internal_depth();
} else {
write_color = texture_storage->render_target_get_color(render_target);
write_depth = texture_storage->render_target_get_depth(render_target);
}

for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
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 (fbo_int != 0) {
GLuint read_color = rb->get_internal_color();
GLuint read_depth = rb->get_internal_depth();
GLuint write_color = texture_storage->render_target_get_color(render_target);
GLuint write_depth = texture_storage->render_target_get_depth(render_target);

for (uint32_t v = 0; v < view_count; v++) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);

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);
}
}

glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
glDeleteFramebuffers(2, fbos);
}
}

template <PassMode p_pass_mode>
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();
Expand Down Expand Up @@ -3123,7 +3242,7 @@ Ref<RenderSceneBuffers> RasterizerSceneGLES3::render_buffers_create() {
return rb;
}

void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas) {
void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> 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();
Expand Down Expand Up @@ -3200,8 +3319,11 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
}
}
}
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
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)));
Expand Down
3 changes: 2 additions & 1 deletion drivers/gles3/rasterizer_scene_gles3.h
Expand Up @@ -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, const Size2i &p_viewport_size = Size2i(1, 1));
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &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, const Size2i &p_viewport_size = Size2i(1, 1));
void _render_post_processing(const RenderDataGLES3 *p_render_data);

template <PassMode p_pass_mode>
_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);
Expand All @@ -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<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas);
void _render_buffers_debug_draw(Ref<RenderSceneBuffersGLES3> p_render_buffers, RID p_shadow_atlas, GLuint p_fbo);

/* Camera Attributes */

Expand Down
35 changes: 35 additions & 0 deletions drivers/gles3/storage/config.cpp
Expand Up @@ -92,14 +92,49 @@ Config::Config() {
anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
}

glGetIntegerv(GL_MAX_SAMPLES, &msaa_max_samples);
#ifdef WEB_ENABLED
msaa_supported = (msaa_max_samples > 0);
#else
msaa_supported = extensions.has("GL_EXT_framebuffer_multisample");
#endif
#ifndef IOS_ENABLED
msaa_multiview_supported = extensions.has("GL_EXT_multiview_texture_multisample");
multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
#endif

#ifdef ANDROID_ENABLED
// These are GLES only
rt_msaa_supported = extensions.has("GL_EXT_multisampled_render_to_texture");
rt_msaa_multiview_supported = extensions.has("GL_OVR_multiview_multisampled_render_to_texture");

if (multiview_supported) {
eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
if (eglFramebufferTextureMultiviewOVR == nullptr) {
multiview_supported = false;
}
}

if (msaa_multiview_supported) {
eglTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)eglGetProcAddress("glTexStorage3DMultisample");
if (eglTexStorage3DMultisample == nullptr) {
msaa_multiview_supported = false;
}
}

if (rt_msaa_supported) {
eglFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
if (eglFramebufferTexture2DMultisampleEXT == nullptr) {
rt_msaa_supported = false;
}
}

if (rt_msaa_multiview_supported) {
eglFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR");
if (eglFramebufferTextureMultisampleMultiviewOVR == nullptr) {
rt_msaa_multiview_supported = false;
}
}
#endif

force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
Expand Down
12 changes: 12 additions & 0 deletions drivers/gles3/storage/config.h
Expand Up @@ -42,6 +42,9 @@

#ifdef ANDROID_ENABLED
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
typedef void (*PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean);
typedef void (*PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei);
#endif

namespace GLES3 {
Expand Down Expand Up @@ -82,9 +85,18 @@ class Config {
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;

GLint msaa_max_samples = 0;
bool msaa_supported = false;
bool msaa_multiview_supported = false;
bool rt_msaa_supported = false;
bool rt_msaa_multiview_supported = false;
bool multiview_supported = false;

#ifdef ANDROID_ENABLED
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr;
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr;
#endif

static Config *get_singleton() { return singleton; };
Expand Down
4 changes: 0 additions & 4 deletions drivers/gles3/storage/material_storage.cpp
Expand Up @@ -3000,10 +3000,6 @@ void SceneShaderData::set_code(const String &p_code) {
WARN_PRINT_ONCE_ED("Transmittance is only available when using the Forward+ rendering backend.");
}

if (uses_depth_texture) {
WARN_PRINT_ONCE_ED("Reading from the depth texture is not supported when using the GL Compatibility backend yet. Support will be added in a future release.");
}

if (uses_normal_texture) {
WARN_PRINT_ONCE_ED("Reading from the normal-roughness texture is only available when using the Forward+ or Mobile rendering backends.");
}
Expand Down