Skip to content

Commit ae7c533

Browse files
committedDec 11, 2023
Merge pull request #84686 from dsnopek/webxr-msaa
Add MSAA support for WebXR
2 parents 4943b6e + 275c496 commit ae7c533

9 files changed

+122
-49
lines changed
 

‎drivers/gles3/storage/config.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,14 @@ Config::Config() {
9999
msaa_supported = extensions.has("GL_EXT_framebuffer_multisample");
100100
#endif
101101
#ifndef IOS_ENABLED
102+
#ifdef WEB_ENABLED
103+
msaa_multiview_supported = extensions.has("OCULUS_multiview");
104+
rt_msaa_multiview_supported = msaa_multiview_supported;
105+
#else
102106
msaa_multiview_supported = extensions.has("GL_EXT_multiview_texture_multisample");
103-
multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
107+
#endif
108+
109+
multiview_supported = extensions.has("OCULUS_multiview") || extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
104110
#endif
105111

106112
#ifdef ANDROID_ENABLED

‎drivers/gles3/storage/render_scene_buffers_gles3.cpp

+50-22
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,42 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
5151
free_render_buffer_data();
5252
}
5353

54+
void RenderSceneBuffersGLES3::_rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count) {
55+
if (p_view_count > 1) {
56+
if (p_samples > 1) {
57+
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED)
58+
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, p_samples, 0, p_view_count);
59+
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
60+
#else
61+
ERR_PRINT_ONCE("Multiview MSAA isn't supported on this platform.");
62+
#endif
63+
} else {
64+
#ifndef IOS_ENABLED
65+
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, 0, p_view_count);
66+
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, 0, p_view_count);
67+
#else
68+
ERR_PRINT_ONCE("Multiview isn't supported on this platform.");
69+
#endif
70+
}
71+
} else {
72+
if (p_samples > 1) {
73+
#ifdef ANDROID_ENABLED
74+
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0, p_samples);
75+
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
76+
#else
77+
ERR_PRINT_ONCE("MSAA via EXT_multisampled_render_to_texture isn't supported on this platform.");
78+
#endif
79+
} else {
80+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0);
81+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0);
82+
}
83+
}
84+
}
85+
5486
GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count) {
5587
FBDEF new_fbo;
5688

57-
#ifdef ANDROID_ENABLED
89+
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED)
5890
// There shouldn't be more then 3 entries in this...
5991
for (const FBDEF &cached_fbo : msaa3d.cached_fbos) {
6092
if (cached_fbo.color == p_color && cached_fbo.depth == p_depth) {
@@ -68,13 +100,7 @@ GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_dept
68100
glGenFramebuffers(1, &new_fbo.fbo);
69101
glBindFramebuffer(GL_FRAMEBUFFER, new_fbo.fbo);
70102

71-
if (p_view_count > 1) {
72-
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, p_samples, 0, p_view_count);
73-
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
74-
} else {
75-
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0, p_samples);
76-
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
77-
}
103+
_rt_attach_textures(p_color, p_depth, p_samples, p_view_count);
78104

79105
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
80106
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -317,8 +343,6 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
317343
// hence we'll use our FBO cache here.
318344
msaa3d.needs_resolve = false;
319345
msaa3d.check_fbo_cache = true;
320-
#endif
321-
#ifdef ANDROID_ENABLED
322346
} else if (use_internal_buffer) {
323347
// We can combine MSAA and scaling/effects.
324348
msaa3d.needs_resolve = false;
@@ -329,13 +353,7 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
329353
glGenFramebuffers(1, &msaa3d.fbo);
330354
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
331355

332-
if (use_multiview) {
333-
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, msaa3d.samples, 0, view_count);
334-
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, internal3d.depth, 0, msaa3d.samples, 0, view_count);
335-
} else {
336-
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, internal3d.color, 0, msaa3d.samples);
337-
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, internal3d.depth, 0, msaa3d.samples);
338-
}
356+
_rt_attach_textures(internal3d.color, internal3d.depth, msaa3d.samples, view_count);
339357

340358
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
341359
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -515,24 +533,34 @@ void RenderSceneBuffersGLES3::free_render_buffer_data() {
515533
}
516534

