Browse Source

Add support for OpenGL to OpenXR

David Snopek 2 years ago
parent
commit
23603e409c

+ 8 - 0
doc/classes/DisplayServer.xml

@@ -1725,9 +1725,17 @@
 		</constant>
 		</constant>
 		<constant name="WINDOW_VIEW" value="2" enum="HandleType">
 		<constant name="WINDOW_VIEW" value="2" enum="HandleType">
 			Window view:
 			Window view:
+			- Windows: [code]HDC[/code] for the window (only with the GL Compatibility renderer).
 			- macOS: [code]NSView*[/code] for the window main view.
 			- macOS: [code]NSView*[/code] for the window main view.
 			- iOS: [code]UIView*[/code] for the window main view.
 			- iOS: [code]UIView*[/code] for the window main view.
 		</constant>
 		</constant>
+		<constant name="OPENGL_CONTEXT" value="3" enum="HandleType">
+			OpenGL context (only with the GL Compatibility renderer):
+			- Windows: [code]HGLRC[/code] for the window.
+			- Linux: [code]GLXContext*[/code] for the window.
+			- MacOS: [code]NSOpenGLContext*[/code] for the window.
+			- Android: [code]EGLContext[/code] for the window.
+		</constant>
 		<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
 		<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
 			Utterance has begun to be spoken.
 			Utterance has begun to be spoken.
 		</constant>
 		</constant>

+ 22 - 2
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1642,6 +1642,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 		ERR_FAIL_COND(rb.is_null());
 		ERR_FAIL_COND(rb.is_null());
 	}
 	}
 
 
+	GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
+	ERR_FAIL_COND(!rt);
+
 	// Assign render data
 	// Assign render data
 	// Use the format from rendererRD
 	// Use the format from rendererRD
 	RenderDataGLES3 render_data;
 	RenderDataGLES3 render_data;
@@ -1729,8 +1732,20 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 
 
 	scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
 	scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
 
 
+	bool flip_y = !render_data.reflection_probe.is_valid();
+
+	if (rt->overridden.color.is_valid()) {
+		// If we've overridden the render target's color texture, then don't render upside down.
+		// We're probably rendering directly to an XR device.
+		flip_y = false;
+	}
+	if (!flip_y) {
+		// If we're rendering right-side up, then we need to change the winding order.
+		glFrontFace(GL_CW);
+	}
+
 	_setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
 	_setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
-	_setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
+	_setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, flip_y, clear_color, false);
 
 
 	_fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
 	_fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
 	render_list[RENDER_LIST_OPAQUE].sort_by_key();
 	render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -1811,7 +1826,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 		}
 		}
 	}
 	}
 
 
-	glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+	glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
 	glViewport(0, 0, rb->width, rb->height);
 	glViewport(0, 0, rb->width, rb->height);
 
 
 	// Do depth prepass if it's explicitly enabled
 	// Do depth prepass if it's explicitly enabled
@@ -1917,6 +1932,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 
 
 	_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
 	_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
 
 
+	if (!flip_y) {
+		// Restore the default winding order.
+		glFrontFace(GL_CCW);
+	}
+
 	if (rb.is_valid()) {
 	if (rb.is_valid()) {
 		_render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
 		_render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
 	}
 	}

+ 0 - 62
drivers/gles3/storage/render_scene_buffers_gles3.cpp

@@ -33,17 +33,12 @@
 #include "render_scene_buffers_gles3.h"
 #include "render_scene_buffers_gles3.h"
 #include "texture_storage.h"
 #include "texture_storage.h"
 
 
-#ifdef ANDROID_ENABLED
-#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
-#endif
-
 RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
 RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
 	free_render_buffer_data();
 	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) {
 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::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.x = p_internal_size.x; // ignore for now
 	//internal_size.y = p_internal_size.y;
 	//internal_size.y = p_internal_size.y;
@@ -62,66 +57,9 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
 	GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
 	GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
 
 
 	is_transparent = rt->is_transparent;
 	is_transparent = rt->is_transparent;
-
-	// framebuffer
-	glGenFramebuffers(1, &framebuffer);
-	glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-
-	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);
-	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);
-
-		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);
-	}
-
-	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) {
-		free_render_buffer_data();
-		WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
-		return;
-	}
 }
 }
 
 
 void RenderSceneBuffersGLES3::free_render_buffer_data() {
 void RenderSceneBuffersGLES3::free_render_buffer_data() {
-	if (depth_texture) {
-		glDeleteTextures(1, &depth_texture);
-		depth_texture = 0;
-	}
-	if (framebuffer) {
-		glDeleteFramebuffers(1, &framebuffer);
-		framebuffer = 0;
-	}
 }
 }
 
 
 #endif // GLES3_ENABLED
 #endif // GLES3_ENABLED

+ 0 - 3
drivers/gles3/storage/render_scene_buffers_gles3.h

@@ -61,9 +61,6 @@ public:
 	bool is_transparent = false;
 	bool is_transparent = false;
 
 
 	RID render_target;
 	RID render_target;
-	GLuint internal_texture = 0; // Used for rendering when post effects are enabled
-	GLuint depth_texture = 0; // Main depth texture
-	GLuint framebuffer = 0; // Main framebuffer, contains internal_texture and depth_texture or render_target->color and depth_texture
 
 
 	//built-in textures used for ping pong image processing and blurring
 	//built-in textures used for ping pong image processing and blurring
 	struct Blur {
 	struct Blur {

+ 240 - 53
drivers/gles3/storage/texture_storage.cpp

@@ -614,7 +614,9 @@ void TextureStorage::texture_free(RID p_texture) {
 	}
 	}
 
 
 	if (t->tex_id != 0) {
 	if (t->tex_id != 0) {
-		glDeleteTextures(1, &t->tex_id);
+		if (!t->is_external) {
+			glDeleteTextures(1, &t->tex_id);
+		}
 		t->tex_id = 0;
 		t->tex_id = 0;
 	}
 	}
 
 
@@ -680,6 +682,35 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
 	texture_owner.initialize_rid(p_texture, proxy_tex);
 	texture_owner.initialize_rid(p_texture, proxy_tex);
 }
 }
 
 
+RID TextureStorage::texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
+	Texture texture;
+	texture.active = true;
+	texture.is_external = true;
+	texture.type = p_type;
+
+	switch (p_type) {
+		case Texture::TYPE_2D: {
+			texture.target = GL_TEXTURE_2D;
+		} break;
+		case Texture::TYPE_3D: {
+			texture.target = GL_TEXTURE_3D;
+		} break;
+		case Texture::TYPE_LAYERED: {
+			texture.target = GL_TEXTURE_2D_ARRAY;
+		} break;
+	}
+
+	texture.real_format = texture.format = p_format;
+	texture.tex_id = p_image;
+	texture.alloc_width = texture.width = p_width;
+	texture.alloc_height = texture.height = p_height;
+	texture.depth = p_depth;
+	texture.layers = p_layers;
+	texture.layered_type = p_layered_type;
+
+	return texture_owner.make_rid(texture);
+}
+
 void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
 void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
 	texture_set_data(p_texture, p_image, p_layer);
 	texture_set_data(p_texture, p_image, p_layer);
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
@@ -1459,43 +1490,74 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 	glDepthMask(GL_FALSE);
 	glDepthMask(GL_FALSE);
 
 
 	{
 	{
-		/* Front FBO */
+		Texture *texture;
+		bool use_multiview = rt->view_count > 1 && config->multiview_supported;
+		GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
 
 
-		Texture *texture = get_texture(rt->texture);
-		ERR_FAIL_COND(!texture);
+		/* Front FBO */
 
 
-		// framebuffer
 		glGenFramebuffers(1, &rt->fbo);
 		glGenFramebuffers(1, &rt->fbo);
 		glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
 		glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
 
 
 		// color
 		// color
-		glGenTextures(1, &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);
-
-			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);
+		if (rt->overridden.color.is_valid()) {
+			texture = get_texture(rt->overridden.color);
+			ERR_FAIL_COND(!texture);
+
+			rt->color = texture->tex_id;
+			rt->size = Size2i(texture->width, texture->height);
 		} else {
 		} 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);
+			texture = get_texture(rt->texture);
+			ERR_FAIL_COND(!texture);
 
 
-			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);
-		}
+			glGenTextures(1, &rt->color);
+			glBindTexture(texture_target, rt->color);
+
+			if (use_multiview) {
+				glTexImage3D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
+			} else {
+				glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+			}
 
 
-		if (rt->view_count > 1 && config->multiview_supported) {
+			glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		}
+		if (use_multiview) {
 			glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
 			glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
 		} else {
 		} else {
 			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
 			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
 		}
 		}
 
 
-		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+		// depth
+		if (rt->overridden.depth.is_valid()) {
+			texture = get_texture(rt->overridden.depth);
+			ERR_FAIL_COND(!texture);
 
 
+			rt->depth = texture->tex_id;
+		} else {
+			glGenTextures(1, &rt->depth);
+			glBindTexture(texture_target, rt->depth);
+
+			if (use_multiview) {
+				glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+			} else {
+				glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+			}
+
+			glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		}
+		if (use_multiview) {
+			glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
+		} else {
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
+		}
+
+		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 			glDeleteFramebuffers(1, &rt->fbo);
 			glDeleteFramebuffers(1, &rt->fbo);
 			glDeleteTextures(1, &rt->color);
 			glDeleteTextures(1, &rt->color);
@@ -1503,32 +1565,38 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
 			rt->size.x = 0;
 			rt->size.x = 0;
 			rt->size.y = 0;
 			rt->size.y = 0;
 			rt->color = 0;
 			rt->color = 0;
-			texture->tex_id = 0;
-			texture->active = false;
+			rt->depth = 0;
+			if (rt->overridden.color.is_null()) {
+				texture->tex_id = 0;
+				texture->active = false;
+			}
 			WARN_PRINT("Could not create render target, status: " + get_framebuffer_error(status));
 			WARN_PRINT("Could not create render target, status: " + get_framebuffer_error(status));
 			return;
 			return;
 		}
 		}
 
 
-		texture->format = rt->image_format;
-		texture->real_format = rt->image_format;
-		if (rt->view_count > 1 && config->multiview_supported) {
-			texture->type = Texture::TYPE_LAYERED;
-			texture->target = GL_TEXTURE_2D_ARRAY;
-			texture->layers = rt->view_count;
+		if (rt->overridden.color.is_valid()) {
+			texture->is_render_target = true;
 		} else {
 		} else {
-			texture->type = Texture::TYPE_2D;
-			texture->target = GL_TEXTURE_2D;
-			texture->layers = 1;
+			texture->format = rt->image_format;
+			texture->real_format = rt->image_format;
+			texture->target = texture_target;
+			if (rt->view_count > 1 && config->multiview_supported) {
+				texture->type = Texture::TYPE_LAYERED;
+				texture->layers = rt->view_count;
+			} else {
+				texture->type = Texture::TYPE_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;
+			texture->tex_id = rt->color;
+			texture->width = rt->size.x;
+			texture->alloc_width = rt->size.x;
+			texture->height = rt->size.y;
+			texture->alloc_height = rt->size.y;
+			texture->active = true;
 		}
 		}
-		texture->gl_format_cache = rt->color_format;
-		texture->gl_type_cache = GL_UNSIGNED_BYTE;
-		texture->gl_internal_format_cache = rt->color_internal_format;
-		texture->tex_id = rt->color;
-		texture->width = rt->size.x;
-		texture->alloc_width = rt->size.x;
-		texture->height = rt->size.y;
-		texture->alloc_height = rt->size.y;
-		texture->active = true;
 	}
 	}
 
 
 	glClearColor(0, 0, 0, 0);
 	glClearColor(0, 0, 0, 0);
@@ -1596,17 +1664,32 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 
 
 	if (rt->fbo) {
 	if (rt->fbo) {
 		glDeleteFramebuffers(1, &rt->fbo);
 		glDeleteFramebuffers(1, &rt->fbo);
-		glDeleteTextures(1, &rt->color);
 		rt->fbo = 0;
 		rt->fbo = 0;
+	}
+
+	if (rt->overridden.color.is_null()) {
+		glDeleteTextures(1, &rt->color);
 		rt->color = 0;
 		rt->color = 0;
 	}
 	}
 
 
-	Texture *tex = get_texture(rt->texture);
-	tex->alloc_height = 0;
-	tex->alloc_width = 0;
-	tex->width = 0;
-	tex->height = 0;
-	tex->active = false;
+	if (rt->overridden.depth.is_null()) {
+		glDeleteTextures(1, &rt->depth);
+		rt->depth = 0;
+	}
+
+	if (rt->texture.is_valid()) {
+		Texture *tex = get_texture(rt->texture);
+		tex->alloc_height = 0;
+		tex->alloc_width = 0;
+		tex->width = 0;
+		tex->height = 0;
+		tex->active = false;
+	}
+
+	if (rt->overridden.color.is_valid()) {
+		Texture *tex = get_texture(rt->overridden.color);
+		tex->is_render_target = false;
+	}
 
 
 	if (rt->backbuffer_fbo != 0) {
 	if (rt->backbuffer_fbo != 0) {
 		glDeleteFramebuffers(1, &rt->backbuffer_fbo);
 		glDeleteFramebuffers(1, &rt->backbuffer_fbo);
@@ -1617,6 +1700,15 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
 	_render_target_clear_sdf(rt);
 	_render_target_clear_sdf(rt);
 }
 }
 
 
