From 398ee08375e1acc2354dcb8b9edbf2902a59fcf1 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Sun, 4 Sep 2022 09:56:24 -0500 Subject: [PATCH] Add multiview to the opengl3 driver --- drivers/gles3/rasterizer_gles3.cpp | 25 ++++++-- drivers/gles3/rasterizer_gles3.h | 2 +- drivers/gles3/rasterizer_scene_gles3.cpp | 46 +++++++++++---- drivers/gles3/rasterizer_scene_gles3.h | 12 ++++ drivers/gles3/shader_gles3.cpp | 33 ++++++++--- drivers/gles3/shader_gles3.h | 2 +- drivers/gles3/shaders/scene.glsl | 41 +++++++++++-- drivers/gles3/shaders/tonemap.glsl | 20 +++++++ drivers/gles3/storage/config.cpp | 19 ++++++ drivers/gles3/storage/config.h | 9 +++ .../storage/render_scene_buffers_gles3.cpp | 44 ++++++++++---- .../storage/render_scene_buffers_gles3.h | 2 +- drivers/gles3/storage/texture_storage.cpp | 59 ++++++++++++++----- drivers/gles3/storage/texture_storage.h | 1 + modules/webxr/godot_webxr.h | 2 +- modules/webxr/native/library_godot_webxr.js | 39 +++++++----- modules/webxr/webxr_interface_js.cpp | 3 +- platform/web/SCsub | 1 + platform/web/display_server_web.cpp | 3 + platform/web/godot_webgl2.h | 17 ++++++ platform/web/js/libs/library_godot_webgl2.js | 52 ++++++++++++++++ thirdparty/glad/KHR/khrplatform.h | 27 ++++++++- thirdparty/glad/glad.c | 20 +++++-- thirdparty/glad/glad/glad.h | 25 ++++++-- 24 files changed, 423 insertions(+), 81 deletions(-) create mode 100644 platform/web/js/libs/library_godot_webgl2.js diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 0836a212546..ea97dff522b 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -274,15 +274,32 @@ RasterizerGLES3::~RasterizerGLES3() { void RasterizerGLES3::prepare_for_blitting_render_targets() { } -void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) { +void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer) { GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target); + ERR_FAIL_COND(!rt); - glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + GLuint read_fbo = 0; + if (rt->view_count > 1) { + glGenFramebuffers(1, &read_fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo); + glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, p_layer); + } else { + glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + } + glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); // Flip content upside down to correct for coordinates. - glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); + Vector2i screen_rect_end = p_screen_rect.get_end(); + glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, + p_screen_rect.position.x, screen_rect_end.y, screen_rect_end.x, p_screen_rect.position.y, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + if (read_fbo != 0) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &read_fbo); + } } // is this p_screen useless in a multi window environment? @@ -293,7 +310,7 @@ void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_sc RID rid_rt = blit.render_target; Rect2 dst_rect = blit.dst_rect; - _blit_render_target_to_screen(rid_rt, p_screen, dst_rect); + _blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0); } } diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 431515fd0d2..d7d26685b48 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -68,7 +68,7 @@ protected: RasterizerCanvasGLES3 *canvas = nullptr; RasterizerSceneGLES3 *scene = nullptr; - void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect); + void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer); public: RendererUtilities *get_utilities() { return utilities; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d6486801e77..da713a52591 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1273,6 +1273,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix); + if (p_render_data->view_count > 1) { + for (uint32_t v = 0; v < p_render_data->view_count; v++) { + projection = correction * p_render_data->view_projection[v]; + GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]); + GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]); + + scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x; + scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y; + scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z; + scene_state.multiview_ubo.eye_offset[v][3] = 0.0; + } + } + scene_state.ubo.directional_light_count = p_render_data->directional_light_count; scene_state.ubo.z_far = p_render_data->z_far; @@ -1374,6 +1387,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer); glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); + + if (p_render_data->view_count > 1) { + if (scene_state.multiview_buffer == 0) { + glGenBuffers(1, &scene_state.multiview_buffer); + } + glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer); + glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } } // Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer @@ -1916,8 +1938,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, GLES3::SceneShaderData *prev_shader = nullptr; GeometryInstanceGLES3 *prev_inst = nullptr; SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR; + SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized - SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized. + // @todo Get this from p_params->spec_constant_base_flags instead of hardcoding it. + uint32_t base_spec_constants = 0; + + if (p_render_data->view_count > 1) { + base_spec_constants |= 1 << SPEC_CONSTANT_USE_MULTIVIEW; + } switch (p_pass_mode) { case PASS_MODE_COLOR: @@ -1957,8 +1985,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, continue; } - //uint32_t base_spec_constants = p_params->spec_constant_base_flags; - GLES3::SceneShaderData *shader; GLES3::SceneMaterialData *material_data; void *mesh_surface; @@ -2128,7 +2154,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } if (prev_shader != shader || prev_variant != instance_variant) { - material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant); + material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants); float opaque_prepass_threshold = 0.0; if constexpr (p_pass_mode == PASS_MODE_DEPTH) { opaque_prepass_threshold = 0.99; @@ -2136,7 +2162,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, opaque_prepass_threshold = 0.1; } - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, base_spec_constants); prev_shader = shader; prev_variant = instance_variant; @@ -2144,21 +2170,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) { // Rebind the light indices. - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant); - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant, base_spec_constants); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant, base_spec_constants); if (inst->omni_light_count) { - glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr()); + glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->omni_light_count, inst->omni_light_gl_cache.ptr()); } if (inst->spot_light_count) { - glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr()); + glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->spot_light_count, inst->spot_light_gl_cache.ptr()); } prev_inst = inst; } - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants); if (inst->instance_count > 0) { // Using MultiMesh. // Bind instance buffers. diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 38956202284..3a759425e2d 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -74,6 +74,7 @@ enum SceneUniformLocation { SCENE_OMNILIGHT_UNIFORM_LOCATION, SCENE_SPOTLIGHT_UNIFORM_LOCATION, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, + SCENE_MULTIVIEW_UNIFORM_LOCATION, }; enum SkyUniformLocation { @@ -90,6 +91,8 @@ enum { SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2, SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3, SPEC_CONSTANT_DISABLE_FOG = 4, + SPEC_CONSTANT_USE_RADIANCE_MAP = 5, + SPEC_CONSTANT_USE_MULTIVIEW = 6, }; struct RenderDataGLES3 { @@ -343,6 +346,13 @@ private: }; static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes"); + struct MultiviewUBO { + float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4]; + }; + static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes"); + struct TonemapUBO { float exposure = 1.0; float white = 1.0; @@ -353,6 +363,8 @@ private: UBO ubo; GLuint ubo_buffer = 0; + MultiviewUBO multiview_ubo; + GLuint multiview_buffer = 0; GLuint tonemap_buffer = 0; bool used_depth_prepass = false; diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 033f10dbc5f..2ff7f721807 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -142,7 +142,7 @@ RID ShaderGLES3::version_create() { return version_owner.make_rid(version); } -void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) { +void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) { #ifdef GLES_OVER_GL builder.append("#version 330\n"); builder.append("#define USE_GLES_OVER_GL\n"); @@ -171,6 +171,24 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant } builder.append("\n"); //make sure defines begin at newline + // Insert multiview extension loading, because it needs to appear before + // any non-preprocessor code (like the "precision highp..." lines below). + builder.append("#ifdef USE_MULTIVIEW\n"); + builder.append("#if defined(GL_OVR_multiview2)\n"); + builder.append("#extension GL_OVR_multiview2 : require\n"); + builder.append("#elif defined(GL_OVR_multiview)\n"); + builder.append("#extension GL_OVR_multiview : require\n"); + builder.append("#endif\n"); + if (p_stage_type == StageType::STAGE_TYPE_VERTEX) { + builder.append("layout(num_views=2) in;\n"); + } + builder.append("#define ViewIndex gl_ViewID_OVR\n"); + builder.append("#define MAX_VIEWS 2\n"); + builder.append("#else\n"); + builder.append("#define ViewIndex 0\n"); + builder.append("#define MAX_VIEWS 1\n"); + builder.append("#endif\n"); + // Default to highp precision unless specified otherwise. builder.append("precision highp float;\n"); builder.append("precision highp int;\n"); @@ -180,8 +198,9 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant builder.append("precision highp sampler2DArray;\n"); #endif - for (uint32_t i = 0; i < p_template.chunks.size(); i++) { - const StageTemplate::Chunk &chunk = p_template.chunks[i]; + const StageTemplate &stage_template = stage_templates[p_stage_type]; + for (uint32_t i = 0; i < stage_template.chunks.size(); i++) { + const StageTemplate::Chunk &chunk = stage_template.chunks[i]; switch (chunk.type) { case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) @@ -224,7 +243,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_ //vertex stage { StringBuilder builder; - _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization); + _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_VERTEX, p_specialization); spec.vert_id = glCreateShader(GL_VERTEX_SHADER); String builder_string = builder.as_string(); @@ -272,7 +291,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_ //fragment stage { StringBuilder builder; - _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization); + _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_FRAGMENT, p_specialization); spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER); String builder_string = builder.as_string(); @@ -413,7 +432,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver { StringBuilder builder; - _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask); + _build_variant_code(builder, i, version, STAGE_TYPE_VERTEX, specialization_default_mask); RS::ShaderNativeSourceCode::Version::Stage stage; stage.name = "vertex"; @@ -425,7 +444,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver //fragment stage { StringBuilder builder; - _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask); + _build_variant_code(builder, i, version, STAGE_TYPE_FRAGMENT, specialization_default_mask); RS::ShaderNativeSourceCode::Version::Stage stage; stage.name = "fragment"; diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 2b72549b5b0..760b5e5ddb1 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -153,7 +153,7 @@ private: StageTemplate stage_templates[STAGE_TYPE_MAX]; - void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization); + void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization); void _add_stage(const char *p_code, StageType p_stage_type); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index efd6036ba9e..2bd93796bde 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -16,6 +16,7 @@ DISABLE_LIGHT_OMNI = false DISABLE_LIGHT_SPOT = false DISABLE_FOG = false USE_RADIANCE_MAP = true +USE_MULTIVIEW = false #[vertex] @@ -153,6 +154,15 @@ layout(std140) uniform SceneData { // ubo:2 } scene_data; +#ifdef USE_MULTIVIEW +layout(std140) uniform MultiviewData { // ubo:8 + highp mat4 projection_matrix_view[MAX_VIEWS]; + highp mat4 inv_projection_matrix_view[MAX_VIEWS]; + highp vec4 eye_offset[MAX_VIEWS]; +} +multiview_data; +#endif + uniform highp mat4 world_transform; #ifdef USE_LIGHTMAP @@ -250,8 +260,14 @@ void main() { #if defined(OVERRIDE_POSITION) highp vec4 position; #endif - highp mat4 projection_matrix = scene_data.projection_matrix; - highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix; + +#ifdef USE_MULTIVIEW + mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex]; + mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex]; +#else + mat4 projection_matrix = scene_data.projection_matrix; + mat4 inv_projection_matrix = scene_data.inv_projection_matrix; +#endif //USE_MULTIVIEW #ifdef USE_INSTANCING vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); @@ -339,7 +355,6 @@ void main() { /* clang-format off */ #[fragment] - // Default to SPECULAR_SCHLICK_GGX. #if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON) #define SPECULAR_SCHLICK_GGX @@ -463,6 +478,15 @@ layout(std140) uniform SceneData { // ubo:2 } scene_data; +#ifdef USE_MULTIVIEW +layout(std140) uniform MultiviewData { // ubo:8 + highp mat4 projection_matrix_view[MAX_VIEWS]; + highp mat4 inv_projection_matrix_view[MAX_VIEWS]; + highp vec4 eye_offset[MAX_VIEWS]; +} +multiview_data; +#endif + /* clang-format off */ #GLOBALS @@ -530,8 +554,13 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4 #endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT) -uniform highp sampler2D screen_texture; // texunit:-5 +#ifdef USE_MULTIVIEW +uniform highp sampler2DArray depth_buffer; // texunit:-6 +uniform highp sampler2DArray screen_texture; // texunit:-5 +#else uniform highp sampler2D depth_buffer; // texunit:-6 +uniform highp sampler2D screen_texture; // texunit:-5 +#endif uniform highp mat4 world_transform; uniform mediump float opaque_prepass_threshold; @@ -884,7 +913,11 @@ vec4 fog_process(vec3 vertex) { void main() { //lay out everything, whatever is unused is optimized away anyway vec3 vertex = vertex_interp; +#ifdef USE_MULTIVIEW + vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz); +#else vec3 view = -normalize(vertex_interp); +#endif vec3 albedo = vec3(1.0); vec3 backlight = vec3(0.0); vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index a478cf91707..0b769e77f21 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -44,7 +44,11 @@ in vec2 uv_interp; layout(location = 0) out vec4 frag_color; +#ifdef USE_MULTIVIEW +uniform highp sampler2DArray source; //texunit:0 +#else uniform highp sampler2D source; //texunit:0 +#endif #if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) #define USING_GLOW // only use glow when at least one glow level is selected @@ -191,10 +195,17 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { const float FXAA_REDUCE_MUL = (1.0 / 8.0); const float FXAA_SPAN_MAX = 8.0; +#ifdef USE_MULTIVIEW + vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz; + vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz; + vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz; + vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz; +#else vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; +#endif vec3 rgbM = color; vec3 luma = vec3(0.299, 0.587, 0.114); float lumaNW = dot(rgbNW, luma); @@ -219,8 +230,13 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { dir * rcpDirMin)) * pixel_size; +#ifdef USE_MULTIVIEW + vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz); +#else vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz); +#endif float lumaB = dot(rgbB, luma); if ((lumaB < lumaMin) || (lumaB > lumaMax)) { @@ -231,7 +247,11 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { } void main() { +#ifdef USE_MULTIVIEW + vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0); +#else vec4 color = textureLod(source, uv_interp, 0.0); +#endif #ifdef USE_FXAA color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size); diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 242c1ce0a9f..609ecacded4 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -34,6 +34,15 @@ #include "core/config/project_settings.h" #include "core/templates/vector.h" +#ifdef ANDROID_ENABLED +#include +#include +#include + +#include +#include +#endif + using namespace GLES3; #define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF @@ -98,6 +107,16 @@ Config::Config() { anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level); } + multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview"); +#ifdef ANDROID_ENABLED + if (multiview_supported) { + eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR"); + if (eglFramebufferTextureMultiviewOVR == nullptr) { + multiview_supported = false; + } + } +#endif + force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter"); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index fe183457756..de08385e044 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -44,6 +44,10 @@ #include OPENGL_INCLUDE_H #endif +#ifdef ANDROID_ENABLED +typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei); +#endif + namespace GLES3 { class Config { @@ -82,6 +86,11 @@ public: bool support_anisotropic_filter = false; float anisotropic_level = 0.0f; + bool multiview_supported = false; +#ifdef ANDROID_ENABLED + PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr; +#endif + static Config *get_singleton() { return singleton; }; Config(); diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 9123984dc72..b8e4530f569 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -33,12 +33,17 @@ #include "render_scene_buffers_gles3.h" #include "texture_storage.h" +#ifdef ANDROID_ENABLED +#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR +#endif + RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() { free_render_buffer_data(); } void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); + GLES3::Config *config = GLES3::Config::get_singleton(); //internal_size.x = p_internal_size.x; // ignore for now //internal_size.y = p_internal_size.y; @@ -50,7 +55,7 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte //msaa = p_msaa; //screen_space_aa = p_screen_space_aa; //use_debanding = p_use_debanding; - //view_count = p_view_count; + view_count = p_view_count; free_render_buffer_data(); @@ -62,24 +67,43 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - glBindTexture(GL_TEXTURE_2D, rt->color); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + if (view_count > 1 && config->multiview_supported) { + glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color); + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, view_count); + } else { + glBindTexture(GL_TEXTURE_2D, rt->color); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + } glGenTextures(1, &depth_texture); - glBindTexture(GL_TEXTURE_2D, depth_texture); + if (view_count > 1 && config->multiview_supported) { + glBindTexture(GL_TEXTURE_2D_ARRAY, depth_texture); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glBindTexture(GL_TEXTURE_2D, depth_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); + if (view_count > 1 && config->multiview_supported) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0, 0, view_count); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); + } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo); if (status != GL_FRAMEBUFFER_COMPLETE) { diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h index ad0d2032b07..dbedbd22c3d 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.h +++ b/drivers/gles3/storage/render_scene_buffers_gles3.h @@ -56,7 +56,7 @@ public: RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; //bool use_debanding = false; - //uint32_t view_count = 1; + uint32_t view_count = 1; bool is_transparent = false; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 554b4165faf..524ff14cc96 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -34,6 +34,10 @@ #include "config.h" #include "drivers/gles3/effects/copy_effects.h" +#ifdef ANDROID_ENABLED +#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR +#endif + using namespace GLES3; TextureStorage *TextureStorage::singleton = nullptr; @@ -720,8 +724,7 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) { } void TextureStorage::texture_2d_update(RID p_texture, const Ref &p_image, int p_layer) { - // only 1 layer so far - texture_set_data(p_texture, p_image); + texture_set_data(p_texture, p_image, p_layer); #ifdef TOOLS_ENABLED Texture *tex = texture_owner.get_or_null(p_texture); @@ -1012,7 +1015,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref &p_image, img->resize_to_po2(false); } - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : texture->target; Vector read = img->get_data(); @@ -1069,7 +1072,11 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref &p_image, glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + if (texture->target == GL_TEXTURE_2D_ARRAY) { + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 0, format, type, &read[ofs]); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + } } tsize += size; @@ -1425,6 +1432,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { return; } + Config *config = Config::get_singleton(); + rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2; rt->color_format = GL_RGBA; rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV; @@ -1446,17 +1455,29 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { // color glGenTextures(1, &rt->color); - glBindTexture(GL_TEXTURE_2D, rt->color); + if (rt->view_count > 1 && config->multiview_supported) { + glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr); - glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glBindTexture(GL_TEXTURE_2D, rt->color); + glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + if (rt->view_count > 1 && config->multiview_supported) { + glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -1475,8 +1496,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { texture->format = rt->image_format; texture->real_format = rt->image_format; - texture->type = Texture::TYPE_2D; - texture->target = GL_TEXTURE_2D; + if (rt->view_count > 1 && config->multiview_supported) { + texture->type = Texture::TYPE_LAYERED; + texture->target = GL_TEXTURE_2D_ARRAY; + texture->layers = rt->view_count; + } else { + texture->type = Texture::TYPE_2D; + texture->target = GL_TEXTURE_2D; + texture->layers = 1; + } texture->gl_format_cache = rt->color_format; texture->gl_type_cache = GL_UNSIGNED_BYTE; texture->gl_internal_format_cache = rt->color_internal_format; @@ -1619,13 +1647,14 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); - if (p_width == rt->size.x && p_height == rt->size.y) { + if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) { return; } _clear_render_target(rt); rt->size = Size2i(p_width, p_height); + rt->view_count = p_view_count; _update_render_target(rt); } diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 39a74236e54..dbe39428aca 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -324,6 +324,7 @@ private: struct RenderTarget { Point2i position = Point2i(0, 0); Size2i size = Size2i(0, 0); + uint32_t view_count = 1; int mipmap_count = 1; RID self; GLuint fbo = 0; diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h index 34d068be3e7..d8d5bd99cc0 100644 --- a/modules/webxr/godot_webxr.h +++ b/modules/webxr/godot_webxr.h @@ -65,7 +65,7 @@ extern int godot_webxr_get_view_count(); extern int *godot_webxr_get_render_target_size(); extern float *godot_webxr_get_transform_for_eye(int p_eye); extern float *godot_webxr_get_projection_for_eye(int p_eye); -extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo); +extern void godot_webxr_commit(unsigned int p_texture); extern void godot_webxr_sample_controller_data(); extern int godot_webxr_get_controller_count(); diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js index 9b75796ee53..c476a54c597 100644 --- a/modules/webxr/native/library_godot_webxr.js +++ b/modules/webxr/native/library_godot_webxr.js @@ -337,20 +337,18 @@ const GodotWebXR = { return buf; }, - godot_webxr_commit_for_eye__proxy: 'sync', - godot_webxr_commit_for_eye__sig: 'vii', - godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) { + godot_webxr_commit__proxy: 'sync', + godot_webxr_commit__sig: 'vi', + godot_webxr_commit: function (p_texture) { if (!GodotWebXR.session || !GodotWebXR.pose) { return; } - const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0; const glLayer = GodotWebXR.session.renderState.baseLayer; - const view = GodotWebXR.pose.views[view_index]; - const viewport = glLayer.getViewport(view); + const views = GodotWebXR.pose.views; const gl = GodotWebXR.gl; - const framebuffer = GL.framebuffers[p_destination_fbo]; + const texture = GL.textures[p_texture]; const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING); @@ -359,14 +357,27 @@ const GodotWebXR = { // Copy from Godot render target into framebuffer from WebXR. gl.bindFramebuffer(gl.FRAMEBUFFER, null); - gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer); - gl.readBuffer(gl.COLOR_ATTACHMENT0); - gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer); + for (let i = 0; i < views.length; i++) { + const viewport = glLayer.getViewport(views[i]); - // Flip Y upside down on destination. - gl.blitFramebuffer(0, 0, viewport.width, viewport.height, - viewport.x, viewport.height, viewport.width, viewport.y, - gl.COLOR_BUFFER_BIT, gl.NEAREST); + const read_fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, read_fbo); + if (views.length > 1) { + gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, i); + } else { + gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + } + gl.readBuffer(gl.COLOR_ATTACHMENT0); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer); + + // Flip Y upside down on destination. + gl.blitFramebuffer(0, 0, viewport.width, viewport.height, + viewport.x, viewport.y + viewport.height, viewport.x + viewport.width, viewport.y, + gl.COLOR_BUFFER_BIT, gl.NEAREST); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + gl.deleteFramebuffer(read_fbo); + } // Restore state. gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer); diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 6b671c1660b..f6ed9f027ee 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -415,8 +415,7 @@ Vector WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target); - // @todo Support multiple eyes! - godot_webxr_commit_for_eye(1, rt->fbo); + godot_webxr_commit(rt->color); return blit_to_screen; }; diff --git a/platform/web/SCsub b/platform/web/SCsub index cb00fa9f5b2..077024507a7 100644 --- a/platform/web/SCsub +++ b/platform/web/SCsub @@ -35,6 +35,7 @@ sys_env.AddJSLibraries( "js/libs/library_godot_os.js", "js/libs/library_godot_runtime.js", "js/libs/library_godot_input.js", + "js/libs/library_godot_webgl2.js", ] ) diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index f6a61b18e46..2ee1edd2b4c 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -773,6 +773,9 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) { webgl2_init_failed = true; } else { + if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) { + // @todo Should we log this? + } RasterizerGLES3::make_current(); } } diff --git a/platform/web/godot_webgl2.h b/platform/web/godot_webgl2.h index 968b70f84b3..ae6b23ae18b 100644 --- a/platform/web/godot_webgl2.h +++ b/platform/web/godot_webgl2.h @@ -34,4 +34,21 @@ #include "GLES3/gl3.h" #include "webgl/webgl2.h" +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 +#define GL_MAX_VIEWS_OVR 0x9631 +#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 + +#ifdef __cplusplus +extern "C" { +#endif + +void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); + +#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR + +#ifdef __cplusplus +} +#endif + #endif // GODOT_WEBGL2_H diff --git a/platform/web/js/libs/library_godot_webgl2.js b/platform/web/js/libs/library_godot_webgl2.js new file mode 100644 index 00000000000..365f712be78 --- /dev/null +++ b/platform/web/js/libs/library_godot_webgl2.js @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* library_godot_webgl2.js */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +const GodotWebGL2 = { + $GodotWebGL2__deps: ['$GL', '$GodotRuntime'], + $GodotWebGL2: {}, + + godot_webgl2_glFramebufferTextureMultiviewOVR__deps: ['emscripten_webgl_get_current_context'], + godot_webgl2_glFramebufferTextureMultiviewOVR__proxy: 'sync', + godot_webgl2_glFramebufferTextureMultiviewOVR__sig: 'viiiiii', + godot_webgl2_glFramebufferTextureMultiviewOVR: function (target, attachment, texture, level, base_view_index, num_views) { + const context = GL.currentContext; + if (typeof context.multiviewExt === 'undefined') { + const ext = context.GLctx.getExtension('OVR_multiview2'); + if (!ext) { + console.error('Trying to call glFramebufferTextureMultiviewOVR() without the OVR_multiview2 extension'); + return; + } + context.multiviewExt = ext; + } + context.multiviewExt.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views); + }, +}; + +autoAddDeps(GodotWebGL2, '$GodotWebGL2'); +mergeInto(LibraryManager.library, GodotWebGL2); diff --git a/thirdparty/glad/KHR/khrplatform.h b/thirdparty/glad/KHR/khrplatform.h index dd22d927018..01646449cae 100644 --- a/thirdparty/glad/KHR/khrplatform.h +++ b/thirdparty/glad/KHR/khrplatform.h @@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif #elif defined(__VMS ) || defined(__sgi) @@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t; * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ -#ifdef _WIN64 +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) typedef signed long long int khronos_intptr_t; typedef unsigned long long int khronos_uintptr_t; -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; #else typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #endif diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c index dc1b8cb697e..4b20178ef7b 100644 --- a/thirdparty/glad/glad.c +++ b/thirdparty/glad/glad.c @@ -1,6 +1,6 @@ /* - OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020. + OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022. Language/Generator: C/C++ Specification: gl @@ -11,16 +11,18 @@ GL_ARB_framebuffer_object, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, - GL_EXT_framebuffer_object + GL_EXT_framebuffer_object, + GL_OVR_multiview, + GL_OVR_multiview2 Loader: True Local files: False Omit khrplatform: False Reproducible: False Commandline: - --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object" + --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2" Online: - https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2 */ #include @@ -1000,6 +1002,8 @@ int GLAD_GL_ARB_framebuffer_object = 0; int GLAD_GL_EXT_framebuffer_blit = 0; int GLAD_GL_EXT_framebuffer_multisample = 0; int GLAD_GL_EXT_framebuffer_object = 0; +int GLAD_GL_OVR_multiview = 0; +int GLAD_GL_OVR_multiview2 = 0; PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL; PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL; @@ -1023,6 +1027,7 @@ PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL; PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL; PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL; +PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR = NULL; static void load_GL_VERSION_1_0(GLADloadproc load) { if(!GLAD_GL_VERSION_1_0) return; glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); @@ -1844,6 +1849,10 @@ static void load_GL_EXT_framebuffer_object(GLADloadproc load) { glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT"); glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT"); } +static void load_GL_OVR_multiview(GLADloadproc load) { + if(!GLAD_GL_OVR_multiview) return; + glad_glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)load("glFramebufferTextureMultiviewOVR"); +} static int find_extensionsGL(void) { if (!get_exts()) return 0; GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output"); @@ -1851,6 +1860,8 @@ static int find_extensionsGL(void) { GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object"); + GLAD_GL_OVR_multiview = has_ext("GL_OVR_multiview"); + GLAD_GL_OVR_multiview2 = has_ext("GL_OVR_multiview2"); free_exts(); return 1; } @@ -1934,6 +1945,7 @@ int gladLoadGLLoader(GLADloadproc load) { load_GL_EXT_framebuffer_blit(load); load_GL_EXT_framebuffer_multisample(load); load_GL_EXT_framebuffer_object(load); + load_GL_OVR_multiview(load); return GLVersion.major != 0 || GLVersion.minor != 0; } diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h index f211e6aa570..37d12e4ee2d 100644 --- a/thirdparty/glad/glad/glad.h +++ b/thirdparty/glad/glad/glad.h @@ -1,6 +1,6 @@ /* - OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020. + OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022. Language/Generator: C/C++ Specification: gl @@ -11,16 +11,18 @@ GL_ARB_framebuffer_object, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, - GL_EXT_framebuffer_object + GL_EXT_framebuffer_object, + GL_OVR_multiview, + GL_OVR_multiview2 Loader: True Local files: False Omit khrplatform: False Reproducible: False Commandline: - --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object" + --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2" Online: - https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2 */ @@ -3687,6 +3689,10 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 +#define GL_MAX_VIEWS_OVR 0x9631 +#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 #ifndef GL_ARB_debug_output #define GL_ARB_debug_output 1 GLAPI int GLAD_GL_ARB_debug_output; @@ -3776,6 +3782,17 @@ typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target); GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; #define glGenerateMipmapEXT glad_glGenerateMipmapEXT #endif +#ifndef GL_OVR_multiview +#define GL_OVR_multiview 1 +GLAPI int GLAD_GL_OVR_multiview; +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +GLAPI PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR; +#define glFramebufferTextureMultiviewOVR glad_glFramebufferTextureMultiviewOVR +#endif +#ifndef GL_OVR_multiview2 +#define GL_OVR_multiview2 1 +GLAPI int GLAD_GL_OVR_multiview2; +#endif #ifdef __cplusplus }