diff options
Diffstat (limited to 'emulator/opengl/host/libs/libOpenglRender/render_api.cpp')
-rw-r--r-- | emulator/opengl/host/libs/libOpenglRender/render_api.cpp | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/emulator/opengl/host/libs/libOpenglRender/render_api.cpp b/emulator/opengl/host/libs/libOpenglRender/render_api.cpp new file mode 100644 index 0000000..c8d3e06 --- /dev/null +++ b/emulator/opengl/host/libs/libOpenglRender/render_api.cpp @@ -0,0 +1,359 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "libOpenglRender/render_api.h" +#include "IOStream.h" +#include "FrameBuffer.h" +#include "RenderServer.h" +#include "osProcess.h" +#include "TimeUtils.h" + +#include "TcpStream.h" +#ifdef _WIN32 +#include "Win32PipeStream.h" +#else +#include "UnixStream.h" +#endif + +#include "EGLDispatch.h" +#include "GLDispatch.h" +#include "GL2Dispatch.h" + +static osUtils::childProcess *s_renderProc = NULL; +static RenderServer *s_renderThread = NULL; +static int s_renderPort = 0; + +static IOStream *createRenderThread(int p_stream_buffer_size, + unsigned int clientFlags); + +// +// 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 + +bool initLibrary(void) +{ + // + // Load EGL Plugin + // + if (!init_egl_dispatch()) { + // Failed to load EGL + printf("Failed to init_egl_dispatch\n"); + return false; + } + + // + // Load GLES Plugin + // + if (!init_gl_dispatch()) { + // Failed to load GLES + ERR("Failed to init_gl_dispatch\n"); + return false; + } + + /* failure to init the GLES2 dispatch table is not fatal */ + init_gl2_dispatch(); + + return true; +} + +bool initOpenGLRenderer(int width, int height, int portNum, + OnPostFn onPost, void* onPostContext) +{ + + // + // Fail if renderer is already initialized + // + if (s_renderProc || s_renderThread) { + return false; + } + + s_renderPort = portNum; + +#ifdef RENDER_API_USE_THREAD // should be defined for mac + // + // initialize the renderer and listen to connections + // on a thread in the current process. + // + bool inited = FrameBuffer::initialize(width, height, onPost, onPostContext); + if (!inited) { + return false; + } + + s_renderThread = RenderServer::create(portNum); + if (!s_renderThread) { + return false; + } + + s_renderThread->start(); + +#else + if (onPost) { + // onPost callback not supported with separate renderer process. + // + // If we ever revive separate process support, we could make the choice + // between thread and process at runtime instead of compile time, and + // choose the thread path if an onPost callback is requested. Or, the + // callback could be supported with a separate process using shmem or + // other IPC mechanism. + return false; + } + + // + // Launch emulator_renderer + // + char cmdLine[128]; + snprintf(cmdLine, 128, "emulator_renderer -windowid %d -port %d -x %d -y %d -width %d -height %d", + (int)window, portNum, x, y, width, height); + + s_renderProc = osUtils::childProcess::create(cmdLine, NULL); + if (!s_renderProc) { + return false; + } + + // + // try to connect to the renderer in order to check it + // was successfully initialized. + // + int nTrys = 0; + IOStream *dummy = NULL; + do { + ++nTrys; + + // + // Wait a bit to make the renderer process a chance to be + // initialized. + // On Windows we need during this time to handle windows + // events since the renderer generates a subwindow of this + // process's window, we need to be responsive for windows + // during this time to let the renderer generates this subwindow. + // +#ifndef _WIN32 + TimeSleepMS(300); +#else + long long t0 = GetCurrentTimeMS(); + while( (GetCurrentTimeMS() - t0) < 300 ) { + MSG msg; + int n = 0; + while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) + { + n++; + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + if (n == 0) TimeSleepMS(10); + } +#endif + + dummy = createRenderThread(8, 0); + + if (!dummy) { + // stop if the process is no longer running + if (!osUtils::isProcessRunning(s_renderProc->getPID())) { + break; + } + } + } while(!dummy && nTrys < 10); // give up after 3 seconds, XXX: ??? + + if (!dummy) { + // + // Failed - make sure the process is killed + // + osUtils::KillProcess(s_renderProc->getPID(), true); + delete s_renderProc; + s_renderProc = NULL; + return false; + } + + // destroy the dummy connection + delete dummy; +#endif + + return true; +} + +bool stopOpenGLRenderer() +{ + bool ret = false; + + // open a dummy connection to the renderer to make it + // realize the exit request. + // (send the exit request in clientFlags) + IOStream *dummy = createRenderThread(8, IOSTREAM_CLIENT_EXIT_SERVER); + if (!dummy) return false; + + if (s_renderProc) { + // + // wait for the process to exit + // + int exitStatus; + ret = s_renderProc->wait(&exitStatus); + + delete s_renderProc; + s_renderProc = NULL; + } + else if (s_renderThread) { + + // wait for the thread to exit + int status; + ret = s_renderThread->wait(&status); + + delete s_renderThread; + s_renderThread = NULL; + } + + 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__); + } +} + + +/* 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 STREAM_MODE_TCP + +int gRendererStreamMode = DEFAULT_STREAM_MODE; + +IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) +{ + SocketStream* stream = NULL; + + if (gRendererStreamMode == 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) { + ERR("createRenderThread failed to create stream\n"); + return NULL; + } + if (stream->connect(s_renderPort) < 0) { + ERR("createRenderThread failed to connect\n"); + delete stream; + return NULL; + } + + // + // send clientFlags to the renderer + // + unsigned int *pClientFlags = + (unsigned int *)stream->allocBuffer(sizeof(unsigned int)); + *pClientFlags = clientFlags; + stream->commitBuffer(sizeof(unsigned int)); + + return stream; +} + +int +setStreamMode(int mode) +{ + switch (mode) { + case STREAM_MODE_DEFAULT: + mode = DEFAULT_STREAM_MODE; + break; + + case STREAM_MODE_TCP: + break; + +#ifndef _WIN32 + case STREAM_MODE_UNIX: + break; +#else /* _WIN32 */ + case STREAM_MODE_PIPE: + break; +#endif /* _WIN32 */ + default: + // Invalid stream mode + return -1; + } + gRendererStreamMode = mode; + return 0; +} |