517535
GLuint RenderSceneBuffersGLES3::get_render_fbo() {
518-
if (msaa3d.check_fbo_cache) {
519-
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
536+
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
537+
GLuint rt_fbo = 0;
520538

539+
if (msaa3d.check_fbo_cache) {
521540
GLuint color = texture_storage->render_target_get_color(render_target);
522541
GLuint depth = texture_storage->render_target_get_depth(render_target);
523542

524-
return _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
543+
rt_fbo = _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
525544
} else if (msaa3d.fbo != 0) {
526545
// We have an MSAA fbo, render to our MSAA buffer
527546
return msaa3d.fbo;
528547
} else if (internal3d.fbo != 0) {
529548
// We have an internal buffer, render to our internal buffer!
530549
return internal3d.fbo;
531550
} else {
532-
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
551+
rt_fbo = texture_storage->render_target_get_fbo(render_target);
552+
}
533553

534-
return texture_storage->render_target_get_fbo(render_target);
554+
if (texture_storage->render_target_is_reattach_textures(render_target)) {
555+
GLuint color = texture_storage->render_target_get_color(render_target);
556+
GLuint depth = texture_storage->render_target_get_depth(render_target);
557+
558+
glBindFramebuffer(GL_FRAMEBUFFER, rt_fbo);
559+
_rt_attach_textures(color, depth, msaa3d.samples, view_count);
560+
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
535561
}
562+
563+
return rt_fbo;
536564
}
537565

538566
#endif // GLES3_ENABLED

‎drivers/gles3/storage/render_scene_buffers_gles3.h

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class RenderSceneBuffersGLES3 : public RenderSceneBuffers {
9595
void _clear_intermediate_buffers();
9696
void _clear_back_buffers();
9797

98+
void _rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
9899
GLuint _rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
99100

100101
public:

‎drivers/gles3/storage/texture_storage.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -2320,6 +2320,20 @@ GLuint TextureStorage::render_target_get_depth(RID p_render_target) const {
23202320
}
23212321
}
23222322

2323+
void TextureStorage::render_target_set_reattach_textures(RID p_render_target, bool p_reattach_textures) const {
2324+
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
2325+
ERR_FAIL_NULL(rt);
2326+
2327+
rt->reattach_textures = p_reattach_textures;
2328+
}
2329+
2330+
bool TextureStorage::render_target_is_reattach_textures(RID p_render_target) const {
2331+
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
2332+
ERR_FAIL_NULL_V(rt, false);
2333+
2334+
return rt->reattach_textures;
2335+
}
2336+
23232337
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
23242338
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
23252339
ERR_FAIL_NULL(rt);

‎drivers/gles3/storage/texture_storage.h

+3
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ struct RenderTarget {
365365

366366
bool used_in_frame = false;
367367
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
368+
bool reattach_textures = false;
368369

369370
struct RTOverridden {
370371
bool is_overridden = false;
@@ -639,6 +640,8 @@ class TextureStorage : public RendererTextureStorage {
639640
GLuint render_target_get_fbo(RID p_render_target) const;
640641
GLuint render_target_get_color(RID p_render_target) const;
641642
GLuint render_target_get_depth(RID p_render_target) const;
643+
void render_target_set_reattach_textures(RID p_render_target, bool p_reattach_textures) const;
644+
bool render_target_is_reattach_textures(RID p_render_target) const;
642645

643646
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
644647
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;

‎modules/webxr/webxr_interface_js.cpp

+12-26
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ void WebXRInterfaceJS::uninitialize() {
309309

310310
godot_webxr_uninitialize();
311311

312-
GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage);
312+
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
313313
if (texture_storage != nullptr) {
314314
for (KeyValue<unsigned int, RID> &E : texture_cache) {
315315
// Forcibly mark as not part of a render target so we can free it.
@@ -438,16 +438,11 @@ Projection WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_a
438438
}
439439

440440
bool WebXRInterfaceJS::pre_draw_viewport(RID p_render_target) {
441-
GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage);
441+
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
442442
if (texture_storage == nullptr) {
443443
return false;
444444
}
445445

446-
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
447-
if (rt == nullptr) {
448-
return false;
449-
}
450-
451446
// Cache the resources so we don't have to get them from JS twice.
452447
color_texture = _get_color_texture();
453448
depth_texture = _get_depth_texture();
@@ -460,31 +455,22 @@ bool WebXRInterfaceJS::pre_draw_viewport(RID p_render_target) {
460455
//
461456
// See: https://immersive-web.github.io/layers/#xropaquetextures
462457
//
463-
// This is why we're doing this sort of silly check: if the color and depth
464-
// textures are the same this frame as last frame, we need to attach them
465-
// again, despite the fact that the GLuint for them hasn't changed.
466-
if (rt->overridden.is_overridden && rt->overridden.color == color_texture && rt->overridden.depth == depth_texture) {
467-
GLES3::Config *config = GLES3::Config::get_singleton();
468-
bool use_multiview = rt->view_count > 1 && config->multiview_supported;
469-
470-
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
471-
if (use_multiview) {
472-
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
473-
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
474-
} else {
475-
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
476-
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
477-
}
478-
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
479-
}
458+
// So, even if the color and depth textures have the same GLuint as the last
459+
// frame, we need to re-attach them again.
460+
texture_storage->render_target_set_reattach_textures(p_render_target, true);
480461

481462
return true;
482463
}
483464

484465
Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) {
485466
Vector<BlitToScreen> blit_to_screen;
486467

487-
// We don't need to do anything here.
468+
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
469+
if (texture_storage == nullptr) {
470+
return blit_to_screen;
471+
}
472+
473+
texture_storage->render_target_set_reattach_textures(p_render_target, false);
488474

489475
return blit_to_screen;
490476
};
@@ -513,7 +499,7 @@ RID WebXRInterfaceJS::_get_texture(unsigned int p_texture_id) {
513499
return cache->get();
514500
}
515501

516-
GLES3::TextureStorage *texture_storage = dynamic_cast<GLES3::TextureStorage *>(RSG::texture_storage);
502+
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
517503
if (texture_storage == nullptr) {
518504
return RID();
519505
}

‎platform/web/godot_webgl2.h

+2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ extern "C" {
4444
#endif
4545

4646
void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
47+
void godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);
4748
void godot_webgl2_glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
4849

4950
#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR
51+
#define glFramebufferTextureMultisampleMultiviewOVR godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR
5052

5153
#ifdef __cplusplus
5254
}

‎platform/web/js/libs/library_godot_webgl2.externs.js

+16
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,19 @@ OVR_multiview2.prototype.FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
3434
* @return {void}
3535
*/
3636
OVR_multiview2.prototype.framebufferTextureMultiviewOVR = function(target, attachment, texture, level, baseViewIndex, numViews) {};
37+
38+
/**
39+
* @constructor OCULUS_multiview
40+
*/
41+
function OCULUS_multiview() {}
42+
43+
/**
44+
* @param {number} target
45+
* @param {number} attachment
46+
* @param {WebGLTexture} texture
47+
* @param {number} level
48+
* @param {number} baseViewIndex
49+
* @param {number} numViews
50+
* @return {void}
51+
*/
52+
OCULUS_multiview.prototype.framebufferTextureMultisampleMultiviewOVR = function(target, attachment, texture, level, samples, baseViewIndex, numViews) {};

‎platform/web/js/libs/library_godot_webgl2.js

+17
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,23 @@ const GodotWebGL2 = {
6161
const /** OVR_multiview2 */ ext = context.multiviewExt;
6262
ext.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views);
6363
},
64+
65+
godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR__deps: ['emscripten_webgl_get_current_context'],
66+
godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR__proxy: 'sync',
67+
godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR__sig: 'viiiiiii',
68+
godot_webgl2_glFramebufferTextureMultisampleMultiviewOVR: function (target, attachment, texture, level, samples, base_view_index, num_views) {
69+
const context = GL.currentContext;
70+
if (typeof context.oculusMultiviewExt === 'undefined') {
71+
const /** OCULUS_multiview */ ext = context.GLctx.getExtension('OCULUS_multiview');
72+
if (!ext) {
73+
GodotRuntime.error('Trying to call glFramebufferTextureMultisampleMultiviewOVR() without the OCULUS_multiview extension');
74+
return;
75+
}
76+
context.oculusMultiviewExt = ext;
77+
}
78+
const /** OCULUS_multiview */ ext = context.oculusMultiviewExt;
79+
ext.framebufferTextureMultisampleMultiviewOVR(target, attachment, GL.textures[texture], level, samples, base_view_index, num_views);
80+
},
6481
};
6582

6683
autoAddDeps(GodotWebGL2, '$GodotWebGL2');

0 commit comments

Comments
 (0)
Please sign in to comment.