diff options
Diffstat (limited to 'ovgosd.c')
-rw-r--r-- | ovgosd.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/ovgosd.c b/ovgosd.c new file mode 100644 index 0000000..2e472f2 --- /dev/null +++ b/ovgosd.c @@ -0,0 +1,297 @@ +/* + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include <VG/openvg.h> +#include <VG/vgu.h> +#include <EGL/egl.h> +#include <GLES/gl.h> + +#include "ovgosd.h" +#include "omxdevice.h" + +class cOvg : public cThread +{ +public: + + cOvg() : + cThread(), + m_do(0), + m_done(0), + m_mutex(0), + m_width(0), + m_height(0), + m_pixmap(0), + m_aspect(0), + m_d(0), + m_x(0), + m_y(0), + m_w(0), + m_h(0), + m_clear(false) + { + cOmxDevice::GetDisplaySize(m_width, m_height, m_aspect); + + m_do = new cCondWait(); + m_done = new cCondWait(); + m_mutex = new cMutex(); + + Start(); + } + + ~cOvg() + { + Cancel(-1); + Clear(); + + delete m_do; + delete m_done; + delete m_mutex; + } + + void GetDisplaySize(int &width, int &height, double &aspect) + { + width = m_width; + height = m_height; + aspect = m_aspect; + } + + void DrawPixmap(int x, int y, int w, int h, int d, const uint8_t *data) + { + m_mutex->Lock(); + m_pixmap = data; + m_d = d; + m_x = x; + m_y = y; + m_w = w; + m_h = h; + m_do->Signal(); + m_done->Wait(); + m_mutex->Unlock(); + } + + void Clear() + { + m_mutex->Lock(); + m_clear = true; + m_do->Signal(); + m_done->Wait(); + m_mutex->Unlock(); + } + +protected: + + virtual void Action(void) + { + dsyslog("rpihddevice: cOvg() thread started"); + + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) + esyslog("rpihddevice: failed to get EGL display connection!"); + + if (eglInitialize(display, NULL, NULL) == EGL_FALSE) + esyslog("rpihddevice: failed to init EGL display connection!"); + + eglBindAPI(EGL_OPENVG_API); + + const EGLint fbAttr[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_CONFORMANT, EGL_OPENVG_BIT, + EGL_NONE + }; + + EGLConfig config; + EGLint numConfig; + + // get an appropriate EGL frame buffer configuration + if (eglChooseConfig(display, fbAttr, &config, 1, &numConfig) == EGL_FALSE) + esyslog("rpihddevice: failed to get EGL frame buffer config!"); + + // create an EGL rendering context + EGLContext context = eglCreateContext(display, config, NULL, NULL); + if (context == EGL_NO_CONTEXT) + esyslog("rpihddevice: failed to create EGL rendering context!"); + + DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = vc_dispmanx_display_open(0 /* LCD */); + DISPMANX_UPDATE_HANDLE_T dispmanUpdate = vc_dispmanx_update_start(0); + + VC_RECT_T dstRect = { 0, 0, m_width, m_height }; + VC_RECT_T srcRect = { 0, 0, m_width << 16, m_height << 16 }; + + DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add( + dispmanUpdate, dispmanDisplay, 2, &dstRect, 0, &srcRect, + DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0); + + vc_dispmanx_update_submit_sync(dispmanUpdate); + + EGL_DISPMANX_WINDOW_T nativewindow; + nativewindow.element = dispmanElement; + nativewindow.width = m_width; + nativewindow.height = m_height; + + const EGLint windowAttr[] = { + EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER, + EGL_NONE + }; + + EGLSurface surface = eglCreateWindowSurface(display, config, &nativewindow, windowAttr); + if (surface == EGL_NO_SURFACE) + esyslog("rpihddevice: failed to create EGL window surface!"); + + // connect the context to the surface + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) + esyslog("rpihddevice: failed to connect context to surface!"); + + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + vgSetfv(VG_CLEAR_COLOR, 4, color); + vgClear(0, 0, m_width, m_height); + eglSwapBuffers(display, surface); + + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_BETTER); + vgSeti(VG_BLEND_MODE, VG_BLEND_SRC); + + vgLoadIdentity(); + vgScale(1.0f, -1.0f); + vgTranslate(0.0f, -m_height); + + VGImage image = vgCreateImage(VG_sARGB_8888, m_width, m_height, VG_IMAGE_QUALITY_BETTER); + + while (Running()) + { + m_do->Wait(); + if (m_pixmap) + { + vgClearImage(image, m_x, m_y, m_w, m_h); + vgImageSubData(image, m_pixmap, m_d, VG_sARGB_8888, m_x, m_y, m_w, m_h); + vgDrawImage(image); + m_pixmap = 0; + } + if (m_clear) + { + vgClearImage(image, 0, 0, m_width, m_height); + vgDrawImage(image); + m_clear = false; + } + eglSwapBuffers(display, surface); + m_done->Signal(); + } + + vgDestroyImage(image); + + // clear screen + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(display, surface); + + // Release OpenGL resources + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + eglDestroyContext(display, context); + eglTerminate(display); + + dsyslog("rpihddevice: cOvg() thread ended"); + } + +private: + + cCondWait* m_do; + cCondWait* m_done; + cMutex* m_mutex; + + int m_width; + int m_height; + double m_aspect; + + const uint8_t *m_pixmap; + int m_d; + int m_x; + int m_y; + int m_w; + int m_h; + + bool m_clear; + +}; + +cRpiOsdProvider::cRpiOsdProvider() : + cOsdProvider(), + m_ovg(0) +{ + dsyslog("rpihddevice: new cOsdProvider()"); + m_ovg = new cOvg(); +} + +cRpiOsdProvider::~cRpiOsdProvider() +{ + dsyslog("rpihddevice: delete cOsdProvider()"); + delete m_ovg; +} + +cOsd *cRpiOsdProvider::CreateOsd(int Left, int Top, uint Level) +{ + return new cOvgOsd(Left, Top, Level, m_ovg); +} + +cOvgOsd::cOvgOsd(int Left, int Top, uint Level, cOvg *ovg) : + cOsd(Left, Top, Level), + m_ovg(ovg) +{ +} + +cOvgOsd::~cOvgOsd() +{ + m_ovg->Clear(); +} + +void cOvgOsd::Flush(void) +{ + if (IsTrueColor()) + { + LOCK_PIXMAPS; + + while (cPixmapMemory *pm = RenderPixmaps()) { + int w = pm->ViewPort().Width(); + int h = pm->ViewPort().Height(); + int d = w * sizeof(tColor); + m_ovg->DrawPixmap( + Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y(), + pm->ViewPort().Width(), pm->ViewPort().Height(), + pm->ViewPort().Width() * sizeof(tColor), pm->Data()); + delete pm; + } + + return; + } + + for (int i = 0; cBitmap *bitmap = GetBitmap(i); ++i) + { + int x1, y1, x2, y2; + if (bitmap->Dirty(x1, y1, x2, y2)) + { + int w = x2 - x1 + 1; + int h = y2 - y1 + 1; + uint8_t *argb = (uint8_t *) malloc(w * h * sizeof(uint32_t)); + + for (int y = y1; y <= y2; ++y) + { + for (int x = x1; x <= x2; ++x) + { + ((uint32_t *) argb)[x - x1 + (y - y1) * w] = + bitmap->GetColor(x, y); + } + } + m_ovg->DrawPixmap(Left() + bitmap->X0() + x1, + Top() + bitmap->Y0() + y1, w, h, w * sizeof(tColor), argb); + bitmap->Clean(); + free(argb); + } + } +} + |