Add EGL replay implementation

This commit is contained in:
Peter Gal
2017-02-14 18:53:20 +01:00
committed by Baldur Karlsson
parent af6b4cf68c
commit a70bcb8ad3
5 changed files with 454 additions and 9 deletions
+6
View File
@@ -65,6 +65,12 @@ struct GLWindowingData
#include "official/glxext.h"
#endif
#if RENDERDOC_SUPPORT_GLES
// force include the elgplatform.h, as we want to use
// our own because the system one could be a bit older and
// propably not suitable for the given egl.h
#include "official/eglplatform.h"
#include "official/egl.h"
#include "official/eglext.h"
#endif
+290 -9
View File
@@ -27,26 +27,152 @@
#include "gl_driver.h"
#include "gl_resources.h"
typedef EGLBoolean (*PFN_eglBindAPI)(EGLenum api);
typedef EGLDisplay (*PFN_eglGetDisplay)(EGLNativeDisplayType display_id);
typedef EGLContext (*PFN_eglCreateContext)(EGLDisplay dpy, EGLConfig config,
EGLContext share_context, const EGLint *attrib_list);
typedef EGLBoolean (*PFN_eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read,
EGLContext ctx);
typedef EGLBoolean (*PFN_eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (*PFN_eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (*PFN_eglQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute,
EGLint *value);
typedef EGLBoolean (*PFN_eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
typedef EGLSurface (*PFN_eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config,
const EGLint *attrib_list);
typedef EGLSurface (*PFN_eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config,
EGLNativeWindowType win, const EGLint *attrib_list);
typedef EGLBoolean (*PFN_eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef __eglMustCastToProperFunctionPointerType (*PFN_eglGetProcAddress)(const char *procname);
typedef EGLBoolean (*PFN_eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
PFN_eglBindAPI eglBindAPIProc = NULL;
PFN_eglInitialize eglInitializeProc = NULL;
PFN_eglGetDisplay eglGetDisplayProc = NULL;
PFN_eglCreateContext eglCreateContextProc = NULL;
PFN_eglMakeCurrent eglMakeCurrentProc = NULL;
PFN_eglSwapBuffers eglSwapBuffersProc = NULL;
PFN_eglDestroyContext eglDestroyContextProc = NULL;
PFN_eglQuerySurface eglQuerySurfaceProc = NULL;
PFN_eglDestroySurface eglDestroySurfaceProc = NULL;
PFN_eglCreatePbufferSurface eglCreatePbufferSurfaceProc = NULL;
PFN_eglCreateWindowSurface eglCreateWindowSurfaceProc = NULL;
PFN_eglChooseConfig eglChooseConfigProc = NULL;
PFN_eglGetProcAddress eglGetProcAddressProc = NULL;
void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx)
{
// TODO
static GLWindowingData *prev = NULL;
if(eglMakeCurrentProc && ctx && ctx != prev)
{
prev = ctx;
eglMakeCurrentProc(ctx->egl_dpy, ctx->egl_wnd, ctx->egl_wnd, ctx->egl_ctx);
m_pDriver->ActivateContext(*ctx);
}
}
void GLReplay::SwapBuffers(GLWindowingData *ctx)
{
// TODO
eglSwapBuffersProc(ctx->egl_dpy, ctx->egl_wnd);
}
void GLReplay::CloseReplayContext()
{
// TODO
if(eglDestroyContextProc)
{
eglMakeCurrentProc(m_ReplayCtx.egl_dpy, 0L, 0L, NULL);
eglDestroyContextProc(m_ReplayCtx.egl_dpy, m_ReplayCtx.egl_ctx);
}
}
uint64_t GLReplay::MakeOutputWindow(WindowingSystem system, void *data, bool depth)
{
// TODO
EGLNativeWindowType window = 0;
if(system == eWindowingSystem_Xlib)
{
XlibWindowData *xlib = (XlibWindowData *)data;
window = (EGLNativeWindowType)xlib->window;
}
else if(system == eWindowingSystem_Unknown)
{
// allow undefined so that internally we can create a window-less context
Display *dpy = XOpenDisplay(NULL);
if(dpy == NULL)
return 0;
}
else
{
RDCERR("Unexpected window system %u", system);
}
EGLDisplay eglDisplay = eglGetDisplayProc(EGL_DEFAULT_DISPLAY);
RDCASSERT(eglDisplay);
static const EGLint configAttribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES3_BIT,
EGL_SURFACE_TYPE,
EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE};
EGLint numConfigs;
EGLConfig config;
if(!eglChooseConfigProc(eglDisplay, configAttribs, &config, 1, &numConfigs))
{
RDCERR("Couldn't find a suitable EGL config");
return 0;
}
static const EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR,
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL_NONE};
EGLContext ctx = eglCreateContextProc(eglDisplay, config, EGL_NO_CONTEXT, ctxAttribs);
if(ctx == NULL)
{
RDCERR("Couldn't create GL ES context");
return 0;
}
EGLSurface surface = 0;
if(window != 0)
{
surface = eglCreateWindowSurfaceProc(eglDisplay, config, window, NULL);
}
else
{
static const EGLint pbAttribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE};
surface = eglCreatePbufferSurfaceProc(eglDisplay, config, pbAttribs);
}
RDCASSERT(surface != NULL);
OutputWindow win;
win.egl_dpy = eglDisplay;
win.egl_ctx = ctx;
win.egl_wnd = surface;
eglQuerySurfaceProc(eglDisplay, surface, EGL_WIDTH, &win.width);
eglQuerySurfaceProc(eglDisplay, surface, EGL_HEIGHT, &win.height);
MakeCurrentReplayContext(&win);
InitOutputWindow(win);
CreateOutputWindowBackbuffer(win, depth);
uint64_t ret = m_OutputWindowID++;
m_OutputWindows[ret] = win;
return ret;
}
@@ -63,9 +189,10 @@ void GLReplay::DestroyOutputWindow(uint64_t id)
WrappedOpenGL &gl = *m_pDriver;
gl.glDeleteFramebuffers(1, &outw.BlitData.readFBO);
m_OutputWindows.erase(it);
eglMakeCurrentProc(outw.egl_dpy, 0L, 0L, NULL);
eglDestroyContextProc(outw.egl_dpy, outw.egl_ctx);
// TODO
m_OutputWindows.erase(it);
}
void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
@@ -75,7 +202,8 @@ void GLReplay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
OutputWindow &outw = m_OutputWindows[id];
// TODO
eglQuerySurfaceProc(outw.egl_dpy, outw.egl_wnd, EGL_WIDTH, &w);
eglQuerySurfaceProc(outw.egl_dpy, outw.egl_wnd, EGL_HEIGHT, &h);
}
bool GLReplay::IsOutputWindowVisible(uint64_t id)
@@ -94,6 +222,159 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
{
RDCDEBUG("Creating an OpenGL ES replay device");
// TODO
return eReplayCreate_APIInitFailed;
// Query the required EGL functions
if(eglCreateContextProc == NULL)
{
eglGetProcAddressProc = (PFN_eglGetProcAddress)dlsym(RTLD_NEXT, "eglGetProcAddress");
eglChooseConfigProc = (PFN_eglChooseConfig)dlsym(RTLD_NEXT, "eglChooseConfig");
eglInitializeProc = (PFN_eglInitialize)dlsym(RTLD_NEXT, "eglInitialize");
eglBindAPIProc = (PFN_eglBindAPI)dlsym(RTLD_NEXT, "eglBindAPI");
eglGetDisplayProc = (PFN_eglGetDisplay)dlsym(RTLD_NEXT, "eglGetDisplay");
eglCreateContextProc = (PFN_eglCreateContext)dlsym(RTLD_NEXT, "eglCreateContext");
eglMakeCurrentProc = (PFN_eglMakeCurrent)dlsym(RTLD_NEXT, "eglMakeCurrent");
eglSwapBuffersProc = (PFN_eglSwapBuffers)dlsym(RTLD_NEXT, "eglSwapBuffers");
eglDestroyContextProc = (PFN_eglDestroyContext)dlsym(RTLD_NEXT, "eglDestroyContext");
eglDestroySurfaceProc = (PFN_eglDestroySurface)dlsym(RTLD_NEXT, "eglDestroySurface");
eglQuerySurfaceProc = (PFN_eglQuerySurface)dlsym(RTLD_NEXT, "eglQuerySurface");
eglCreatePbufferSurfaceProc =
(PFN_eglCreatePbufferSurface)dlsym(RTLD_NEXT, "eglCreatePbufferSurface");
eglCreateWindowSurfaceProc =
(PFN_eglCreateWindowSurface)dlsym(RTLD_NEXT, "eglCreateWindowSurface");
if(eglGetProcAddressProc == NULL || eglBindAPIProc == NULL || eglGetDisplayProc == NULL ||
eglCreateContextProc == NULL || eglMakeCurrentProc == NULL || eglSwapBuffersProc == NULL ||
eglDestroyContextProc == NULL || eglDestroySurfaceProc == NULL ||
eglQuerySurfaceProc == NULL || eglCreatePbufferSurfaceProc == NULL ||
eglCreateWindowSurfaceProc == NULL || eglChooseConfigProc == NULL)
{
RDCERR(
"Couldn't find required function addresses, eglGetProcAddress eglCreateContext"
"eglSwapBuffers (etc.)");
return eReplayCreate_APIInitFailed;
}
}
GLInitParams initParams;
RDCDriver driverType = RDC_OpenGL;
string driverName = "OpenGL";
uint64_t machineIdent = 0;
if(logfile)
{
auto status = RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, machineIdent,
(RDCInitParams *)&initParams);
if(status != eReplayCreate_Success)
return status;
}
Display *dpy = XOpenDisplay(NULL);
if(dpy == NULL)
{
RDCERR("Couldn't open default X display");
return eReplayCreate_APIInitFailed;
}
eglBindAPIProc(EGL_OPENGL_ES_API);
EGLDisplay eglDisplay = eglGetDisplayProc(EGL_DEFAULT_DISPLAY);
if(!eglDisplay)
{
RDCERR("Couldn't open default EGL display");
return eReplayCreate_APIInitFailed;
}
int major, minor;
eglInitializeProc(eglDisplay, &major, &minor);
static const EGLint configAttribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES3_BIT,
EGL_SURFACE_TYPE,
EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE};
EGLint numConfigs;
EGLConfig config;
if(!eglChooseConfigProc(eglDisplay, configAttribs, &config, 1, &numConfigs))
{
RDCERR("Couldn't find a suitable EGL config");
return eReplayCreate_APIInitFailed;
}
static const EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR,
EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL_NONE};
GLReplay::PreContextInitCounters();
EGLContext ctx = eglCreateContextProc(eglDisplay, config, EGL_NO_CONTEXT, ctxAttribs);
if(ctx == NULL)
{
XCloseDisplay(dpy);
GLReplay::PostContextShutdownCounters();
RDCERR("Couldn't create GL ES 3.x context - RenderDoc requires OpenGL ES 3.x availability");
return eReplayCreate_APIHardwareUnsupported;
}
static const EGLint pbAttribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE};
EGLSurface pbuffer = eglCreatePbufferSurfaceProc(eglDisplay, config, pbAttribs);
if(pbuffer == NULL)
{
RDCERR("Couldn't create a suitable PBuffer");
eglDestroySurfaceProc(eglDisplay, pbuffer);
XCloseDisplay(dpy);
GLReplay::PostContextShutdownCounters();
return eReplayCreate_APIInitFailed;
}
EGLBoolean res = eglMakeCurrentProc(eglDisplay, pbuffer, pbuffer, ctx);
if(!res)
{
RDCERR("Couldn't active the created GL ES context");
eglDestroySurfaceProc(eglDisplay, pbuffer);
eglDestroyContextProc(eglDisplay, ctx);
XCloseDisplay(dpy);
GLReplay::PostContextShutdownCounters();
return eReplayCreate_APIInitFailed;
}
// TODO: add extesion check just like in the GL case.
const GLHookSet &real = GetRealGLFunctionsEGL();
bool extensionsValidated = ValidateFunctionPointers(real);
if(!extensionsValidated)
{
eglDestroySurfaceProc(eglDisplay, pbuffer);
eglDestroyContextProc(eglDisplay, ctx);
XCloseDisplay(dpy);
GLReplay::PostContextShutdownCounters();
return eReplayCreate_APIHardwareUnsupported;
}
WrappedOpenGL *gl = new WrappedOpenGL(logfile, real);
gl->Initialise(initParams);
if(gl->GetSerialiser()->HasError())
{
delete gl;
return eReplayCreate_FileIOFailed;
}
RDCLOG("Created OPEN GL ES replay device.");
GLReplay *replay = gl->GetReplay();
replay->SetProxy(logfile == NULL);
GLWindowingData data;
data.egl_dpy = eglDisplay;
data.egl_ctx = ctx;
data.egl_wnd = pbuffer;
replay->SetReplayData(data);
*driver = (IReplayDriver *)replay;
return eReplayCreate_Success;
}
+133
View File
@@ -0,0 +1,133 @@
#ifndef __eglplatform_h_
#define __eglplatform_h_
/*
** Copyright (c) 2007-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are 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 Materials.
**
** THE MATERIALS ARE 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
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Platform-specific types and definitions for egl.h
* $Revision: 30994 $ on $Date: 2015-04-30 13:36:48 -0700 (Thu, 30 Apr 2015) $
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
* they can be included in future versions of this file. Please submit changes
* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
* by filing a bug against product "EGL" component "Registry".
*/
#include <KHR/khrplatform.h>
/* Macros used in EGL function prototype declarations.
*
* EGL functions should be prototyped as:
*
* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
*
* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
*/
#ifndef EGLAPI
#define EGLAPI KHRONOS_APICALL
#endif
#ifndef EGLAPIENTRY
#define EGLAPIENTRY KHRONOS_APIENTRY
#endif
#define EGLAPIENTRYP EGLAPIENTRY*
/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
* are aliases of window-system-dependent types, such as X Display * or
* Windows Device Context. They must be defined in platform-specific
* code below. The EGL-prefixed versions of Native*Type are the same
* types, renamed in EGL 1.3 so all types in the API start with "EGL".
*
* Khronos STRONGLY RECOMMENDS that you use the default definitions
* provided below, since these changes affect both binary and source
* portability of applications using EGL running on different EGL
* implementations.
*/
#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
#elif defined(__APPLE__) || defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
typedef int EGLNativeDisplayType;
typedef void *EGLNativeWindowType;
typedef void *EGLNativePixmapType;
#elif defined(__ANDROID__) || defined(ANDROID)
#include <android/native_window.h>
struct egl_native_pixmap_t;
typedef struct ANativeWindow* EGLNativeWindowType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
#elif defined(__unix__)
/* X11 (tentative) */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
typedef Display *EGLNativeDisplayType;
typedef Pixmap EGLNativePixmapType;
typedef Window EGLNativeWindowType;
#else
#error "Platform not recognized"
#endif
/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
typedef EGLNativeDisplayType NativeDisplayType;
typedef EGLNativePixmapType NativePixmapType;
typedef EGLNativeWindowType NativeWindowType;
/* Define EGLint. This must be a signed integral type large enough to contain
* all legal attribute names and values passed into and out of EGL, whether
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
* handle, or other. While in general a 32-bit integer will suffice, if
* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
* integer type.
*/
typedef khronos_int32_t EGLint;
/* C++ / C typecast macros for special EGL handle values */
#if defined(__cplusplus)
#define EGL_CAST(type, value) (static_cast<type>(value))
#else
#define EGL_CAST(type, value) ((type) (value))
#endif
#endif /* __eglplatform_h */
+4
View File
@@ -17,6 +17,10 @@ elseif(UNIX)
list(APPEND libraries PRIVATE ${OPENGL_gl_LIBRARY})
endif()
if(ENABLE_GLES)
list(APPEND libraries PRIVATE -lEGL)
endif()
if(ENABLE_XLIB)
list(APPEND libraries PRIVATE -lX11)
endif()
+21
View File
@@ -708,6 +708,14 @@ extern "C" void glXWaitX();
#endif
#if defined(RENDERDOC_SUPPORT_GLES)
// symbol defined in libEGL but not in librenderdoc.
// Forces link of libEGL.
extern "C" int eglWaitGL(void);
#endif
void sig_handler(int signo)
{
if(usingKillSignal)
@@ -726,6 +734,14 @@ int main(int argc, char *argv[])
if(never_run)
glXWaitX();
#endif
#if defined(RENDERDOC_SUPPORT_GLES)
volatile bool never_run = false;
if(never_run)
eglWaitGL();
#endif
signal(SIGINT, sig_handler);
@@ -750,6 +766,11 @@ int main(int argc, char *argv[])
count++;
#endif
#if defined(RENDERDOC_SUPPORT_GLES)
support += "GLES, ";
count++;
#endif
if(count == 0)
{
support += "None.";