Skip to content

Commit

Permalink
Add 3D MSAA and scaling support to GLES3
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Nov 10, 2023
1 parent 3e7f638 commit 4007d92
Show file tree
Hide file tree
Showing 13 changed files with 829 additions and 57 deletions.
2 changes: 2 additions & 0 deletions doc/classes/ProjectSettings.xml
Expand Up @@ -2774,9 +2774,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
36 changes: 36 additions & 0 deletions drivers/gles3/storage/config.cpp
Expand Up @@ -92,14 +92,50 @@ Config::Config() {
anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
}

#ifdef WEB_ENABLED
GLint msaa_max_samples;
glGetIntegerv(GL_MAX_SAMPLES, &msaa_max_samples);
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
11 changes: 11 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,17 @@ class Config {
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;

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 @@ -2981,10 +2981,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

0 comments on commit 4007d92

Please sign in to comment.