+void TextureStorage::_clear_render_target_overridden_fbo_cache(RenderTarget *rt) {
+	// Dispose of the cached fbo's and the allocated textures
+	for (KeyValue<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry> &E : rt->overridden.fbo_cache) {
+		glDeleteTextures(E.value.allocated_textures.size(), E.value.allocated_textures.ptr());
+		glDeleteFramebuffers(1, &E.value.fbo);
+	}
+	rt->overridden.fbo_cache.clear();
+}
+
 RID TextureStorage::render_target_create() {
 RID TextureStorage::render_target_create() {
 	RenderTarget render_target;
 	RenderTarget render_target;
 	//render_target.was_used = false;
 	//render_target.was_used = false;
@@ -1635,11 +1727,14 @@ RID TextureStorage::render_target_create() {
 void TextureStorage::render_target_free(RID p_rid) {
 void TextureStorage::render_target_free(RID p_rid) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_rid);
 	RenderTarget *rt = render_target_owner.get_or_null(p_rid);
 	_clear_render_target(rt);
 	_clear_render_target(rt);
+	_clear_render_target_overridden_fbo_cache(rt);
 
 
 	Texture *t = get_texture(rt->texture);
 	Texture *t = get_texture(rt->texture);
 	if (t) {
 	if (t) {
 		t->is_render_target = false;
 		t->is_render_target = false;
-		texture_free(rt->texture);
+		if (rt->overridden.color.is_null()) {
+			texture_free(rt->texture);
+		}
 		//memdelete(t);
 		//memdelete(t);
 	}
 	}
 	render_target_owner.free(p_rid);
 	render_target_owner.free(p_rid);
@@ -1666,6 +1761,9 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
 	if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
 	if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
 		return;
 		return;
 	}
 	}
+	if (rt->overridden.color.is_valid()) {
+		return;
+	}
 
 
 	_clear_render_target(rt);
 	_clear_render_target(rt);
 
 
@@ -1683,10 +1781,91 @@ Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
 	return rt->size;
 	return rt->size;
 }
 }
 
 
+void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND(!rt);
+	ERR_FAIL_COND(rt->direct_to_screen);
+
+	rt->overridden.velocity = p_velocity_texture;
+
+	if (rt->overridden.color == p_color_texture && rt->overridden.depth == p_depth_texture) {
+		return;
+	}
+
+	if (p_color_texture.is_null() && p_depth_texture.is_null()) {
+		_clear_render_target(rt);
+		rt->overridden.is_overridden = false;
+		rt->overridden.color = RID();
+		rt->overridden.depth = RID();
+		rt->size = Size2i();
+		_clear_render_target_overridden_fbo_cache(rt);
+		return;
+	}
+
+	if (!rt->overridden.is_overridden) {
+		_clear_render_target(rt);
+	}
+
+	rt->overridden.color = p_color_texture;
+	rt->overridden.depth = p_depth_texture;
+	rt->overridden.is_overridden = true;
+
+	uint32_t hash_key = hash_murmur3_one_64(p_color_texture.get_id());
+	hash_key = hash_murmur3_one_64(p_depth_texture.get_id(), hash_key);
+	hash_key = hash_fmix32(hash_key);
+
+	RBMap<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry>::Element *cache;
+	if ((cache = rt->overridden.fbo_cache.find(hash_key)) != nullptr) {
+		rt->fbo = cache->get().fbo;
+		rt->size = cache->get().size;
+		rt->texture = p_color_texture;
+		return;
+	}
+
+	_update_render_target(rt);
+
+	RenderTarget::RTOverridden::FBOCacheEntry new_entry;
+	new_entry.fbo = rt->fbo;
+	new_entry.size = rt->size;
+	// Keep track of any textures we had to allocate because they weren't overridden.
+	if (p_color_texture.is_null()) {
+		new_entry.allocated_textures.push_back(rt->color);
+	}
+	if (p_depth_texture.is_null()) {
+		new_entry.allocated_textures.push_back(rt->depth);
+	}
+	rt->overridden.fbo_cache.insert(hash_key, new_entry);
+}
+
+RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND_V(!rt, RID());
+
+	return rt->overridden.color;
+}
+
+RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND_V(!rt, RID());
+
+	return rt->overridden.depth;
+}
+
+RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
+	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+	ERR_FAIL_COND_V(!rt, RID());
+
+	return rt->overridden.velocity;
+}
+
 RID TextureStorage::render_target_get_texture(RID p_render_target) {
 RID TextureStorage::render_target_get_texture(RID p_render_target) {
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
 	ERR_FAIL_COND_V(!rt, RID());
 	ERR_FAIL_COND_V(!rt, RID());
 
 
+	if (rt->overridden.color.is_valid()) {
+		return rt->overridden.color;
+	}
+
 	return rt->texture;
 	return rt->texture;
 }
 }
 
 
@@ -1696,8 +1875,10 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
 
 
 	rt->is_transparent = p_transparent;
 	rt->is_transparent = p_transparent;
 
 
-	_clear_render_target(rt);
-	_update_render_target(rt);
+	if (rt->overridden.color.is_null()) {
+		_clear_render_target(rt);
+		_update_render_target(rt);
+	}
 }
 }
 
 
 bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
 bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
@@ -1718,6 +1899,11 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
 	// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
 	// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
 	_clear_render_target(rt);
 	_clear_render_target(rt);
 	rt->direct_to_screen = p_direct_to_screen;
 	rt->direct_to_screen = p_direct_to_screen;
+	if (rt->direct_to_screen) {
+		rt->overridden.color = RID();
+		rt->overridden.depth = RID();
+		rt->overridden.velocity = RID();
+	}
 	_update_render_target(rt);
 	_update_render_target(rt);
 }
 }
 
 
@@ -1750,6 +1936,7 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
 	}
 	}
 
 
 	WARN_PRINT("2D MSAA is not yet supported for GLES3.");
 	WARN_PRINT("2D MSAA is not yet supported for GLES3.");
+
 	_clear_render_target(rt);
 	_clear_render_target(rt);
 	rt->msaa = p_msaa;
 	rt->msaa = p_msaa;
 	_update_render_target(rt);
 	_update_render_target(rt);

+ 24 - 4
drivers/gles3/storage/texture_storage.h

