Merge "opengles emulator: support display rotation and resize"

This commit is contained in:
David Turner
2011-08-13 15:47:13 -07:00
committed by Android Code Review
6 changed files with 356 additions and 67 deletions

View File

@@ -24,18 +24,51 @@ extern "C" {
//
// initOpenGLRenderer - initialize the OpenGL renderer process.
// window is the native window to be used as the framebuffer.
// x,y,width,height are the dimensions of the rendering subwindow.
// portNum is the tcp port number the renderer is listening to.
// width and height are the framebuffer dimensions that will be
// reported to the guest display driver.
//
// returns true if renderer has been starter successfully;
// returns true if renderer has been started successfully;
//
// This function is *NOT* thread safe and should be called first
// to initialize the renderer.
//
bool initOpenGLRenderer(FBNativeWindowType window,
int x, int y, int width, int height,
int portNum);
bool initOpenGLRenderer(int width, int height, int portNum);
//
// createOpenGLSubwindow -
// Create a native subwindow which is a child of 'window'
// to be used for framebuffer display.
// Framebuffer will not get displayed if a subwindow is not
// created.
// x,y,width,height are the dimensions of the rendering subwindow.
// zRot is the rotation to apply on the framebuffer display image.
//
bool createOpenGLSubwindow(FBNativeWindowType window,
int x, int y, int width, int height, float zRot);
//
// destroyOpenGLSubwindow -
// destroys the created native subwindow. Once destroyed,
// Framebuffer content will not be visible until a new
// subwindow will be created.
//
bool destroyOpenGLSubwindow();
//
// setOpenGLDisplatRotation -
// set the framebuffer display image rotation in units
// of degrees around the z axis
//
void setOpenGLDisplayRotation(float zRot);
//
// repaintOpenGLDisplay -
// causes the OpenGL subwindow to get repainted with the
// latest framebuffer content.
//
void repaintOpenGLDisplay();
//
// stopOpenGLRenderer - stops the OpenGL renderer process.

View File

@@ -27,14 +27,13 @@ FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL;
HandleType FrameBuffer::s_nextHandle = 0;
#ifdef WITH_GLES2
static const char *getGLES2ExtensionString(EGLDisplay p_dpy,
EGLNativeWindowType p_window)
static const char *getGLES2ExtensionString(EGLDisplay p_dpy)
{
EGLConfig config;
EGLSurface surface;
GLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
@@ -45,9 +44,13 @@ static const char *getGLES2ExtensionString(EGLDisplay p_dpy,
return NULL;
}
surface = s_egl.eglCreateWindowSurface(p_dpy, config,
p_window,
NULL);
EGLint pbufAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs);
if (surface == EGL_NO_SURFACE) {
return NULL;
}
@@ -86,24 +89,17 @@ static const char *getGLES2ExtensionString(EGLDisplay p_dpy,
void FrameBuffer::finalize(){
if(s_theFrameBuffer){
s_theFrameBuffer->removeSubWindow();
s_theFrameBuffer->m_colorbuffers.clear();
s_theFrameBuffer->m_windows.clear();
s_theFrameBuffer->m_contexts.clear();
s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglSurface);
s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglContext);
if (s_theFrameBuffer->m_subWin) {
destroySubWindow(s_theFrameBuffer->m_subWinDisplay,
s_theFrameBuffer->m_subWin);
}
delete s_theFrameBuffer;
s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufSurface);
s_theFrameBuffer = NULL;
}
}
bool FrameBuffer::initialize(FBNativeWindowType p_window,
int p_x, int p_y,
int p_width, int p_height)
bool FrameBuffer::initialize(int width, int height)
{
if (s_theFrameBuffer != NULL) {
return true;
@@ -130,7 +126,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
//
// allocate space for the FrameBuffer object
//
FrameBuffer *fb = new FrameBuffer(p_x, p_y, p_width, p_height);
FrameBuffer *fb = new FrameBuffer(width, height);
if (!fb) {
ERR("Failed to create fb\n");
return false;
@@ -169,10 +165,6 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
DBG("egl: %d %d\n", fb->m_caps.eglMajor, fb->m_caps.eglMinor);
s_egl.eglBindAPI(EGL_OPENGL_ES_API);
fb->m_nativeWindow = p_window;
fb->m_subWin = createSubWindow(p_window,&fb->m_subWinDisplay,p_x,p_y,p_width,p_height);
//
// if GLES2 plugin has loaded - try to make GLES2 context and
// get GLES2 extension string
@@ -180,7 +172,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
const char *gl2Extensions = NULL;
#ifdef WITH_GLES2
if (fb->m_caps.hasGL2) {
gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay, fb->m_subWin);
gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay);
if (!gl2Extensions) {
// Could not create GLES2 context - drop GL2 capability
fb->m_caps.hasGL2 = false;
@@ -189,8 +181,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
#endif
//
// Create EGL context and Surface attached to the native window, for
// framebuffer post rendering.
// Create EGL context for framebuffer post rendering.
//
#if 0
GLint configAttribs[] = {
@@ -203,35 +194,25 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_NONE
};
#endif
EGLConfig eglConfig;
int n;
if (!s_egl.eglChooseConfig(fb->m_eglDisplay, configAttribs,
&eglConfig, 1, &n)) {
&fb->m_eglConfig, 1, &n)) {
ERR("Failed on eglChooseConfig\n");
delete fb;
return false;
}
EGLNativeDisplayType dpy;
fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay, eglConfig,
fb->m_subWin,
NULL);
if (fb->m_eglSurface == EGL_NO_SURFACE) {
ERR("Failed to create surface\n");
delete fb;
return false;
}
GLint glContextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_NONE
};
fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, eglConfig,
fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
EGL_NO_CONTEXT,
glContextAttribs);
if (fb->m_eglContext == EGL_NO_CONTEXT) {
@@ -240,6 +221,26 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
return false;
}
//
// create a 1x1 pbuffer surface which will be used for binding
// the FB context.
// The FB output will go to a subwindow, if one exist.
//
EGLint pbufAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
fb->m_pbufSurface = s_egl.eglCreatePbufferSurface(fb->m_eglDisplay,
fb->m_eglConfig,
pbufAttribs);
if (fb->m_pbufSurface == EGL_NO_SURFACE) {
printf("Failed to create pbuf surface for FB 0x%x\n", s_egl.eglGetError());
delete fb;
return false;
}
// Make the context current
if (!fb->bind_locked()) {
ERR("Failed to make current\n");
@@ -341,9 +342,7 @@ bool FrameBuffer::initialize(FBNativeWindowType p_window,
return true;
}
FrameBuffer::FrameBuffer(int p_x, int p_y, int p_width, int p_height) :
m_x(p_x),
m_y(p_y),
FrameBuffer::FrameBuffer(int p_width, int p_height) :
m_width(p_width),
m_height(p_height),
m_eglDisplay(EGL_NO_DISPLAY),
@@ -354,6 +353,8 @@ FrameBuffer::FrameBuffer(int p_x, int p_y, int p_width, int p_height) :
m_prevDrawSurf(EGL_NO_SURFACE),
m_subWin(NULL),
m_subWinDisplay(NULL),
m_lastPostedColorBuffer(0),
m_zRot(0.0f),
m_statsNumFrames(0),
m_statsStartTime(0LL)
{
@@ -364,6 +365,74 @@ FrameBuffer::~FrameBuffer()
{
}
bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
int p_x, int p_y,
int p_width, int p_height, float zRot)
{
bool success = false;
if (s_theFrameBuffer) {
s_theFrameBuffer->m_lock.lock();
FrameBuffer *fb = s_theFrameBuffer;
if (!fb->m_subWin) {
// create native subwindow for FB display output
fb->m_subWin = createSubWindow(p_window,
&fb->m_subWinDisplay,
p_x,p_y,p_width,p_height);
if (fb->m_subWin) {
fb->m_nativeWindow = p_window;
// create EGLSurface from the generated subwindow
fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay,
fb->m_eglConfig,
fb->m_subWin,
NULL);
if (fb->m_eglSurface == EGL_NO_SURFACE) {
ERR("Failed to create surface\n");
destroySubWindow(fb->m_subWinDisplay, fb->m_subWin);
fb->m_subWin = NULL;
}
else if (fb->bindSubwin_locked()) {
// Subwin creation was successfull,
// update viewport and z rotation and draw
// the last posted color buffer.
s_gl.glViewport(0, 0, p_width, p_height);
fb->m_zRot = zRot;
fb->post( fb->m_lastPostedColorBuffer, false );
fb->unbind_locked();
success = true;
}
}
}
s_theFrameBuffer->m_lock.unlock();
}
return success;
}
bool FrameBuffer::removeSubWindow()
{
bool removed = false;
if (s_theFrameBuffer) {
s_theFrameBuffer->m_lock.lock();
if (s_theFrameBuffer->m_subWin) {
s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,
s_theFrameBuffer->m_eglSurface);
destroySubWindow(s_theFrameBuffer->m_subWinDisplay,
s_theFrameBuffer->m_subWin);
s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE;
s_theFrameBuffer->m_subWin = NULL;
removed = true;
}
s_theFrameBuffer->m_lock.unlock();
}
return removed;
}
HandleType FrameBuffer::genHandle()
{
HandleType id;
@@ -620,6 +689,24 @@ bool FrameBuffer::bind_locked()
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface,
m_pbufSurface, m_eglContext)) {
ERR("eglMakeCurrent failed\n");
return false;
}
m_prevContext = prevContext;
m_prevReadSurf = prevReadSurf;
m_prevDrawSurf = prevDrawSurf;
return true;
}
bool FrameBuffer::bindSubwin_locked()
{
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)) {
ERR("eglMakeCurrent failed\n");
@@ -645,17 +732,41 @@ bool FrameBuffer::unbind_locked()
return true;
}
bool FrameBuffer::post(HandleType p_colorbuffer)
bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
{
android::Mutex::Autolock mutex(m_lock);
if (needLock) m_lock.lock();
bool ret = false;
ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
if (c != m_colorbuffers.end()) {
if (!bind_locked()) {
m_lastPostedColorBuffer = p_colorbuffer;
if (!m_subWin) {
// no subwindow created for the FB output
// cannot post the colorbuffer
if (needLock) m_lock.unlock();
return ret;
}
// bind the subwindow eglSurface
if (!bindSubwin_locked()) {
ERR("FrameBuffer::post eglMakeCurrent failed\n");
if (needLock) m_lock.unlock();
return false;
}
//
// render the color buffer to the window
//
s_gl.glPushMatrix();
s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f);
if (m_zRot != 0.0f) {
s_gl.glClear(GL_COLOR_BUFFER_BIT);
}
ret = (*c).second->post();
s_gl.glPopMatrix();
if (ret) {
//
@@ -674,8 +785,19 @@ bool FrameBuffer::post(HandleType p_colorbuffer)
s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
}
// restore previous binding
unbind_locked();
}
if (needLock) m_lock.unlock();
return ret;
}
bool FrameBuffer::repost()
{
if (m_lastPostedColorBuffer) {
return post( m_lastPostedColorBuffer );
}
return false;
}

