mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 16:49:12 +01:00
839df31347
This branch is the final step of fully supporting both OpenGL and OpenGL ES in the same binary. This of course only applies to EGL and won't work for GLX/AGL/WGL since they don't really support GL ES. The changes here actually aren't too terrible, basically change every #ifdef USE_GLES to a runtime check. This adds a DetectMode() function to the EGL context backend. EGL will iterate through each of the configs and check for GL, GLES3_KHR, and GLES2 bits After that it'll change the mode from _DETECT to whichever one is the best supported. After that point we'll just create a context with the mode that was detected
235 lines
6.1 KiB
C++
235 lines
6.1 KiB
C++
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
#include "Host.h"
|
|
#include "RenderBase.h"
|
|
|
|
#include "../GLInterface.h"
|
|
#include "EGL.h"
|
|
|
|
// Show the current FPS
|
|
void cInterfaceEGL::UpdateFPSDisplay(const char *text)
|
|
{
|
|
Platform.UpdateFPSDisplay(text);
|
|
}
|
|
void cInterfaceEGL::Swap()
|
|
{
|
|
eglSwapBuffers(GLWin.egl_dpy, GLWin.egl_surf);
|
|
}
|
|
void cInterfaceEGL::SwapInterval(int Interval)
|
|
{
|
|
eglSwapInterval(GLWin.egl_dpy, Interval);
|
|
}
|
|
|
|
void* cInterfaceEGL::GetProcAddress(std::string name)
|
|
{
|
|
return (void*)eglGetProcAddress(name.c_str());
|
|
}
|
|
|
|
void cInterfaceEGL::DetectMode()
|
|
{
|
|
if (s_opengl_mode != MODE_DETECT)
|
|
return;
|
|
|
|
EGLint num_configs;
|
|
EGLConfig *config = NULL;
|
|
bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
|
|
|
|
// attributes for a visual in RGBA format with at least
|
|
// 8 bits per color
|
|
int attribs[] = {
|
|
EGL_RED_SIZE, 8,
|
|
EGL_GREEN_SIZE, 8,
|
|
EGL_BLUE_SIZE, 8,
|
|
EGL_NONE };
|
|
|
|
// Get how many configs there are
|
|
if (!eglChooseConfig( GLWin.egl_dpy, attribs, NULL, 0, &num_configs)) {
|
|
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
|
|
goto err_exit;
|
|
}
|
|
|
|
config = new EGLConfig[num_configs];
|
|
|
|
// Get all the configurations
|
|
if (!eglChooseConfig(GLWin.egl_dpy, attribs, config, num_configs, &num_configs))
|
|
{
|
|
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
|
|
goto err_exit;
|
|
}
|
|
|
|
for (int i = 0; i < num_configs; ++i)
|
|
{
|
|
EGLint attribVal;
|
|
bool ret;
|
|
ret = eglGetConfigAttrib(GLWin.egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal);
|
|
if (ret)
|
|
{
|
|
if (attribVal & EGL_OPENGL_BIT)
|
|
supportsGL = true;
|
|
if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */
|
|
supportsGLES3 = true;
|
|
if (attribVal & EGL_OPENGL_ES2_BIT)
|
|
supportsGLES2 = true;
|
|
}
|
|
}
|
|
if (supportsGL)
|
|
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
|
else if (supportsGLES3)
|
|
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
|
|
else if (supportsGLES2)
|
|
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
|
|
err_exit:
|
|
if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode
|
|
s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL
|
|
if (config)
|
|
delete[] config;
|
|
}
|
|
|
|
// Create rendering window.
|
|
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
|
bool cInterfaceEGL::Create(void *&window_handle)
|
|
{
|
|
const char *s;
|
|
EGLint egl_major, egl_minor;
|
|
|
|
if(!Platform.SelectDisplay())
|
|
return false;
|
|
|
|
GLWin.egl_dpy = Platform.EGLGetDisplay();
|
|
|
|
if (!GLWin.egl_dpy) {
|
|
INFO_LOG(VIDEO, "Error: eglGetDisplay() failed\n");
|
|
return false;
|
|
}
|
|
|
|
GLWin.platform = Platform.platform;
|
|
|
|
if (!eglInitialize(GLWin.egl_dpy, &egl_major, &egl_minor)) {
|
|
INFO_LOG(VIDEO, "Error: eglInitialize() failed\n");
|
|
return false;
|
|
}
|
|
|
|
/* Detection code */
|
|
EGLConfig config;
|
|
EGLint num_configs;
|
|
|
|
DetectMode();
|
|
|
|
// attributes for a visual in RGBA format with at least
|
|
// 8 bits per color
|
|
int attribs[] = {
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
EGL_RED_SIZE, 8,
|
|
EGL_GREEN_SIZE, 8,
|
|
EGL_BLUE_SIZE, 8,
|
|
EGL_NONE };
|
|
|
|
EGLint ctx_attribs[] = {
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
EGL_NONE
|
|
};
|
|
switch(s_opengl_mode)
|
|
{
|
|
case MODE_OPENGL:
|
|
attribs[1] = EGL_OPENGL_BIT;
|
|
ctx_attribs[0] = EGL_NONE;
|
|
break;
|
|
case MODE_OPENGLES2:
|
|
attribs[1] = EGL_OPENGL_ES2_BIT;
|
|
ctx_attribs[1] = 2;
|
|
break;
|
|
case MODE_OPENGLES3:
|
|
attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */
|
|
ctx_attribs[1] = 3;
|
|
break;
|
|
default:
|
|
ERROR_LOG(VIDEO, "Unknown opengl mode set\n");
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
if (!eglChooseConfig( GLWin.egl_dpy, attribs, &config, 1, &num_configs)) {
|
|
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (s_opengl_mode == MODE_OPENGL)
|
|
eglBindAPI(EGL_OPENGL_API);
|
|
else
|
|
eglBindAPI(EGL_OPENGL_ES_API);
|
|
|
|
|
|
if (!Platform.Init(config))
|
|
return false;
|
|
|
|
s = eglQueryString(GLWin.egl_dpy, EGL_VERSION);
|
|
INFO_LOG(VIDEO, "EGL_VERSION = %s\n", s);
|
|
|
|
s = eglQueryString(GLWin.egl_dpy, EGL_VENDOR);
|
|
INFO_LOG(VIDEO, "EGL_VENDOR = %s\n", s);
|
|
|
|
s = eglQueryString(GLWin.egl_dpy, EGL_EXTENSIONS);
|
|
INFO_LOG(VIDEO, "EGL_EXTENSIONS = %s\n", s);
|
|
|
|
s = eglQueryString(GLWin.egl_dpy, EGL_CLIENT_APIS);
|
|
INFO_LOG(VIDEO, "EGL_CLIENT_APIS = %s\n", s);
|
|
|
|
GLWin.egl_ctx = eglCreateContext(GLWin.egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
|
|
if (!GLWin.egl_ctx) {
|
|
INFO_LOG(VIDEO, "Error: eglCreateContext failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
GLWin.native_window = Platform.CreateWindow();
|
|
|
|
GLWin.egl_surf = eglCreateWindowSurface(GLWin.egl_dpy, config,
|
|
GLWin.native_window, NULL);
|
|
if (!GLWin.egl_surf) {
|
|
INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
Platform.ToggleFullscreen(SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen);
|
|
|
|
window_handle = (void *)GLWin.native_window;
|
|
return true;
|
|
}
|
|
|
|
bool cInterfaceEGL::MakeCurrent()
|
|
{
|
|
return eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx);
|
|
}
|
|
// Close backend
|
|
void cInterfaceEGL::Shutdown()
|
|
{
|
|
Platform.DestroyWindow();
|
|
if (GLWin.egl_ctx && !eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx))
|
|
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
|
if (GLWin.egl_ctx)
|
|
{
|
|
eglMakeCurrent(GLWin.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
if(!eglDestroyContext(GLWin.egl_dpy, GLWin.egl_ctx))
|
|
NOTICE_LOG(VIDEO, "Could not destroy drawing context.");
|
|
if(!eglDestroySurface(GLWin.egl_dpy, GLWin.egl_surf))
|
|
NOTICE_LOG(VIDEO, "Could not destroy window surface.");
|
|
if(!eglTerminate(GLWin.egl_dpy))
|
|
NOTICE_LOG(VIDEO, "Could not destroy display connection.");
|
|
GLWin.egl_ctx = NULL;
|
|
}
|
|
}
|