@@ -126,6 +126,7 @@ struct Texture {
 	RID self;
 	RID self;
 
 
 	bool is_proxy = false;
 	bool is_proxy = false;
+	bool is_external = false;
 	bool is_render_target = false;
 	bool is_render_target = false;
 
 
 	RID proxy_to = RID();
 	RID proxy_to = RID();
@@ -187,6 +188,7 @@ struct Texture {
 	void copy_from(const Texture &o) {
 	void copy_from(const Texture &o) {
 		proxy_to = o.proxy_to;
 		proxy_to = o.proxy_to;
 		is_proxy = o.is_proxy;
 		is_proxy = o.is_proxy;
+		is_external = o.is_external;
 		width = o.width;
 		width = o.width;
 		height = o.height;
 		height = o.height;
 		alloc_width = o.alloc_width;
 		alloc_width = o.alloc_width;
@@ -310,6 +312,7 @@ struct RenderTarget {
 	RID self;
 	RID self;
 	GLuint fbo = 0;
 	GLuint fbo = 0;
 	GLuint color = 0;
 	GLuint color = 0;
+	GLuint depth = 0;
 	GLuint backbuffer_fbo = 0;
 	GLuint backbuffer_fbo = 0;
 	GLuint backbuffer = 0;
 	GLuint backbuffer = 0;
 
 
@@ -333,6 +336,20 @@ struct RenderTarget {
 	bool used_in_frame = false;
 	bool used_in_frame = false;
 	RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
 	RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
 
 
+	struct RTOverridden {
+		bool is_overridden = false;
+		RID color;
+		RID depth;
+		RID velocity;
+
+		struct FBOCacheEntry {
+			GLuint fbo;
+			Size2i size;
+			Vector<GLuint> allocated_textures;
+		};
+		RBMap<uint32_t, FBOCacheEntry> fbo_cache;
+	} overridden;
+
 	RID texture;
 	RID texture;
 
 
 	Color clear_color = Color(1, 1, 1, 1);
 	Color clear_color = Color(1, 1, 1, 1);
@@ -395,6 +412,7 @@ private:
 	mutable RID_Owner<RenderTarget> render_target_owner;
 	mutable RID_Owner<RenderTarget> render_target_owner;
 
 
 	void _clear_render_target(RenderTarget *rt);
 	void _clear_render_target(RenderTarget *rt);
+	void _clear_render_target_overridden_fbo_cache(RenderTarget *rt);
 	void _update_render_target(RenderTarget *rt);
 	void _update_render_target(RenderTarget *rt);
 	void _create_render_target_backbuffer(RenderTarget *rt);
 	void _create_render_target_backbuffer(RenderTarget *rt);
 	void _render_target_allocate_sdf(RenderTarget *rt);
 	void _render_target_allocate_sdf(RenderTarget *rt);
@@ -454,6 +472,8 @@ public:
 	virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
 	virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
 	virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
 	virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
 
 
+	RID texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY);
+
 	virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override;
 	virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override;
 	virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
 	virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
 	virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
 	virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
@@ -593,10 +613,10 @@ public:
 	virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
 	virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
 	virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
 
 
-	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override {}
-	virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
-	virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
-	virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
+	virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override;
+	virtual RID render_target_get_override_color(RID p_render_target) const override;
+	virtual RID render_target_get_override_depth(RID p_render_target) const override;
+	virtual RID render_target_get_override_velocity(RID p_render_target) const override;
 
 
 	virtual RID render_target_get_texture(RID p_render_target) override;
 	virtual RID render_target_get_texture(RID p_render_target) override;
 
 

+ 2 - 0
modules/openxr/SCsub

@@ -90,6 +90,8 @@ if env["platform"] == "android":
     env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
     env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
 if env["vulkan"]:
 if env["vulkan"]:
     env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
     env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
+if env["opengl3"]:
+    env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp")
 
 
 env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
 env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
 env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp")
 env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp")

+ 479 - 0
modules/openxr/extensions/openxr_opengl_extension.cpp

@@ -0,0 +1,479 @@
+/*************************************************************************/
+/*  openxr_opengl_extension.cpp                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 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.                */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "../extensions/openxr_opengl_extension.h"
+#include "../openxr_util.h"
+#include "drivers/gles3/effects/copy_effects.h"
+#include "drivers/gles3/storage/texture_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
+#include "servers/rendering_server.h"
+
+OpenXROpenGLExtension::OpenXROpenGLExtension(OpenXRAPI *p_openxr_api) :
+		OpenXRGraphicsExtensionWrapper(p_openxr_api) {
+#ifdef ANDROID_ENABLED
+	request_extensions[XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME] = nullptr;
+#else
+	request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr;
+#endif
+
+	ERR_FAIL_NULL(openxr_api);
+}
+
+OpenXROpenGLExtension::~OpenXROpenGLExtension() {
+}
+
+void OpenXROpenGLExtension::on_instance_created(const XrInstance p_instance) {
+	ERR_FAIL_NULL(openxr_api);
+
+	// Obtain pointers to functions we're accessing here.
+
+#ifdef ANDROID_ENABLED
+	EXT_INIT_XR_FUNC(xrGetOpenGLESGraphicsRequirementsKHR);
+#else
+	EXT_INIT_XR_FUNC(xrGetOpenGLGraphicsRequirementsKHR);
+#endif
+	EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
+}
+
+bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_version) {
+	ERR_FAIL_NULL_V(openxr_api, false);
+
+	XrSystemId system_id = openxr_api->get_system_id();
+	XrInstance instance = openxr_api->get_instance();
+
+#ifdef ANDROID_ENABLED
+	XrGraphicsRequirementsOpenGLESKHR opengl_requirements;
+	opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
+	opengl_requirements.next = nullptr;
+
+	XrResult result = xrGetOpenGLESGraphicsRequirementsKHR(instance, system_id, &opengl_requirements);
+	if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) {
+		return false;
+	}
+#else
+	XrGraphicsRequirementsOpenGLKHR opengl_requirements;
+	opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
+	opengl_requirements.next = nullptr;
+
+	XrResult result = xrGetOpenGLGraphicsRequirementsKHR(instance, system_id, &opengl_requirements);
+	if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) {
+		return false;
+	}
+#endif
+
+	if (p_desired_version < opengl_requirements.minApiVersionSupported) {
+		print_line("OpenXR: Requested OpenGL version does not meet the minimum version this runtime supports.");
+		print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
+		print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported));
+		print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported));
+		return false;
+	}
+
+	if (p_desired_version > opengl_requirements.maxApiVersionSupported) {
+		print_line("OpenXR: Requested OpenGL version exceeds the maximum version this runtime has been tested on and is known to support.");
+		print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
+		print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported));
+		print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported));
+	}
+
+	return true;
+}
+
+#ifdef WIN32
+XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl;
+#elif ANDROID_ENABLED
+XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl;
+#else
+XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl;
+#endif
+
+void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
+	XrVersion desired_version = XR_MAKE_VERSION(3, 3, 0);
+
+	if (!check_graphics_api_support(desired_version)) {
+		print_line("OpenXR: Trying to initialize with OpenGL anyway...");
+		//return p_next_pointer;
+	}
+
+	DisplayServer *display_server = DisplayServer::get_singleton();
+
+#ifdef WIN32
+	graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR,
+	graphics_binding_gl.next = p_next_pointer;
+
+	graphics_binding_gl.hDC = (HDC)display_server->window_get_native_handle(DisplayServer::WINDOW_VIEW);
+	graphics_binding_gl.hGLRC = (HGLRC)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
+#elif ANDROID_ENABLED
+	graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
+	graphics_binding_gl.next = p_next_pointer;
+
+	graphics_binding_gl.display = eglGetCurrentDisplay();
+	graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122
+	graphics_binding_gl.context = eglGetCurrentContext();
+#else
+	graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
+	graphics_binding_gl.next = p_next_pointer;
+
+	void *display_handle = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE);
+	void *glxcontext_handle = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
+	void *glxdrawable_handle = (void *)display_server->window_get_native_handle(DisplayServer::WINDOW_HANDLE);
+
+	graphics_binding_gl.xDisplay = (Display *)display_handle;
+	graphics_binding_gl.glxContext = (GLXContext)glxcontext_handle;
+	graphics_binding_gl.glxDrawable = (GLXDrawable)glxdrawable_handle;
+
+	if (graphics_binding_gl.xDisplay == nullptr) {
+		print_line("OpenXR Failed to get xDisplay from Godot, using XOpenDisplay(nullptr)");
+		graphics_binding_gl.xDisplay = XOpenDisplay(nullptr);
+	}
+	if (graphics_binding_gl.glxContext == nullptr) {
+		print_line("OpenXR Failed to get glxContext from Godot, using glXGetCurrentContext()");
+		graphics_binding_gl.glxContext = glXGetCurrentContext();
+	}
+	if (graphics_binding_gl.glxDrawable == 0) {
+		print_line("OpenXR Failed to get glxDrawable from Godot, using glXGetCurrentDrawable()");
+		graphics_binding_gl.glxDrawable = glXGetCurrentDrawable();
+	}
+
+	// spec says to use proper values but runtimes don't care
+	graphics_binding_gl.visualid = 0;
+	graphics_binding_gl.glxFBConfig = 0;
+#endif
+
+	return &graphics_binding_gl;
+}
+
+void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
+#ifdef WIN32
+	p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
+	p_usable_swap_chains.push_back(GL_RGBA8);
+#elif ANDROID_ENABLED
+	p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
+	p_usable_swap_chains.push_back(GL_RGBA8);
+#else
+	p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8_EXT);
+	p_usable_swap_chains.push_back(GL_RGBA8_EXT);
+#endif
+}
+
+void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) {
+	p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT32F);
+	p_usable_depth_formats.push_back(GL_DEPTH24_STENCIL8);
+	p_usable_depth_formats.push_back(GL_DEPTH32F_STENCIL8);
+}
+
+bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
+	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+	ERR_FAIL_NULL_V(texture_storage, false);
+
+	uint32_t swapchain_length;
+	XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr);
+	if (XR_FAILED(result)) {
+		print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]");
+		return false;
+	}
+
+#ifdef ANDROID_ENABLED
+	XrSwapchainImageOpenGLESKHR *images = (XrSwapchainImageOpenGLESKHR *)memalloc(sizeof(XrSwapchainImageOpenGLESKHR) * swapchain_length);
+#else
+	XrSwapchainImageOpenGLKHR *images = (XrSwapchainImageOpenGLKHR *)memalloc(sizeof(XrSwapchainImageOpenGLKHR) * swapchain_length);
+#endif
+	ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image");
+
+	for (uint64_t i = 0; i < swapchain_length; i++) {
+#ifdef ANDROID_ENABLED
+		images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
+#else
+		images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
+#endif
+		images[i].next = nullptr;
+		images[i].image = 0;
+	}
+
+	result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
+	if (XR_FAILED(result)) {
+		print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]");
+		memfree(images);
+		return false;
+	}
+
+	SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
+	if (data == nullptr) {
+		print_line("OpenXR: Failed to allocate memory for swapchain data");
+		memfree(images);
+		return false;
+	}
+	*r_swapchain_graphics_data = data;
+	data->is_multiview = (p_array_size > 1);
+
+	Image::Format format = Image::FORMAT_RGBA8;
+
+	Vector<RID> texture_rids;
+
+	for (uint64_t i = 0; i < swapchain_length; i++) {
+		RID texture_rid = texture_storage->texture_create_external(
+				p_array_size == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED,
+				format,
+				images[i].image,
+				p_width,
+				p_height,
+				1,
+				p_array_size);
+
+		texture_rids.push_back(texture_rid);
+	}
+
+	data->texture_rids = texture_rids;
+
+	memfree(images);
+
+	return true;
+}
+
+bool OpenXROpenGLExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
+	XrMatrix4x4f matrix;
+	XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
+
+	for (int j = 0; j < 4; j++) {
+		for (int i = 0; i < 4; i++) {
+			r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i];
+		}
+	}
+
+	return true;
+}
+
+RID OpenXROpenGLExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) {
+	SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
+	ERR_FAIL_NULL_V(data, RID());
+
+	ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID());
+	return data->texture_rids[p_image_index];
+}
+
+void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
+	if (*p_swapchain_graphics_data == nullptr) {
+		return;
+	}
+
+	GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+	ERR_FAIL_NULL(texture_storage);
+
+	SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
+
+	for (int i = 0; i < data->texture_rids.size(); i++) {
+		texture_storage->texture_free(data->texture_rids[i]);
+	}
+	data->texture_rids.clear();
+
+	memdelete(data);
+	*p_swapchain_graphics_data = nullptr;
+}
+
+#define ENUM_TO_STRING_CASE(e) \
+	case e: {                  \
+		return String(#e);     \
+	} break;
+
+String OpenXROpenGLExtension::get_swapchain_format_name(int64_t p_swapchain_format) const {
+	// These are somewhat different per platform, will need to weed some stuff out...
+	switch (p_swapchain_format) {
+#ifdef WIN32
+		// using definitions from GLAD
+		ENUM_TO_STRING_CASE(GL_R8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RG8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGB8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGBA8_SNORM)
+		ENUM_TO_STRING_CASE(GL_R16_SNORM)
+		ENUM_TO_STRING_CASE(GL_RG16_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGB16_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGBA16_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGB4)
+		ENUM_TO_STRING_CASE(GL_RGB5)
+		ENUM_TO_STRING_CASE(GL_RGB8)
+		ENUM_TO_STRING_CASE(GL_RGB10)
+		ENUM_TO_STRING_CASE(GL_RGB12)
+		ENUM_TO_STRING_CASE(GL_RGB16)
+		ENUM_TO_STRING_CASE(GL_RGBA2)
+		ENUM_TO_STRING_CASE(GL_RGBA4)
+		ENUM_TO_STRING_CASE(GL_RGB5_A1)
+		ENUM_TO_STRING_CASE(GL_RGBA8)
+		ENUM_TO_STRING_CASE(GL_RGB10_A2)
+		ENUM_TO_STRING_CASE(GL_RGBA12)
+		ENUM_TO_STRING_CASE(GL_RGBA16)
+		ENUM_TO_STRING_CASE(GL_RGBA32F)
+		ENUM_TO_STRING_CASE(GL_RGB32F)
+		ENUM_TO_STRING_CASE(GL_RGBA16F)
+		ENUM_TO_STRING_CASE(GL_RGB16F)
+		ENUM_TO_STRING_CASE(GL_RGBA32UI)
+		ENUM_TO_STRING_CASE(GL_RGB32UI)
+		ENUM_TO_STRING_CASE(GL_RGBA16UI)
+		ENUM_TO_STRING_CASE(GL_RGB16UI)
+		ENUM_TO_STRING_CASE(GL_RGBA8UI)
+		ENUM_TO_STRING_CASE(GL_RGB8UI)
+		ENUM_TO_STRING_CASE(GL_RGBA32I)
+		ENUM_TO_STRING_CASE(GL_RGB32I)
+		ENUM_TO_STRING_CASE(GL_RGBA16I)
+		ENUM_TO_STRING_CASE(GL_RGB16I)
+		ENUM_TO_STRING_CASE(GL_RGBA8I)
+		ENUM_TO_STRING_CASE(GL_RGB8I)
+		ENUM_TO_STRING_CASE(GL_RGB10_A2UI)
+		ENUM_TO_STRING_CASE(GL_SRGB)
+		ENUM_TO_STRING_CASE(GL_SRGB8)
+		ENUM_TO_STRING_CASE(GL_SRGB_ALPHA)
+		ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32)
+		ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8)
+		ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32F)
+		ENUM_TO_STRING_CASE(GL_DEPTH32F_STENCIL8)
+
+#elif ANDROID_ENABLED
+		// using definitions from GLES3/gl3.h
+
+		ENUM_TO_STRING_CASE(GL_RGBA4)
+		ENUM_TO_STRING_CASE(GL_RGB5_A1)
+		ENUM_TO_STRING_CASE(GL_RGB565)
+		ENUM_TO_STRING_CASE(GL_RGB8)
+		ENUM_TO_STRING_CASE(GL_RGBA8)
+		ENUM_TO_STRING_CASE(GL_RGB10_A2)
+		ENUM_TO_STRING_CASE(GL_RGBA32F)
+		ENUM_TO_STRING_CASE(GL_RGB32F)
+		ENUM_TO_STRING_CASE(GL_RGBA16F)
+		ENUM_TO_STRING_CASE(GL_RGB16F)
+		ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F)
+		ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_10F_11F_11F_REV)
+		ENUM_TO_STRING_CASE(GL_RGB9_E5)
+		ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_5_9_9_9_REV)
+		ENUM_TO_STRING_CASE(GL_RGBA32UI)
+		ENUM_TO_STRING_CASE(GL_RGB32UI)
+		ENUM_TO_STRING_CASE(GL_RGBA16UI)
+		ENUM_TO_STRING_CASE(GL_RGB16UI)
+		ENUM_TO_STRING_CASE(GL_RGBA8UI)
+		ENUM_TO_STRING_CASE(GL_RGB8UI)
+		ENUM_TO_STRING_CASE(GL_RGBA32I)
+		ENUM_TO_STRING_CASE(GL_RGB32I)
+		ENUM_TO_STRING_CASE(GL_RGBA16I)
+		ENUM_TO_STRING_CASE(GL_RGB16I)
+		ENUM_TO_STRING_CASE(GL_RGBA8I)
+		ENUM_TO_STRING_CASE(GL_RGB8I)
+		ENUM_TO_STRING_CASE(GL_RG)
+		ENUM_TO_STRING_CASE(GL_RG_INTEGER)
+		ENUM_TO_STRING_CASE(GL_R8)
+		ENUM_TO_STRING_CASE(GL_RG8)
+		ENUM_TO_STRING_CASE(GL_R16F)
+		ENUM_TO_STRING_CASE(GL_R32F)
+		ENUM_TO_STRING_CASE(GL_RG16F)
+		ENUM_TO_STRING_CASE(GL_RG32F)
+		ENUM_TO_STRING_CASE(GL_R8I)
+		ENUM_TO_STRING_CASE(GL_R8UI)
+		ENUM_TO_STRING_CASE(GL_R16I)
+		ENUM_TO_STRING_CASE(GL_R16UI)
+		ENUM_TO_STRING_CASE(GL_R32I)
+		ENUM_TO_STRING_CASE(GL_R32UI)
+		ENUM_TO_STRING_CASE(GL_RG8I)
+		ENUM_TO_STRING_CASE(GL_RG8UI)
+		ENUM_TO_STRING_CASE(GL_RG16I)
+		ENUM_TO_STRING_CASE(GL_RG16UI)
+		ENUM_TO_STRING_CASE(GL_RG32I)
+		ENUM_TO_STRING_CASE(GL_RG32UI)
+		ENUM_TO_STRING_CASE(GL_R8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RG8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGB8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGBA8_SNORM)
+		ENUM_TO_STRING_CASE(GL_RGB10_A2UI)
+		ENUM_TO_STRING_CASE(GL_SRGB)
+		ENUM_TO_STRING_CASE(GL_SRGB8)
+		ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_R11_EAC)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_R11_EAC)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_RG11_EAC)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_RG11_EAC)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_ETC2)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ETC2)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_RGBA8_ETC2_EAC)
+		ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16)
+		ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24)
+		ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8)
+
+#else
+		// using definitions from GL/gl.h
+		ENUM_TO_STRING_CASE(GL_ALPHA4_EXT)
+		ENUM_TO_STRING_CASE(GL_ALPHA8_EXT)
+		ENUM_TO_STRING_CASE(GL_ALPHA12_EXT)
+		ENUM_TO_STRING_CASE(GL_ALPHA16_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE4_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE8_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE12_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE16_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE4_ALPHA4_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE6_ALPHA2_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE8_ALPHA8_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA4_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA12_EXT)
+		ENUM_TO_STRING_CASE(GL_LUMINANCE16_ALPHA16_EXT)
+		ENUM_TO_STRING_CASE(GL_INTENSITY_EXT)
+		ENUM_TO_STRING_CASE(GL_INTENSITY4_EXT)
+		ENUM_TO_STRING_CASE(GL_INTENSITY8_EXT)
+		ENUM_TO_STRING_CASE(GL_INTENSITY12_EXT)
+		ENUM_TO_STRING_CASE(GL_INTENSITY16_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB2_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB4_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB5_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB8_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB10_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB12_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB16_EXT)
+		ENUM_TO_STRING_CASE(GL_RGBA2_EXT)
+		ENUM_TO_STRING_CASE(GL_RGBA4_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB5_A1_EXT)
+		ENUM_TO_STRING_CASE(GL_RGBA8_EXT)
+		ENUM_TO_STRING_CASE(GL_RGB10_A2_EXT)
+		ENUM_TO_STRING_CASE(GL_RGBA12_EXT)
+		ENUM_TO_STRING_CASE(GL_RGBA16_EXT)
+		ENUM_TO_STRING_CASE(GL_SRGB_EXT)
+		ENUM_TO_STRING_CASE(GL_SRGB8_EXT)
+		ENUM_TO_STRING_CASE(GL_SRGB_ALPHA_EXT)
+		ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8_EXT)
+#endif
+		default: {
+			return String("Swapchain format 0x") + String::num_int64(p_swapchain_format, 16);
+		} break;
+	}
+}
+
+#endif // GLES3_ENABLED