View File

@@ -43,9 +43,11 @@ struct FrameBufferCaps
class FrameBuffer
{
public:
static bool initialize(FBNativeWindowType p_window,
int x, int y,
int width, int height);
static bool initialize(int width, int height);
static bool setupSubWindow(FBNativeWindowType p_window,
int x, int y,
int width, int height, float zRot);
static bool removeSubWindow();
static void finalize();
static FrameBuffer *getFB() { return s_theFrameBuffer; }
@@ -70,7 +72,8 @@ public:
int x, int y, int width, int height,
GLenum format, GLenum type, void *pixels);
bool post(HandleType p_colorbuffer);
bool post(HandleType p_colorbuffer, bool needLock = true);
bool repost();
EGLDisplay getDisplay() const { return m_eglDisplay; }
EGLContext getContext() const { return m_eglContext; }
@@ -78,10 +81,16 @@ public:
bool bind_locked();
bool unbind_locked();
void setDisplayRotation(float zRot) {
m_zRot = zRot;
repost();
}
private:
FrameBuffer(int p_x, int p_y, int p_width, int p_height);
FrameBuffer(int p_width, int p_height);
~FrameBuffer();
HandleType genHandle();
bool bindSubwin_locked();
private:
static FrameBuffer *s_theFrameBuffer;
@@ -100,12 +109,16 @@ private:
EGLSurface m_eglSurface;
EGLContext m_eglContext;
EGLSurface m_pbufSurface;
EGLContext m_prevContext;
EGLSurface m_prevReadSurf;
EGLSurface m_prevDrawSurf;
EGLNativeWindowType m_subWin;
EGLNativeDisplayType m_subWinDisplay;
EGLConfig m_eglConfig;
HandleType m_lastPostedColorBuffer;
float m_zRot;
int m_statsNumFrames;
long long m_statsStartTime;

