Преглед изворни кода

Merge pull request #94952 from alvinhochun/angle-d3d11-flip-y

Optimize ANGLE on D3D11 to remove an extra blit
Thaddeus Crews пре 11 месеци
родитељ
комит
16dfaa5e80

+ 64 - 1
drivers/egl/egl_manager.cpp

@@ -30,6 +30,8 @@
 
 #include "egl_manager.h"
 
+#include "drivers/gles3/rasterizer_gles3.h"
+
 #ifdef EGL_ENABLED
 
 #if defined(EGL_STATIC)
@@ -51,6 +53,16 @@ extern "C" EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platfo
 #define GLAD_EGL_EXT_platform_base 0
 #endif
 
+#ifdef WINDOWS_ENABLED
+// Unofficial ANGLE extension: EGL_ANGLE_surface_orientation
+#ifndef EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE
+#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7
+#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8
+#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001
+#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002
+#endif
+#endif
+
 // Creates and caches a GLDisplay. Returns -1 on error.
 int EGLManager::_get_gldisplay_id(void *p_display) {
 	// Look for a cached GLDisplay.
@@ -115,6 +127,18 @@ int EGLManager::_get_gldisplay_id(void *p_display) {
 	}
 #endif
 
+#ifdef WINDOWS_ENABLED
+	String client_extensions_string = eglQueryString(new_gldisplay.egl_display, EGL_EXTENSIONS);
+	if (eglGetError() == EGL_SUCCESS) {
+		Vector<String> egl_extensions = client_extensions_string.split(" ");
+
+		if (egl_extensions.has("EGL_ANGLE_surface_orientation")) {
+			new_gldisplay.has_EGL_ANGLE_surface_orientation = true;
+			print_verbose("EGL: EGL_ANGLE_surface_orientation is supported.");
+		}
+	}
+#endif
+
 	displays.push_back(new_gldisplay);
 
 	// Return the new GLDisplay's ID.
@@ -237,8 +261,29 @@ Error EGLManager::window_create(DisplayServer::WindowID p_window_id, void *p_dis
 	GLWindow &glwindow = windows[p_window_id];
 	glwindow.gldisplay_id = gldisplay_id;
 
+	Vector<EGLAttrib> egl_attribs;
+
+#ifdef WINDOWS_ENABLED
+	if (gldisplay.has_EGL_ANGLE_surface_orientation) {
+		EGLint optimal_orientation;
+		if (eglGetConfigAttrib(gldisplay.egl_display, gldisplay.egl_config, EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE, &optimal_orientation)) {
+			// We only need to support inverting Y for optimizing ANGLE on D3D11.
+			if (optimal_orientation & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE && !(optimal_orientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE)) {
+				egl_attribs.push_back(EGL_SURFACE_ORIENTATION_ANGLE);
+				egl_attribs.push_back(EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
+			}
+		} else {
+			ERR_PRINT(vformat("Failed to get EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE, error: 0x%08X", eglGetError()));
+		}
+	}
+
+	if (!egl_attribs.is_empty()) {
+		egl_attribs.push_back(EGL_NONE);
+	}
+#endif
+
 	if (GLAD_EGL_VERSION_1_5) {
-		glwindow.egl_surface = eglCreatePlatformWindowSurface(gldisplay.egl_display, gldisplay.egl_config, p_native_window, nullptr);
+		glwindow.egl_surface = eglCreatePlatformWindowSurface(gldisplay.egl_display, gldisplay.egl_config, p_native_window, egl_attribs.ptr());
 	} else {
 		EGLNativeWindowType *native_window_type = (EGLNativeWindowType *)p_native_window;
 		glwindow.egl_surface = eglCreateWindowSurface(gldisplay.egl_display, gldisplay.egl_config, *native_window_type, nullptr);
@@ -250,6 +295,20 @@ Error EGLManager::window_create(DisplayServer::WindowID p_window_id, void *p_dis
 
 	glwindow.initialized = true;
 
+#ifdef WINDOWS_ENABLED
+	if (gldisplay.has_EGL_ANGLE_surface_orientation) {
+		EGLint orientation;
+		if (eglQuerySurface(gldisplay.egl_display, glwindow.egl_surface, EGL_SURFACE_ORIENTATION_ANGLE, &orientation)) {
+			if (orientation & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE && !(orientation & EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE)) {
+				glwindow.flipped_y = true;
+				print_verbose("EGL: Using optimal surface orientation: Invert Y");
+			}
+		} else {
+			ERR_PRINT(vformat("Failed to get EGL_SURFACE_ORIENTATION_ANGLE, error: 0x%08X", eglGetError()));
+		}
+	}
+#endif
+
 	window_make_current(p_window_id);
 
 	return OK;
@@ -316,6 +375,10 @@ void EGLManager::window_make_current(DisplayServer::WindowID p_window_id) {
 	GLDisplay &current_display = displays[current_window->gldisplay_id];
 
 	eglMakeCurrent(current_display.egl_display, current_window->egl_surface, current_window->egl_surface, current_display.egl_context);
+
+#ifdef WINDOWS_ENABLED
+	RasterizerGLES3::set_screen_flipped_y(glwindow.flipped_y);
+#endif
 }
 
 void EGLManager::set_use_vsync(bool p_use) {

+ 7 - 0
drivers/egl/egl_manager.h

@@ -53,11 +53,18 @@ private:
 		EGLDisplay egl_display = EGL_NO_DISPLAY;
 		EGLContext egl_context = EGL_NO_CONTEXT;
 		EGLConfig egl_config = nullptr;
+
+#ifdef WINDOWS_ENABLED
+		bool has_EGL_ANGLE_surface_orientation = false;
+#endif
 	};
 
 	// EGL specific window data.
 	struct GLWindow {
 		bool initialized = false;
+#ifdef WINDOWS_ENABLED
+		bool flipped_y = false;
+#endif
 
 		// An handle to the GLDisplay associated with this window.
 		int gldisplay_id = -1;

+ 18 - 3
drivers/gles3/rasterizer_gles3.cpp

@@ -86,6 +86,10 @@
 #define strcpy strcpy_s
 #endif
 
+#ifdef WINDOWS_ENABLED
+bool RasterizerGLES3::screen_flipped_y = false;
+#endif
+
 bool RasterizerGLES3::gles_over_gl = true;
 
 void RasterizerGLES3::begin_frame(double frame_step) {
@@ -389,6 +393,12 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
 		flip_y = false;
 	}
 
+#ifdef WINDOWS_ENABLED
+	if (screen_flipped_y) {
+		flip_y = !flip_y;
+	}
+#endif
+
 	GLuint read_fbo = 0;
 	glGenFramebuffers(1, &read_fbo);
 	glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
@@ -485,9 +495,14 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
 		screenrect.position += ((Size2(win_size.width, win_size.height) - screenrect.size) / 2.0).floor();
 	}
 
-	// Flip Y.
-	screenrect.position.y = win_size.y - screenrect.position.y;
-	screenrect.size.y = -screenrect.size.y;
+#ifdef WINDOWS_ENABLED
+	if (!screen_flipped_y)
+#endif
+	{
+		// Flip Y.
+		screenrect.position.y = win_size.y - screenrect.position.y;
+		screenrect.size.y = -screenrect.size.y;
+	}
 
 	// Normalize texture coordinates to window size.
 	screenrect.position /= win_size;

+ 10 - 0
drivers/gles3/rasterizer_gles3.h

@@ -58,6 +58,10 @@ private:
 	double time_total = 0.0;
 	bool flip_xy_workaround = false;
 
+#ifdef WINDOWS_ENABLED
+	static bool screen_flipped_y;
+#endif
+
 	static bool gles_over_gl;
 
 protected:
@@ -118,6 +122,12 @@ public:
 		low_end = true;
 	}
 
+#ifdef WINDOWS_ENABLED
+	static void set_screen_flipped_y(bool p_flipped) {
+		screen_flipped_y = p_flipped;
+	}
+#endif
+
 	_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
 	_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
 	_ALWAYS_INLINE_ double get_total_time() const { return time_total; }