+ 120 - 0
modules/openxr/extensions/openxr_opengl_extension.h

@@ -0,0 +1,120 @@
+/*************************************************************************/
+/*  openxr_opengl_extension.h                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 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.                */
+/*************************************************************************/
+
+#ifndef OPENXR_OPENGL_EXTENSION_H
+#define OPENXR_OPENGL_EXTENSION_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/vector.h"
+#include "openxr_extension_wrapper.h"
+
+#include "../openxr_api.h"
+#include "../util.h"
+
+#ifdef ANDROID_ENABLED
+#define XR_USE_GRAPHICS_API_OPENGL_ES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#define XR_USE_GRAPHICS_API_OPENGL
+#endif
+
+#ifdef WINDOWS_ENABLED
+// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
+// however due to the way the openxr headers are put together, we have no choice.
+#include <windows.h>
+#endif
+
+#ifdef X11_ENABLED
+#include OPENGL_INCLUDE_H
+#define GL_GLEXT_PROTOTYPES 1
+#define GL3_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#endif
+
+#ifdef ANDROID_ENABLED
+// The jobject type from jni.h is used by openxr_platform.h on Android.
+#include <jni.h>
+#endif
+
+// include platform dependent structs
+#include <openxr/openxr_platform.h>
+
+class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
+public:
+	OpenXROpenGLExtension(OpenXRAPI *p_openxr_api);
+	virtual ~OpenXROpenGLExtension() override;
+
+	virtual void on_instance_created(const XrInstance p_instance) override;
+	virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
+
+	virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
+	virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
+	virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
+	virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
+	virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
+	virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
+	virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
+
+private:
+	static OpenXROpenGLExtension *singleton;
+
+#ifdef WIN32
+	static XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl;
+#elif ANDROID_ENABLED
+	static XrGraphicsBindingOpenGLESAndroidKHR graphics_binding_gl;
+#else
+	static XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl;
+#endif
+
+	struct SwapchainGraphicsData {
+		bool is_multiview;
+		Vector<RID> texture_rids;
+	};
+
+	bool check_graphics_api_support(XrVersion p_desired_version);
+
+#ifdef ANDROID_ENABLED
+	EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLESGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLESKHR *), p_graphics_requirements)
+#else
+	EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLKHR *), p_graphics_requirements)
+#endif
+	EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
+};
+
+#endif // GLES3_ENABLED
+
+#endif // OPENXR_OPENGL_EXTENSION_H

