Implement support for host side multi-window management
This commit is contained in:
parent
c4e1e291ac
commit
fbc8b984f2
23 changed files with 428 additions and 983 deletions
|
|
@ -2,6 +2,7 @@ set(SOURCES
|
|||
ColorBuffer.cpp
|
||||
FbConfig.cpp
|
||||
FrameBuffer.cpp
|
||||
LayerManager.cpp
|
||||
NativeSubWindow_delegate.cpp
|
||||
ReadBuffer.cpp
|
||||
RenderContext.cpp
|
||||
|
|
@ -9,7 +10,7 @@ set(SOURCES
|
|||
RenderServer.cpp
|
||||
RenderThread.cpp
|
||||
RenderThreadInfo.cpp
|
||||
render_api.cpp
|
||||
RenderApi.cpp
|
||||
RenderWindow.cpp
|
||||
SocketStream.cpp
|
||||
TcpStream.cpp
|
||||
|
|
|
|||
|
|
@ -154,9 +154,6 @@ static char* getGLES1ExtensionString(EGLDisplay p_dpy)
|
|||
|
||||
void FrameBuffer::finalize(){
|
||||
m_colorbuffers.clear();
|
||||
if (m_useSubWindow) {
|
||||
removeSubWindow();
|
||||
}
|
||||
m_windows.clear();
|
||||
m_contexts.clear();
|
||||
s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
|
||||
|
|
@ -431,32 +428,19 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int
|
|||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow) :
|
||||
m_framebufferWidth(p_width),
|
||||
m_framebufferHeight(p_height),
|
||||
m_windowWidth(p_width),
|
||||
m_windowHeight(p_height),
|
||||
m_useSubWindow(useSubWindow),
|
||||
m_configs(NULL),
|
||||
m_eglDisplay(EGL_NO_DISPLAY),
|
||||
m_colorBufferHelper(new ColorBufferHelper(this)),
|
||||
m_eglSurface(EGL_NO_SURFACE),
|
||||
m_eglContext(EGL_NO_CONTEXT),
|
||||
m_pbufContext(EGL_NO_CONTEXT),
|
||||
m_prevContext(EGL_NO_CONTEXT),
|
||||
m_prevReadSurf(EGL_NO_SURFACE),
|
||||
m_prevDrawSurf(EGL_NO_SURFACE),
|
||||
m_subWin((EGLNativeWindowType)0),
|
||||
m_textureDraw(NULL),
|
||||
m_lastPostedColorBuffer(0),
|
||||
m_zRot(0.0f),
|
||||
m_px(0),
|
||||
m_py(0),
|
||||
m_eglContextInitialized(false),
|
||||
m_statsNumFrames(0),
|
||||
m_statsStartTime(0LL),
|
||||
m_onPost(NULL),
|
||||
m_onPostContext(NULL),
|
||||
m_fbImage(NULL),
|
||||
m_glVendor(NULL),
|
||||
m_glRenderer(NULL),
|
||||
m_glVersion(NULL)
|
||||
|
|
@ -468,147 +452,68 @@ FrameBuffer::~FrameBuffer() {
|
|||
delete m_textureDraw;
|
||||
delete m_configs;
|
||||
delete m_colorBufferHelper;
|
||||
free(m_fbImage);
|
||||
}
|
||||
|
||||
void FrameBuffer::setPostCallback(OnPostFn onPost, void* onPostContext)
|
||||
{
|
||||
emugl::Mutex::AutoLock mutex(m_lock);
|
||||
m_onPost = onPost;
|
||||
m_onPostContext = onPostContext;
|
||||
if (m_onPost && !m_fbImage) {
|
||||
m_fbImage = (unsigned char*)malloc(4 * m_framebufferWidth * m_framebufferHeight);
|
||||
if (!m_fbImage) {
|
||||
ERR("out of memory, cancelling OnPost callback");
|
||||
m_onPost = NULL;
|
||||
m_onPostContext = NULL;
|
||||
return;
|
||||
}
|
||||
struct FrameBufferWindow {
|
||||
EGLNativeWindowType native_window = 0;
|
||||
EGLSurface surface = EGL_NO_SURFACE;
|
||||
};
|
||||
|
||||
FrameBufferWindow* FrameBuffer::createWindow(int x, int y, int width, int height) {
|
||||
m_lock.lock();
|
||||
|
||||
auto native_window = createSubWindow(0, x, y, width, height);
|
||||
if (!native_window) {
|
||||
m_lock.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void subWindowRepaint(void* param) {
|
||||
auto fb = static_cast<FrameBuffer*>(param);
|
||||
fb->repost();
|
||||
}
|
||||
auto window = new FrameBufferWindow;
|
||||
window->native_window = native_window;
|
||||
|
||||
bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
|
||||
int wx,
|
||||
int wy,
|
||||
int ww,
|
||||
int wh,
|
||||
int fbw,
|
||||
int fbh,
|
||||
float dpr,
|
||||
float zRot) {
|
||||
bool success = false;
|
||||
|
||||
if (!m_useSubWindow) {
|
||||
ERR("%s: Cannot create native sub-window in this configuration\n",
|
||||
__FUNCTION__);
|
||||
return false;
|
||||
window->surface = s_egl.eglCreateWindowSurface(
|
||||
m_eglDisplay, m_eglConfig, window->native_window, nullptr);
|
||||
if (window->surface == EGL_NO_SURFACE) {
|
||||
destroyWindow(window);
|
||||
m_lock.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!bindWindow_locked(window)) {
|
||||
destroyWindow(window);
|
||||
m_lock.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
s_gles2.glViewport(0, 0, width, height);
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
||||
GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
s_egl.eglSwapBuffers(m_eglDisplay, window->surface);
|
||||
|
||||
unbind_locked();
|
||||
|
||||
m_lock.unlock();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void FrameBuffer::destroyWindow(FrameBufferWindow *window) {
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
m_lock.lock();
|
||||
|
||||
// If the subwindow doesn't exist, create it with the appropriate dimensions
|
||||
if (!m_subWin) {
|
||||
s_egl.eglMakeCurrent(m_eglDisplay, nullptr, nullptr, nullptr);
|
||||
|
||||
// Create native subwindow for FB display output
|
||||
m_x = wx;
|
||||
m_y = wy;
|
||||
m_windowWidth = ww;
|
||||
m_windowHeight = wh;
|
||||
if (window->surface != EGL_NO_SURFACE)
|
||||
s_egl.eglDestroySurface(m_eglDisplay, window->surface);
|
||||
|
||||
m_subWin = createSubWindow(p_window, m_x, m_y,
|
||||
m_windowWidth, m_windowHeight, subWindowRepaint, this);
|
||||
if (m_subWin) {
|
||||
m_nativeWindow = p_window;
|
||||
destroySubWindow(window->native_window);
|
||||
|
||||
// create EGLSurface from the generated subwindow
|
||||
m_eglSurface = s_egl.eglCreateWindowSurface(m_eglDisplay,
|
||||
m_eglConfig,
|
||||
m_subWin,
|
||||
NULL);
|
||||
|
||||
if (m_eglSurface == EGL_NO_SURFACE) {
|
||||
// NOTE: This can typically happen with software-only renderers like OSMesa.
|
||||
destroySubWindow(m_subWin);
|
||||
m_subWin = (EGLNativeWindowType)0;
|
||||
} else {
|
||||
m_px = 0;
|
||||
m_py = 0;
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, if the subwindow doesn't exist, it is because it either couldn't be created
|
||||
// in the first place or the EGLSurface couldn't be created.
|
||||
if (m_subWin && bindSubwin_locked()) {
|
||||
|
||||
// Only attempt to update window geometry if anything has actually changed.
|
||||
if (!(m_x == wx &&
|
||||
m_y == wy &&
|
||||
m_windowWidth == ww &&
|
||||
m_windowHeight == wh)) {
|
||||
|
||||
m_x = wx;
|
||||
m_y = wy;
|
||||
m_windowWidth = ww;
|
||||
m_windowHeight = wh;
|
||||
|
||||
success = ::moveSubWindow(m_nativeWindow, m_subWin,
|
||||
m_x, m_y, m_windowWidth, m_windowHeight);
|
||||
|
||||
// Otherwise, ensure that at least viewport parameters are properly updated.
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// Subwin creation or movement was successful,
|
||||
// update viewport and z rotation and draw
|
||||
// the last posted color buffer.
|
||||
s_gles2.glViewport(0, 0, fbw * dpr, fbh * dpr);
|
||||
m_dpr = dpr;
|
||||
m_zRot = zRot;
|
||||
if (m_lastPostedColorBuffer) {
|
||||
post(m_lastPostedColorBuffer, false);
|
||||
} else {
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
||||
GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
|
||||
}
|
||||
}
|
||||
unbind_locked();
|
||||
}
|
||||
delete window;
|
||||
|
||||
m_lock.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool FrameBuffer::removeSubWindow() {
|
||||
if (!m_useSubWindow) {
|
||||
ERR("%s: Cannot remove native sub-window in this configuration\n",
|
||||
__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
bool removed = false;
|
||||
m_lock.lock();
|
||||
if (m_subWin) {
|
||||
s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
|
||||
s_egl.eglDestroySurface(m_eglDisplay, m_eglSurface);
|
||||
destroySubWindow(m_subWin);
|
||||
|
||||
m_eglSurface = EGL_NO_SURFACE;
|
||||
m_subWin = (EGLNativeWindowType)0;
|
||||
removed = true;
|
||||
}
|
||||
m_lock.unlock();
|
||||
return removed;
|
||||
}
|
||||
|
||||
HandleType FrameBuffer::genHandle()
|
||||
|
|
@ -1021,25 +926,18 @@ bool FrameBuffer::bind_locked()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FrameBuffer::bindSubwin_locked()
|
||||
bool FrameBuffer::bindWindow_locked(FrameBufferWindow *window)
|
||||
{
|
||||
EGLContext prevContext = s_egl.eglGetCurrentContext();
|
||||
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
|
||||
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
|
||||
|
||||
if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
|
||||
m_eglSurface, m_eglContext)) {
|
||||
if (!s_egl.eglMakeCurrent(m_eglDisplay, window->surface,
|
||||
window->surface, m_eglContext)) {
|
||||
ERR("eglMakeCurrent failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// initialize GL state in eglContext if not yet initilaized
|
||||
//
|
||||
if (!m_eglContextInitialized) {
|
||||
m_eglContextInitialized = true;
|
||||
}
|
||||
|
||||
m_prevContext = prevContext;
|
||||
m_prevReadSurf = prevReadSurf;
|
||||
m_prevDrawSurf = prevDrawSurf;
|
||||
|
|
@ -1059,64 +957,37 @@ bool FrameBuffer::unbind_locked()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
|
||||
bool FrameBuffer::post(FrameBufferWindow *window, HandleType p_colorbuffer, bool needLock)
|
||||
{
|
||||
if (needLock) {
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
printf("%s window %p\n", __func__, window);
|
||||
|
||||
if (needLock)
|
||||
m_lock.lock();
|
||||
}
|
||||
bool ret = false;
|
||||
|
||||
bool ret;
|
||||
|
||||
ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
|
||||
if (c == m_colorbuffers.end()) {
|
||||
if (c == m_colorbuffers.end())
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
m_lastPostedColorBuffer = p_colorbuffer;
|
||||
|
||||
if (m_subWin) {
|
||||
// bind the subwindow eglSurface
|
||||
if (!bindSubwin_locked()) {
|
||||
ERR("FrameBuffer::post(): eglMakeCurrent failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
if (!bindWindow_locked(window))
|
||||
goto EXIT;
|
||||
|
||||
// get the viewport
|
||||
GLint vp[4];
|
||||
s_gles2.glGetIntegerv(GL_VIEWPORT, vp);
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// divide by device pixel ratio because windowing coordinates ignore DPR,
|
||||
// but the framebuffer includes DPR
|
||||
vp[2] = vp[2] / m_dpr;
|
||||
vp[3] = vp[3] / m_dpr;
|
||||
|
||||
// find the x and y values at the origin when "fully scrolled"
|
||||
// multiply by 2 because the texture goes from -1 to 1, not 0 to 1
|
||||
float fx = 2.f * (vp[2] - m_windowWidth) / (float) vp[2];
|
||||
float fy = 2.f * (vp[3] - m_windowHeight) / (float) vp[3];
|
||||
|
||||
// finally, compute translation values
|
||||
float dx = m_px * fx;
|
||||
float dy = m_py * fy;
|
||||
|
||||
//
|
||||
// render the color buffer to the window
|
||||
//
|
||||
if (m_zRot != 0.0f) {
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ret = (*c).second.cb->post(m_zRot, dx, dy);
|
||||
if (ret) {
|
||||
s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
|
||||
}
|
||||
|
||||
// restore previous binding
|
||||
unbind_locked();
|
||||
} else {
|
||||
// If there is no sub-window, don't display anything, the client will
|
||||
// rely on m_onPost to get the pixels instead.
|
||||
ret = true;
|
||||
ret = (*c).second.cb->post(0.0f, 0, 0);
|
||||
if (ret) {
|
||||
s_egl.eglSwapBuffers(m_eglDisplay, window->surface);
|
||||
}
|
||||
|
||||
// restore previous binding
|
||||
unbind_locked();
|
||||
|
||||
//
|
||||
// output FPS statistics
|
||||
//
|
||||
|
|
@ -1131,30 +1002,12 @@ bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Send framebuffer (without FPS overlay) to callback
|
||||
//
|
||||
if (m_onPost) {
|
||||
(*c).second.cb->readback(m_fbImage);
|
||||
m_onPost(m_onPostContext,
|
||||
m_framebufferWidth,
|
||||
m_framebufferHeight,
|
||||
-1,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
m_fbImage);
|
||||
}
|
||||
|
||||
EXIT:
|
||||
if (!ret)
|
||||
printf("post: FAILED\n");
|
||||
|
||||
if (needLock) {
|
||||
m_lock.unlock();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FrameBuffer::repost() {
|
||||
if (m_lastPostedColorBuffer) {
|
||||
return post(m_lastPostedColorBuffer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ struct FrameBufferCaps {
|
|||
EGLint eglMinor;
|
||||
};
|
||||
|
||||
struct FrameBufferWindow;
|
||||
|
||||
// The FrameBuffer class holds the global state of the emulation library on
|
||||
// top of the underlying EGL/GLES implementation. It should probably be
|
||||
// named "Display" instead of "FrameBuffer".
|
||||
|
|
@ -76,32 +78,8 @@ public:
|
|||
// Returns true on success, false otherwise.
|
||||
static bool initialize(EGLNativeDisplayType nativeDisplay, int width, int height, bool useSubWindow);
|
||||
|
||||
// Setup a sub-window to display the content of the emulated GPU
|
||||
// on-top of an existing UI window. |p_window| is the platform-specific
|
||||
// parent window handle. |wx|, |wy|, |ww| and |wh| are the
|
||||
// dimensions in pixels of the sub-window, relative to the parent window's
|
||||
// coordinate. |fbw| and |fbh| are the dimensions used to initialize
|
||||
// the framebuffer, which may be different from the dimensions of the
|
||||
// sub-window (in which case scaling will be applied automatically).
|
||||
// |dpr| is the device pixel ratio of the monitor, which is needed for
|
||||
// proper panning on high-density displays (like retina)
|
||||
// |zRot| is a rotation angle in degrees, (clockwise in the Y-upwards GL
|
||||
// coordinate space).
|
||||
//
|
||||
// If a sub-window already exists, this function updates the subwindow
|
||||
// and framebuffer properties to match the given values.
|
||||
//
|
||||
// Return true on success, false otherwise.
|
||||
//
|
||||
// NOTE: This can return false for software-only EGL engines like OSMesa.
|
||||
bool setupSubWindow(FBNativeWindowType p_window,
|
||||
int wx, int wy,
|
||||
int ww, int wh,
|
||||
int fbw, int fbh, float dpr, float zRot);
|
||||
|
||||
// Remove the sub-window created by setupSubWindow(), if any.
|
||||
// Return true on success, false otherwise.
|
||||
bool removeSubWindow();
|
||||
FrameBufferWindow* createWindow(int x, int y, int width, int height);
|
||||
void destroyWindow(FrameBufferWindow *window);
|
||||
|
||||
// Finalize the instance.
|
||||
void finalize();
|
||||
|
|
@ -113,12 +91,6 @@ public:
|
|||
// Return the capabilities of the underlying display.
|
||||
const FrameBufferCaps &getCaps() const { return m_caps; }
|
||||
|
||||
// Return the emulated GPU display width in pixels.
|
||||
int getWidth() const { return m_framebufferWidth; }
|
||||
|
||||
// Return the emulated GPU display height in pixels.
|
||||
int getHeight() const { return m_framebufferHeight; }
|
||||
|
||||
// Return the list of configs available from this display.
|
||||
const FbConfigList* getConfigs() const { return m_configs; }
|
||||
|
||||
|
|
@ -259,36 +231,11 @@ public:
|
|||
// |needLock| is used to indicate whether the operation requires
|
||||
// acquiring/releasing the FrameBuffer instance's lock. It should be
|
||||
// false only when called internally.
|
||||
bool post(HandleType p_colorbuffer, bool needLock = true);
|
||||
|
||||
// Re-post the last ColorBuffer that was displayed through post().
|
||||
// This is useful if you detect that the sub-window content needs to
|
||||
// be re-displayed for any reason.
|
||||
bool repost();
|
||||
bool post(FrameBufferWindow *window, HandleType p_colorbuffer, bool needLock = true);
|
||||
|
||||
// Return the host EGLDisplay used by this instance.
|
||||
EGLDisplay getDisplay() const { return m_eglDisplay; }
|
||||
|
||||
// Change the rotation of the displayed GPU sub-window.
|
||||
void setDisplayRotation(float zRot) {
|
||||
m_zRot = zRot;
|
||||
repost();
|
||||
}
|
||||
|
||||
// Changes what coordinate of this framebuffer will be displayed at the
|
||||
// corner of the GPU sub-window. Specifically, |px| and |py| = 0 means
|
||||
// align the bottom-left of the framebuffer with the bottom-left of the
|
||||
// sub-window, and |px| and |py| = 1 means align the top right of the
|
||||
// framebuffer with the top right of the sub-window. Intermediate values
|
||||
// interpolate between these states.
|
||||
void setDisplayTranslation(float px, float py) {
|
||||
|
||||
// Sanity check the values to ensure they are between 0 and 1
|
||||
m_px = px > 1 ? 1 : (px < 0 ? 0 : px);
|
||||
m_py = py > 1 ? 1 : (py < 0 ? 0 : py);
|
||||
repost();
|
||||
}
|
||||
|
||||
// Return a TextureDraw instance that can be used with this surfaces
|
||||
// and windows created by this instance.
|
||||
TextureDraw* getTextureDraw() const { return m_textureDraw; }
|
||||
|
|
@ -305,18 +252,11 @@ private:
|
|||
~FrameBuffer();
|
||||
HandleType genHandle();
|
||||
|
||||
bool bindSubwin_locked();
|
||||
bool bindWindow_locked(FrameBufferWindow *window);
|
||||
|
||||
private:
|
||||
static FrameBuffer *s_theFrameBuffer;
|
||||
static HandleType s_nextHandle;
|
||||
int m_x;
|
||||
int m_y;
|
||||
int m_framebufferWidth;
|
||||
int m_framebufferHeight;
|
||||
int m_windowWidth;
|
||||
int m_windowHeight;
|
||||
float m_dpr;
|
||||
bool m_useSubWindow;
|
||||
emugl::Mutex m_lock;
|
||||
FbConfigList* m_configs;
|
||||
|
|
@ -328,7 +268,6 @@ private:
|
|||
ColorBufferMap m_colorbuffers;
|
||||
ColorBuffer::Helper* m_colorBufferHelper;
|
||||
|
||||
EGLSurface m_eglSurface;
|
||||
EGLContext m_eglContext;
|
||||
EGLSurface m_pbufSurface;
|
||||
EGLContext m_pbufContext;
|
||||
|
|
@ -336,23 +275,14 @@ private:
|
|||
EGLContext m_prevContext;
|
||||
EGLSurface m_prevReadSurf;
|
||||
EGLSurface m_prevDrawSurf;
|
||||
EGLNativeWindowType m_subWin;
|
||||
TextureDraw* m_textureDraw;
|
||||
EGLConfig m_eglConfig;
|
||||
HandleType m_lastPostedColorBuffer;
|
||||
float m_zRot;
|
||||
float m_px;
|
||||
float m_py;
|
||||
bool m_eglContextInitialized;
|
||||
|
||||
int m_statsNumFrames;
|
||||
long long m_statsStartTime;
|
||||
bool m_fpsStats;
|
||||
|
||||
OnPostFn m_onPost;
|
||||
void* m_onPostContext;
|
||||
unsigned char* m_fbImage;
|
||||
|
||||
const char* m_glVendor;
|
||||
const char* m_glRenderer;
|
||||
const char* m_glVersion;
|
||||
|
|
|
|||
92
external/android-emugl/host/libs/libOpenglRender/LayerManager.cpp
vendored
Normal file
92
external/android-emugl/host/libs/libOpenglRender/LayerManager.cpp
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "LayerManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
std::string get_package_name(const std::string &name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
bool is_layer_blacklisted(const std::string &name) {
|
||||
static std::vector<std::string> blacklist = {
|
||||
"BootAnimation",
|
||||
"StatusBar",
|
||||
"Sprite",
|
||||
"KeyguardScrim",
|
||||
"com.android.launcher/com.android.launcher2.Launcher",
|
||||
"com.android.settings/com.android.settings.FallbackHome",
|
||||
"com.android.systemui.ImageWallpaper",
|
||||
"InputMethod",
|
||||
};
|
||||
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<LayerManager> LayerManager::get() {
|
||||
static auto self = std::shared_ptr<LayerManager>{new LayerManager};
|
||||
return self;
|
||||
}
|
||||
|
||||
LayerManager::LayerManager() {
|
||||
}
|
||||
|
||||
LayerManager::~LayerManager() {
|
||||
}
|
||||
|
||||
void LayerManager::post_layer(const LayerInfo &layer) {
|
||||
if (is_layer_blacklisted(layer.name)) {
|
||||
printf("Ignoring blacklisted layer '%s'\n", layer.name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
FrameBufferWindow *window = nullptr;
|
||||
auto l = layers_.find(layer.name);
|
||||
if (l != layers_.end()) {
|
||||
printf("Using existing layer '%s'\n", layer.name.c_str());
|
||||
window = l->second.window;
|
||||
l->second.updated = true;
|
||||
}
|
||||
else {
|
||||
printf("New layer '%s' {%d,%d,%d,%d}\n", layer.name.c_str());
|
||||
window = FrameBuffer::getFB()->createWindow(
|
||||
layer.display_frame.left,
|
||||
layer.display_frame.top,
|
||||
layer.display_frame.right,
|
||||
layer.display_frame.bottom);
|
||||
if (!window) {
|
||||
printf("Failed to create window for layer '%s'\n", layer.name.c_str());
|
||||
return;
|
||||
}
|
||||
layers_.insert({ layer.name, Layer{window, true}});
|
||||
}
|
||||
|
||||
printf("%s: window %p buffer %d\n", __func__, window, layer.buffer_handle);
|
||||
|
||||
FrameBuffer::getFB()->post(window, layer.buffer_handle);
|
||||
}
|
||||
|
||||
void LayerManager::finish_cycle() {
|
||||
for (auto iter = layers_.begin(); iter != layers_.end(); ++iter) {
|
||||
if (!iter->second.updated) {
|
||||
FrameBuffer::getFB()->destroyWindow(iter->second.window);
|
||||
layers_.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
external/android-emugl/host/libs/libOpenglRender/LayerManager.h
vendored
Normal file
63
external/android-emugl/host/libs/libOpenglRender/LayerManager.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAYER_MANAGER_H_
|
||||
#define LAYER_MANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "FrameBuffer.h"
|
||||
|
||||
struct LayerRect {
|
||||
int top;
|
||||
int left;
|
||||
int right;
|
||||
int bottom;
|
||||
};
|
||||
|
||||
struct LayerInfo {
|
||||
std::string name;
|
||||
LayerRect source_crop;
|
||||
LayerRect display_frame;
|
||||
HandleType buffer_handle;
|
||||
};
|
||||
|
||||
class LayerManager {
|
||||
public:
|
||||
static std::shared_ptr<LayerManager> get();
|
||||
|
||||
~LayerManager();
|
||||
|
||||
void post_layer(const LayerInfo &layer);
|
||||
void finish_cycle();
|
||||
|
||||
private:
|
||||
LayerManager();
|
||||
|
||||
struct Layer {
|
||||
FrameBufferWindow *window;
|
||||
bool updated;
|
||||
};
|
||||
|
||||
std::map<std::string,Layer> layers_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -35,8 +35,6 @@ public:
|
|||
|
||||
void registerSubWindowHandler(const std::shared_ptr<SubWindowHandler> &handler);
|
||||
|
||||
typedef void (*SubWindowRepaintCallback)(void*);
|
||||
|
||||
// Create a new sub-window that will be used to display the content of the
|
||||
// emulated GPU on top of the regular UI window.
|
||||
// |p_window| is the platform-specific handle to the main UI window.
|
||||
|
|
@ -55,25 +53,11 @@ EGLNativeWindowType createSubWindow(FBNativeWindowType p_window,
|
|||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
SubWindowRepaintCallback repaint_callback,
|
||||
void* repaint_callback_param);
|
||||
int height);
|
||||
|
||||
// Destroy a sub-window previously created through createSubWindow() above.
|
||||
void destroySubWindow(EGLNativeWindowType win);
|
||||
|
||||
// Moves a sub-window previously created through createSubWindow() above.
|
||||
// |p_parent_window| is the platform-specific handle to the main UI window.
|
||||
// |p_sub_window| is the platform-specific handle to the EGL subwindow.
|
||||
// |x|,|y|,|width|,|height| are the new location and dimensions of the
|
||||
// subwindow.
|
||||
int moveSubWindow(FBNativeWindowType p_parent_window,
|
||||
EGLNativeWindowType p_sub_window,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,12 +35,8 @@ EGLNativeWindowType createSubWindow(FBNativeWindowType p_window,
|
|||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
SubWindowRepaintCallback repaint_callback,
|
||||
void* repaint_callback_param) {
|
||||
int height) {
|
||||
(void) p_window;
|
||||
(void) repaint_callback;
|
||||
(void) repaint_callback_param;
|
||||
|
||||
if (!current_handler)
|
||||
return (EGLNativeWindowType) 0;
|
||||
|
|
@ -54,19 +50,3 @@ void destroySubWindow(EGLNativeWindowType win) {
|
|||
|
||||
return current_handler->destroy_window(win);
|
||||
}
|
||||
|
||||
int moveSubWindow(FBNativeWindowType p_parent_window,
|
||||
EGLNativeWindowType p_sub_window,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
(void) p_parent_window;
|
||||
(void) p_sub_window;
|
||||
(void) x;
|
||||
(void) y;
|
||||
(void) width;
|
||||
(void) height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,7 @@
|
|||
#include "TimeUtils.h"
|
||||
|
||||
#include "TcpStream.h"
|
||||
#ifdef _WIN32
|
||||
#include "Win32PipeStream.h"
|
||||
#else
|
||||
#include "UnixStream.h"
|
||||
#endif
|
||||
|
||||
#include "DispatchTables.h"
|
||||
|
||||
|
|
@ -142,15 +138,6 @@ RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer(
|
|||
return true;
|
||||
}
|
||||
|
||||
RENDER_APICALL void RENDER_APIENTRY setPostCallback(
|
||||
OnPostFn onPost, void* onPostContext) {
|
||||
if (s_renderWindow) {
|
||||
s_renderWindow->setPostCallback(onPost, onPostContext);
|
||||
} else {
|
||||
ERR("Calling setPostCallback() before creating render window!");
|
||||
}
|
||||
}
|
||||
|
||||
RENDER_APICALL void RENDER_APIENTRY getHardwareStrings(
|
||||
const char** vendor,
|
||||
const char** renderer,
|
||||
|
|
@ -228,53 +215,7 @@ RENDER_APICALL bool RENDER_APIENTRY destroyOpenGLSubwindow(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
RENDER_APICALL void RENDER_APIENTRY setOpenGLDisplayRotation(float zRot)
|
||||
{
|
||||
RenderWindow* window = s_renderWindow;
|
||||
|
||||
if (window) {
|
||||
window->setRotation(zRot);
|
||||
return;
|
||||
}
|
||||
// XXX: should be implemented by sending the renderer process
|
||||
// a request
|
||||
ERR("%s not implemented for separate renderer process !!!\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
RENDER_APICALL void RENDER_APIENTRY setOpenGLDisplayTranslation(float px, float py)
|
||||
{
|
||||
RenderWindow* window = s_renderWindow;
|
||||
|
||||
if (window) {
|
||||
window->setTranslation(px, py);
|
||||
return;
|
||||
}
|
||||
// XXX: should be implemented by sending the renderer process
|
||||
// a request
|
||||
ERR("%s not implemented for separate renderer process !!!\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
RENDER_APICALL void RENDER_APIENTRY repaintOpenGLDisplay(void)
|
||||
{
|
||||
RenderWindow* window = s_renderWindow;
|
||||
|
||||
if (window) {
|
||||
window->repaint();
|
||||
return;
|
||||
}
|
||||
// XXX: should be implemented by sending the renderer process
|
||||
// a request
|
||||
ERR("%s not implemented for separate renderer process !!!\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
/* NOTE: For now, always use TCP mode by default, until the emulator
|
||||
* has been updated to support Unix and Win32 pipes
|
||||
*/
|
||||
#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_TCP
|
||||
#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_UNIX
|
||||
|
||||
int gRendererStreamMode = DEFAULT_STREAM_MODE;
|
||||
|
||||
|
|
@ -285,11 +226,7 @@ IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags)
|
|||
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
|
||||
stream = new TcpStream(p_stream_buffer_size);
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
stream = new Win32PipeStream(p_stream_buffer_size);
|
||||
#else /* !_WIN32 */
|
||||
stream = new UnixStream(p_stream_buffer_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!stream) {
|
||||
|
|
@ -312,28 +249,3 @@ IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags)
|
|||
|
||||
return stream;
|
||||
}
|
||||
|
||||
RENDER_APICALL int RENDER_APIENTRY setStreamMode(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case RENDER_API_STREAM_MODE_DEFAULT:
|
||||
mode = DEFAULT_STREAM_MODE;
|
||||
break;
|
||||
|
||||
case RENDER_API_STREAM_MODE_TCP:
|
||||
break;
|
||||
|
||||
#ifndef _WIN32
|
||||
case RENDER_API_STREAM_MODE_UNIX:
|
||||
break;
|
||||
#else /* _WIN32 */
|
||||
case RENDER_API_STREAM_MODE_PIPE:
|
||||
break;
|
||||
#endif /* _WIN32 */
|
||||
default:
|
||||
// Invalid stream mode
|
||||
return false;
|
||||
}
|
||||
gRendererStreamMode = mode;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -20,9 +20,13 @@
|
|||
#include "FrameBuffer.h"
|
||||
#include "RenderThreadInfo.h"
|
||||
#include "ChecksumCalculatorThreadInfo.h"
|
||||
#include "LayerManager.h"
|
||||
|
||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
static const GLint rendererVersion = 1;
|
||||
|
||||
static GLint rcGetRendererVersion()
|
||||
|
|
@ -156,10 +160,12 @@ static EGLint rcGetFBParam(EGLint param)
|
|||
|
||||
switch(param) {
|
||||
case FB_WIDTH:
|
||||
ret = fb->getWidth();
|
||||
// FIXME DISPLAY MANAGER!!
|
||||
ret = 1920;
|
||||
break;
|
||||
case FB_HEIGHT:
|
||||
ret = fb->getHeight();
|
||||
// FIXME DISPLAY MANAGER!!
|
||||
ret = 1080;
|
||||
break;
|
||||
case FB_XDPI:
|
||||
ret = 72; // XXX: should be implemented
|
||||
|
|
@ -306,7 +312,7 @@ static void rcFBPost(uint32_t colorBuffer)
|
|||
return;
|
||||
}
|
||||
|
||||
fb->post(colorBuffer);
|
||||
fb->post(nullptr, colorBuffer);
|
||||
}
|
||||
|
||||
static void rcFBSetSwapInterval(EGLint interval)
|
||||
|
|
@ -392,6 +398,56 @@ static void rcSelectChecksumCalculator(uint32_t protocol, uint32_t reserved) {
|
|||
ChecksumCalculatorThreadInfo::setVersion(protocol);
|
||||
}
|
||||
|
||||
int rcGetNumDisplays() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rcGetDisplayWidth(uint32_t display_id) {
|
||||
printf("%s: display_id=%d\n", __func__, display_id);
|
||||
return 1920;
|
||||
}
|
||||
|
||||
int rcGetDisplayHeight(uint32_t display_id) {
|
||||
printf("%s: display_id=%d\n", __func__, display_id);
|
||||
return 1080;
|
||||
}
|
||||
|
||||
int rcGetDisplayDpiX(uint32_t display_id) {
|
||||
printf("%s: display_id=%d\n", __func__, display_id);
|
||||
return 120;
|
||||
}
|
||||
|
||||
int rcGetDisplayDpiY(uint32_t display_id) {
|
||||
printf("%s: display_id=%d\n", __func__, display_id);
|
||||
return 120;
|
||||
}
|
||||
|
||||
int rcGetDisplayVsyncPeriod(uint32_t display_id) {
|
||||
printf("%s: display_id=%d\n", __func__, display_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rcPostLayer(const char *name, uint32_t color_buffer,
|
||||
int32_t sourceCropLeft, int32_t sourceCropTop,
|
||||
int32_t sourceCropRight, int32_t sourceCropBottom,
|
||||
int32_t displayFrameLeft, int32_t displayFrameTop,
|
||||
int32_t displayFrameRight, int32_t displayFrameBottom) {
|
||||
|
||||
printf("%s: name='%s' color_buffer=%d {%d,%d,%d,%d}, {%d,%d,%d,%d}\n",
|
||||
__func__, name, color_buffer,
|
||||
sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom,
|
||||
displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom);
|
||||
|
||||
LayerRect source_crop{sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom};
|
||||
LayerRect display_frame{displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom};
|
||||
LayerManager::get()->post_layer({name, source_crop, display_frame, color_buffer});
|
||||
}
|
||||
|
||||
void rcPostAllLayersDone()
|
||||
{
|
||||
LayerManager::get()->finish_cycle();
|
||||
}
|
||||
|
||||
void initRenderControlContext(renderControl_decoder_context_t *dec)
|
||||
{
|
||||
dec->rcGetRendererVersion = rcGetRendererVersion;
|
||||
|
|
@ -423,4 +479,12 @@ void initRenderControlContext(renderControl_decoder_context_t *dec)
|
|||
dec->rcCreateClientImage = rcCreateClientImage;
|
||||
dec->rcDestroyClientImage = rcDestroyClientImage;
|
||||
dec->rcSelectChecksumCalculator = rcSelectChecksumCalculator;
|
||||
dec->rcGetNumDisplays = rcGetNumDisplays;
|
||||
dec->rcGetDisplayWidth = rcGetDisplayWidth;
|
||||
dec->rcGetDisplayHeight = rcGetDisplayHeight;
|
||||
dec->rcGetDisplayDpiX = rcGetDisplayDpiX;
|
||||
dec->rcGetDisplayDpiY = rcGetDisplayDpiY;
|
||||
dec->rcGetDisplayVsyncPeriod = rcGetDisplayVsyncPeriod;
|
||||
dec->rcPostLayer = rcPostLayer;
|
||||
dec->rcPostAllLayersDone = rcPostAllLayersDone;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,69 +138,6 @@ struct RenderWindowMessage {
|
|||
result = true;
|
||||
break;
|
||||
|
||||
case CMD_SET_POST_CALLBACK:
|
||||
D("CMD_SET_POST_CALLBACK\n");
|
||||
fb = FrameBuffer::getFB();
|
||||
fb->setPostCallback(msg.set_post_callback.on_post,
|
||||
msg.set_post_callback.on_post_context);
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case CMD_SETUP_SUBWINDOW:
|
||||
D("CMD_SETUP_SUBWINDOW: parent=%p wx=%d wy=%d ww=%d wh=%d fbw=%d fbh=%d dpr=%f rotation=%f\n",
|
||||
(void*)msg.subwindow.parent,
|
||||
msg.subwindow.wx,
|
||||
msg.subwindow.wy,
|
||||
msg.subwindow.ww,
|
||||
msg.subwindow.wh,
|
||||
msg.subwindow.fbw,
|
||||
msg.subwindow.fbh,
|
||||
msg.subwindow.dpr,
|
||||
msg.subwindow.rotation);
|
||||
result = FrameBuffer::getFB()->setupSubWindow(
|
||||
msg.subwindow.parent,
|
||||
msg.subwindow.wx,
|
||||
msg.subwindow.wy,
|
||||
msg.subwindow.ww,
|
||||
msg.subwindow.wh,
|
||||
msg.subwindow.fbw,
|
||||
msg.subwindow.fbh,
|
||||
msg.subwindow.dpr,
|
||||
msg.subwindow.rotation);
|
||||
break;
|
||||
|
||||
case CMD_REMOVE_SUBWINDOW:
|
||||
D("CMD_REMOVE_SUBWINDOW\n");
|
||||
result = FrameBuffer::getFB()->removeSubWindow();
|
||||
break;
|
||||
|
||||
case CMD_SET_ROTATION:
|
||||
D("CMD_SET_ROTATION rotation=%f\n", msg.rotation);
|
||||
fb = FrameBuffer::getFB();
|
||||
if (fb) {
|
||||
fb->setDisplayRotation(msg.rotation);
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_SET_TRANSLATION:
|
||||
D("CMD_SET_TRANSLATION translation=%f,%f\n", msg.trans.px, msg.trans.py);
|
||||
fb = FrameBuffer::getFB();
|
||||
if (fb) {
|
||||
fb->setDisplayTranslation(msg.trans.px, msg.trans.py);
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_REPAINT:
|
||||
D("CMD_REPAINT\n");
|
||||
fb = FrameBuffer::getFB();
|
||||
if (fb) {
|
||||
fb->repost();
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
|
@ -370,16 +307,6 @@ bool RenderWindow::getHardwareStrings(const char** vendor,
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderWindow::setPostCallback(OnPostFn onPost, void* onPostContext) {
|
||||
D("Entering\n");
|
||||
RenderWindowMessage msg;
|
||||
msg.cmd = CMD_SET_POST_CALLBACK;
|
||||
msg.set_post_callback.on_post = onPost;
|
||||
msg.set_post_callback.on_post_context = onPostContext;
|
||||
(void) processMessage(msg);
|
||||
D("Exiting\n");
|
||||
}
|
||||
|
||||
bool RenderWindow::setupSubWindow(FBNativeWindowType window,
|
||||
int wx,
|
||||
int wy,
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ public:
|
|||
const char** renderer,
|
||||
const char** version);
|
||||
|
||||
// Specify a function that will be called everytime a new frame is
|
||||
// displayed. This is relatively slow but allows one to capture the
|
||||
// output.
|
||||
void setPostCallback(OnPostFn onPost, void* onPostContext);
|
||||
|
||||
// Start displaying the emulated framebuffer using a sub-window of a
|
||||
// parent |window| id. |wx|, |wy|, |ww| and |wh| are the position
|
||||
// and dimension of the sub-window, relative to its parent.
|
||||
|
|
|
|||
|
|
@ -42,3 +42,6 @@ rcUpdateColorBuffer
|
|||
|
||||
rcCloseColorBuffer
|
||||
flag flushOnEncode
|
||||
|
||||
rcPostLayer
|
||||
len name (strlen(name) + 1)
|
||||
|
|
|
|||
|
|
@ -27,3 +27,11 @@ GL_ENTRY(int, rcOpenColorBuffer2, uint32_t colorbuffer)
|
|||
GL_ENTRY(uint32_t, rcCreateClientImage, uint32_t context, EGLenum target, GLuint buffer)
|
||||
GL_ENTRY(int, rcDestroyClientImage, uint32_t image)
|
||||
GL_ENTRY(void, rcSelectChecksumCalculator, uint32_t newProtocol, uint32_t reserved)
|
||||
GL_ENTRY(int, rcGetNumDisplays)
|
||||
GL_ENTRY(int, rcGetDisplayWidth, uint32_t displayId)
|
||||
GL_ENTRY(int, rcGetDisplayHeight, uint32_t displayId)
|
||||
GL_ENTRY(int, rcGetDisplayDpiX, uint32_t displayId)
|
||||
GL_ENTRY(int, rcGetDisplayDpiY, uint32_t displayId)
|
||||
GL_ENTRY(int, rcGetDisplayVsyncPeriod, uint32_t displayId)
|
||||
GL_ENTRY(void, rcPostLayer, const char* name, uint32_t colorBuffer, int32_t sourceCropLeft, int32_t sourceCropTop, int32_t sourceCropRight, int32_t sourceCropBottom, int32_t displayFrameLeft, int32_t displayFrameTop, int32_t displayFrameRight, int32_t displayFrameBottom)
|
||||
GL_ENTRY(void, rcPostAllLayersDone)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
uint32_t 32 0x%08x
|
||||
int32_t 32 0x%08x
|
||||
EGLint 32 0x%08x
|
||||
GLint 32 0x%08x
|
||||
GLuint 32 0x%08x
|
||||
|
|
@ -9,3 +10,4 @@ EGLint* 32 0x%08x
|
|||
GLint* 32 0x%08x
|
||||
GLuint* 32 0x%08x
|
||||
void* 32 0x%08x
|
||||
char* 32 0x%08x
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue