Optimize ANGLE on D3D11 to remove an extra blit
Support the extension EGL_ANGLE_surface_orientation, which allows ANGLE to skip an extra blit from an intermediate buffer to the D3D11 swap chain back buffer for inverting the Y axis due to the difference in coordinate systems. Instead we do our inverting in RasterizerGLES3.
This commit is contained in:
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include "egl_manager.h"
|
#include "egl_manager.h"
|
||||||
|
|
||||||
|
#include "drivers/gles3/rasterizer_gles3.h"
|
||||||
|
|
||||||
#ifdef EGL_ENABLED
|
#ifdef EGL_ENABLED
|
||||||
|
|
||||||
#if defined(EGL_STATIC)
|
#if defined(EGL_STATIC)
|
||||||
@ -51,6 +53,16 @@ extern "C" EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platfo
|
|||||||
#define GLAD_EGL_EXT_platform_base 0
|
#define GLAD_EGL_EXT_platform_base 0
|
||||||
#endif
|
#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.
|
// Creates and caches a GLDisplay. Returns -1 on error.
|
||||||
int EGLManager::_get_gldisplay_id(void *p_display) {
|
int EGLManager::_get_gldisplay_id(void *p_display) {
|
||||||
// Look for a cached GLDisplay.
|
// Look for a cached GLDisplay.
|
||||||
@ -115,6 +127,18 @@ int EGLManager::_get_gldisplay_id(void *p_display) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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);
|
displays.push_back(new_gldisplay);
|
||||||
|
|
||||||
// Return the new GLDisplay's ID.
|
// 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 &glwindow = windows[p_window_id];
|
||||||
glwindow.gldisplay_id = gldisplay_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) {
|
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 {
|
} else {
|
||||||
EGLNativeWindowType *native_window_type = (EGLNativeWindowType *)p_native_window;
|
EGLNativeWindowType *native_window_type = (EGLNativeWindowType *)p_native_window;
|
||||||
glwindow.egl_surface = eglCreateWindowSurface(gldisplay.egl_display, gldisplay.egl_config, *native_window_type, nullptr);
|
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;
|
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);
|
window_make_current(p_window_id);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@ -316,6 +375,10 @@ void EGLManager::window_make_current(DisplayServer::WindowID p_window_id) {
|
|||||||
GLDisplay ¤t_display = displays[current_window->gldisplay_id];
|
GLDisplay ¤t_display = displays[current_window->gldisplay_id];
|
||||||
|
|
||||||
eglMakeCurrent(current_display.egl_display, current_window->egl_surface, current_window->egl_surface, current_display.egl_context);
|
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) {
|
void EGLManager::set_use_vsync(bool p_use) {
|
||||||
|
|||||||
@ -53,11 +53,18 @@ private:
|
|||||||
EGLDisplay egl_display = EGL_NO_DISPLAY;
|
EGLDisplay egl_display = EGL_NO_DISPLAY;
|
||||||
EGLContext egl_context = EGL_NO_CONTEXT;
|
EGLContext egl_context = EGL_NO_CONTEXT;
|
||||||
EGLConfig egl_config = nullptr;
|
EGLConfig egl_config = nullptr;
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
bool has_EGL_ANGLE_surface_orientation = false;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// EGL specific window data.
|
// EGL specific window data.
|
||||||
struct GLWindow {
|
struct GLWindow {
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
bool flipped_y = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// An handle to the GLDisplay associated with this window.
|
// An handle to the GLDisplay associated with this window.
|
||||||
int gldisplay_id = -1;
|
int gldisplay_id = -1;
|
||||||
|
|||||||
@ -82,6 +82,10 @@
|
|||||||
#define strcpy strcpy_s
|
#define strcpy strcpy_s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
bool RasterizerGLES3::screen_flipped_y = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool RasterizerGLES3::gles_over_gl = true;
|
bool RasterizerGLES3::gles_over_gl = true;
|
||||||
|
|
||||||
void RasterizerGLES3::begin_frame(double frame_step) {
|
void RasterizerGLES3::begin_frame(double frame_step) {
|
||||||
@ -380,6 +384,12 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
flip_y = false;
|
flip_y = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
if (screen_flipped_y) {
|
||||||
|
flip_y = !flip_y;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GLuint read_fbo = 0;
|
GLuint read_fbo = 0;
|
||||||
glGenFramebuffers(1, &read_fbo);
|
glGenFramebuffers(1, &read_fbo);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
|
||||||
@ -476,9 +486,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();
|
screenrect.position += ((Size2(win_size.width, win_size.height) - screenrect.size) / 2.0).floor();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flip Y.
|
#ifdef WINDOWS_ENABLED
|
||||||
screenrect.position.y = win_size.y - screenrect.position.y;
|
if (!screen_flipped_y)
|
||||||
screenrect.size.y = -screenrect.size.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.
|
// Normalize texture coordinates to window size.
|
||||||
screenrect.position /= win_size;
|
screenrect.position /= win_size;
|
||||||
|
|||||||
@ -58,6 +58,10 @@ private:
|
|||||||
double time_total = 0.0;
|
double time_total = 0.0;
|
||||||
bool flip_xy_workaround = false;
|
bool flip_xy_workaround = false;
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
static bool screen_flipped_y;
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool gles_over_gl;
|
static bool gles_over_gl;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -117,6 +121,12 @@ public:
|
|||||||
low_end = true;
|
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_ uint64_t get_frame_number() const { return frame; }
|
||||||
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
|
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
|
||||||
_ALWAYS_INLINE_ double get_total_time() const { return time_total; }
|
_ALWAYS_INLINE_ double get_total_time() const { return time_total; }
|
||||||
|
|||||||
Reference in New Issue
Block a user