+ 32 - 3
modules/openxr/openxr_api.cpp

@@ -45,10 +45,40 @@
 #include "extensions/openxr_android_extension.h"
 #include "extensions/openxr_android_extension.h"
 #endif
 #endif
 
 
+// We need to have all the graphics API defines before the Vulkan or OpenGL
+// extensions are included, otherwise we'll only get one graphics API.
+#ifdef VULKAN_ENABLED
+#define XR_USE_GRAPHICS_API_VULKAN
+#endif
+#ifdef GLES3_ENABLED
+#ifdef ANDROID
+#define XR_USE_GRAPHICS_API_OPENGL_ES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#define XR_USE_GRAPHICS_API_OPENGL
+#endif // ANDROID
+#ifdef X11_ENABLED
+#include OPENGL_INCLUDE_H
+#define GL_GLEXT_PROTOTYPES 1
+#define GL3_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#endif // X11_ENABLED
+#endif // GLES_ENABLED
+
 #ifdef VULKAN_ENABLED
 #ifdef VULKAN_ENABLED
 #include "extensions/openxr_vulkan_extension.h"
 #include "extensions/openxr_vulkan_extension.h"
 #endif
 #endif
 
 
+#ifdef GLES3_ENABLED
+#include "extensions/openxr_opengl_extension.h"
+#endif
+
 #include "extensions/openxr_composition_layer_depth_extension.h"
 #include "extensions/openxr_composition_layer_depth_extension.h"
 #include "extensions/openxr_fb_display_refresh_rate_extension.h"
 #include "extensions/openxr_fb_display_refresh_rate_extension.h"
 #include "extensions/openxr_fb_passthrough_extension_wrapper.h"
 #include "extensions/openxr_fb_passthrough_extension_wrapper.h"
@@ -1142,9 +1172,8 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
 #endif
 #endif
 	} else if (p_rendering_driver == "opengl3") {
 	} else if (p_rendering_driver == "opengl3") {
 #ifdef GLES3_ENABLED
 #ifdef GLES3_ENABLED
-		// graphics_extension = memnew(OpenXROpenGLExtension(this));
-		// register_extension_wrapper(graphics_extension);
-		ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time.");
+		graphics_extension = memnew(OpenXROpenGLExtension(this));
+		register_extension_wrapper(graphics_extension);
 #else
 #else
 		// shouldn't be possible...
 		// shouldn't be possible...
 		ERR_FAIL_V(false);
 		ERR_FAIL_V(false);

+ 5 - 0
platform/android/display_server_android.cpp

@@ -321,6 +321,11 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type,
 		case WINDOW_VIEW: {
 		case WINDOW_VIEW: {
 			return 0; // Not supported.
 			return 0; // Not supported.
 		}
 		}
+#ifdef GLES3_ENABLED
+		case OPENGL_CONTEXT: {
+			return eglGetCurrentContext();
+		}
+#endif
 		default: {
 		default: {
 			return 0;
 			return 0;
 		}
 		}

+ 5 - 0
platform/linuxbsd/x11/display_server_x11.cpp

@@ -1309,6 +1309,11 @@ int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, Win
 		case WINDOW_VIEW: {
 		case WINDOW_VIEW: {
 			return 0; // Not supported.
 			return 0; // Not supported.
 		}
 		}
+#ifdef GLES3_ENABLED
+		case OPENGL_CONTEXT: {
+			return (int64_t)gl_manager->get_glx_context(p_window);
+		}
+#endif
 		default: {
 		default: {
 			return 0;
 			return 0;
 		}
 		}

+ 11 - 0
platform/linuxbsd/x11/gl_manager_x11.cpp

@@ -376,6 +376,17 @@ bool GLManager_X11::is_using_vsync() const {
 	return use_vsync;
 	return use_vsync;
 }
 }
 
 