View File

@@ -27,13 +27,19 @@ static int s_renderPort = 0;
static IOStream *createRenderThread(int p_stream_buffer_size,
unsigned int clientFlags);
#ifdef __APPLE__
//
// For now run the renderer as a thread inside the calling
// process instead as running it in a separate process for all
// platforms.
// at the future we want it to run as a seperate process except for
// Mac OS X since it is imposibble on this platform to make one process
// render to a window created by another process.
//
//#ifdef __APPLE__
#define RENDER_API_USE_THREAD
#endif
//#endif
bool initOpenGLRenderer(FBNativeWindowType window,
int x, int y, int width, int height,
int portNum)
bool initOpenGLRenderer(int width, int height, int portNum)
{
//
@@ -50,7 +56,7 @@ bool initOpenGLRenderer(FBNativeWindowType window,
// initialize the renderer and listen to connections
// on a thread in the current process.
//
bool inited = FrameBuffer::initialize(window, x, y, width, height);
bool inited = FrameBuffer::initialize(width, height);
if (!inited) {
return false;
}
@@ -169,6 +175,71 @@ bool stopOpenGLRenderer()
return ret;
}
bool createOpenGLSubwindow(FBNativeWindowType window,
int x, int y, int width, int height, float zRot)
{
if (s_renderThread) {
return FrameBuffer::setupSubWindow(window,x,y,width,height, zRot);
}
else {
//
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
}
return false;
}
bool destroyOpenGLSubwindow()
{
if (s_renderThread) {
return FrameBuffer::removeSubWindow();
}
else {
//
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
return false;
}
}
void setOpenGLDisplayRotation(float zRot)
{
if (s_renderThread) {
FrameBuffer *fb = FrameBuffer::getFB();
if (fb) {
fb->setDisplayRotation(zRot);
}
}
else {
//
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
}
}
void repaintOpenGLDisplay()
{
if (s_renderThread) {
FrameBuffer *fb = FrameBuffer::getFB();
if (fb) {
fb->repost();
}
}
else {
//
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
}
}
IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags)
{
TcpStream *stream = new TcpStream(p_stream_buffer_size);

View File

@@ -120,13 +120,19 @@ int main(int argc, char *argv[])
//
// initialize Framebuffer
//
bool inited = FrameBuffer::initialize(windowId,
winX, winY, winWidth, winHeight);
bool inited = FrameBuffer::initialize(winWidth, winHeight);
if (!inited) {
fprintf(stderr,"Failed to initialize Framebuffer\n");
return -1;
}
inited = FrameBuffer::setupSubWindow(windowId,
winX, winY, winWidth, winHeight, 0.0);
if (!inited) {
fprintf(stderr,"Failed to create subwindow Framebuffer\n");
return -1;
}
//
// Create and run a render server listening to the given port number
//

View File

@@ -80,13 +80,23 @@ int main(int argc, char *argv[])
//
// initialize OpenGL renderer to render in our window
//
bool inited = initOpenGLRenderer(windowId, 0, 0,
winWidth, winHeight, portNum);
bool inited = initOpenGLRenderer(winWidth, winHeight, portNum);
if (!inited) {
return -1;
}
printf("renderer process started\n");
float zRot = 0.0f;
inited = createOpenGLSubwindow(windowId, 0, 0,
winWidth, winHeight, zRot);
if (!inited) {
printf("failed to create OpenGL subwindow\n");
stopOpenGLRenderer();
return -1;
}
int subwinWidth = winWidth;
int subwinHeight = winHeight;
injector = new EventInjector(consolePort);
// Just wait until the window is closed
@@ -103,7 +113,7 @@ int main(int argc, char *argv[])
injector->sendMouseDown(ev.button.x, ev.button.y);
mouseDown = 1;
}
break;
break;
case SDL_MOUSEBUTTONUP:
if (mouseDown) {
injector->sendMouseUp(ev.button.x,ev.button.y);
@@ -123,7 +133,41 @@ int main(int argc, char *argv[])
goto EXIT;
}
#endif
injector->sendKeyDown(convert_keysym(ev.key.keysym.sym));
injector->sendKeyDown(convert_keysym(ev.key.keysym.sym));
if (ev.key.keysym.sym == SDLK_KP_MINUS) {
subwinWidth /= 2;
subwinHeight /= 2;
bool stat = destroyOpenGLSubwindow();
printf("destroy subwin returned %d\n", stat);
stat = createOpenGLSubwindow(windowId,
(winWidth - subwinWidth) / 2,
(winHeight - subwinHeight) / 2,
subwinWidth, subwinHeight,
zRot);
printf("create subwin returned %d\n", stat);
}
else if (ev.key.keysym.sym == SDLK_KP_PLUS) {
subwinWidth *= 2;
subwinHeight *= 2;
bool stat = destroyOpenGLSubwindow();
printf("destroy subwin returned %d\n", stat);
stat = createOpenGLSubwindow(windowId,
(winWidth - subwinWidth) / 2,
(winHeight - subwinHeight) / 2,
subwinWidth, subwinHeight,
zRot);
printf("create subwin returned %d\n", stat);
}
else if (ev.key.keysym.sym == SDLK_KP_MULTIPLY) {
zRot += 10.0f;
setOpenGLDisplayRotation(zRot);
}
else if (ev.key.keysym.sym == SDLK_KP_ENTER) {
repaintOpenGLDisplay();
}
break;
case SDL_KEYUP:
injector->sendKeyUp(convert_keysym(ev.key.keysym.sym));