+void *GLManager_X11::get_glx_context(DisplayServer::WindowID p_window_id) {
+	if (p_window_id == -1) {
+		return nullptr;
+	}
+
+	const GLWindow &win = _windows[p_window_id];
+	const GLDisplay &disp = get_display(win.gldisplay_id);
+
+	return (void *)disp.context->glx_context;
+}
+
 GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) {
 GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) {
 	context_type = p_context_type;
 	context_type = p_context_type;
 
 

+ 2 - 0
platform/linuxbsd/x11/gl_manager_x11.h

@@ -116,6 +116,8 @@ public:
 	void set_use_vsync(bool p_use);
 	void set_use_vsync(bool p_use);
 	bool is_using_vsync() const;
 	bool is_using_vsync() const;
 
 
+	void *get_glx_context(DisplayServer::WindowID p_window_id);
+
 	GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
 	GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
 	~GLManager_X11();
 	~GLManager_X11();
 };
 };

+ 5 - 0
platform/macos/display_server_macos.mm

@@ -2932,6 +2932,11 @@ int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, W
 		case WINDOW_VIEW: {
 		case WINDOW_VIEW: {
 			return (int64_t)windows[p_window].window_view;
 			return (int64_t)windows[p_window].window_view;
 		}
 		}
+#ifdef GLES3_ENABLED
+		case OPENGL_CONTEXT: {
+			return (int64_t)gl_manager->get_context(p_window);
+		}
+#endif
 		default: {
 		default: {
 			return 0;
 			return 0;
 		}
 		}

+ 2 - 0
platform/macos/gl_manager_macos_legacy.h

@@ -89,6 +89,8 @@ public:
 	void set_use_vsync(bool p_use);
 	void set_use_vsync(bool p_use);
 	bool is_using_vsync() const;
 	bool is_using_vsync() const;
 
 
+	NSOpenGLContext *get_context(DisplayServer::WindowID p_window_id);
+
 	GLManager_MacOS(ContextType p_context_type);
 	GLManager_MacOS(ContextType p_context_type);
 	~GLManager_MacOS();
 	~GLManager_MacOS();
 };
 };

+ 9 - 0
platform/macos/gl_manager_macos_legacy.mm

@@ -215,6 +215,15 @@ bool GLManager_MacOS::is_using_vsync() const {
 	return use_vsync;
 	return use_vsync;
 }
 }
 
 
+NSOpenGLContext *GLManager_MacOS::get_context(DisplayServer::WindowID p_window_id) {
+	if (!windows.has(p_window_id)) {
+		return nullptr;
+	}
+
+	GLWindow &win = windows[p_window_id];
+	return win.context;
+}
+
 GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) {
 GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) {
 	context_type = p_context_type;
 	context_type = p_context_type;
 }
 }

+ 6 - 1
platform/windows/display_server_windows.cpp

@@ -741,9 +741,14 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type,
 		case WINDOW_HANDLE: {
 		case WINDOW_HANDLE: {
 			return (int64_t)windows[p_window].hWnd;
 			return (int64_t)windows[p_window].hWnd;
 		}
 		}
+#if defined(GLES3_ENABLED)
 		case WINDOW_VIEW: {
 		case WINDOW_VIEW: {
-			return 0; // Not supported.
+			return (int64_t)gl_manager->get_hdc(p_window);
 		}
 		}
+		case OPENGL_CONTEXT: {
+			return (int64_t)gl_manager->get_hglrc(p_window);
+		}
+#endif
 		default: {
 		default: {
 			return 0;
 			return 0;
 		}
 		}

+ 10 - 0
platform/windows/gl_manager_windows.cpp

@@ -339,6 +339,16 @@ bool GLManager_Windows::is_using_vsync() const {
 	return use_vsync;
 	return use_vsync;
 }
 }
 
 
+HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
+	return get_window(p_window_id).hDC;
+}
+
+HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
+	const GLWindow &win = get_window(p_window_id);
+	const GLDisplay &disp = get_display(win.gldisplay_id);
+	return disp.hRC;
+}
+
 GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
 GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
 	context_type = p_context_type;
 	context_type = p_context_type;
 
 

+ 3 - 0
platform/windows/gl_manager_windows.h

@@ -113,6 +113,9 @@ public:
 	void set_use_vsync(bool p_use);
 	void set_use_vsync(bool p_use);
 	bool is_using_vsync() const;
 	bool is_using_vsync() const;
 
 
+	HDC get_hdc(DisplayServer::WindowID p_window_id);
+	HGLRC get_hglrc(DisplayServer::WindowID p_window_id);
+
 	GLManager_Windows(ContextType p_context_type);
 	GLManager_Windows(ContextType p_context_type);
 	~GLManager_Windows();
 	~GLManager_Windows();
 };
 };

+ 1 - 0
servers/display_server.cpp

@@ -826,6 +826,7 @@ void DisplayServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(DISPLAY_HANDLE);
 	BIND_ENUM_CONSTANT(DISPLAY_HANDLE);
 	BIND_ENUM_CONSTANT(WINDOW_HANDLE);
 	BIND_ENUM_CONSTANT(WINDOW_HANDLE);
 	BIND_ENUM_CONSTANT(WINDOW_VIEW);
 	BIND_ENUM_CONSTANT(WINDOW_VIEW);
+	BIND_ENUM_CONSTANT(OPENGL_CONTEXT);
 
 
 	BIND_ENUM_CONSTANT(TTS_UTTERANCE_STARTED);
 	BIND_ENUM_CONSTANT(TTS_UTTERANCE_STARTED);
 	BIND_ENUM_CONSTANT(TTS_UTTERANCE_ENDED);
 	BIND_ENUM_CONSTANT(TTS_UTTERANCE_ENDED);

+ 1 - 0
servers/display_server.h

@@ -70,6 +70,7 @@ public:
 		DISPLAY_HANDLE,
 		DISPLAY_HANDLE,
 		WINDOW_HANDLE,
 		WINDOW_HANDLE,
 		WINDOW_VIEW,
 		WINDOW_VIEW,
+		OPENGL_CONTEXT,
 	};
 	};
 
 
 	typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, Error &r_error);
 	typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, Error &r_error);