mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-30 17:01:15 +02:00
add openGL based framebuffer implementation for testing on PC
this is based on Carsten Juttner's previous work, but without any video decoding.
This commit is contained in:
@@ -128,6 +128,10 @@ if BOXTYPE_TRIPLE
|
|||||||
neutrino_LDADD += \
|
neutrino_LDADD += \
|
||||||
$(top_builddir)/src/lcddisplay/liblcddisplay.a
|
$(top_builddir)/src/lcddisplay/liblcddisplay.a
|
||||||
endif
|
endif
|
||||||
|
if BOXTYPE_GENERIC
|
||||||
|
neutrino_LDADD += \
|
||||||
|
-lglut -lGL -lGLU -lGLEW
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
if BOXTYPE_TRIPLE
|
if BOXTYPE_TRIPLE
|
||||||
neutrino_LDADD += \
|
neutrino_LDADD += \
|
||||||
|
@@ -36,6 +36,10 @@ libneutrino_driver_a_SOURCES = \
|
|||||||
ringbuffer.c \
|
ringbuffer.c \
|
||||||
volume.cpp
|
volume.cpp
|
||||||
|
|
||||||
|
if BOXTYPE_GENERIC
|
||||||
|
libneutrino_driver_a_SOURCES += \
|
||||||
|
glthread.cpp
|
||||||
|
endif
|
||||||
if BOXTYPE_SPARK
|
if BOXTYPE_SPARK
|
||||||
libneutrino_driver_a_SOURCES += \
|
libneutrino_driver_a_SOURCES += \
|
||||||
framebuffer_spark.cpp
|
framebuffer_spark.cpp
|
||||||
|
@@ -41,6 +41,12 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include "rcinput.h"
|
||||||
|
#include "glthread.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <gui/color.h>
|
#include <gui/color.h>
|
||||||
#include <gui/pictureviewer.h>
|
#include <gui/pictureviewer.h>
|
||||||
#include <global.h>
|
#include <global.h>
|
||||||
@@ -245,6 +251,34 @@ void CFrameBuffer::init(const char * const fbDevice)
|
|||||||
{
|
{
|
||||||
int tr = 0xFF;
|
int tr = 0xFF;
|
||||||
|
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
fd = -1;
|
||||||
|
if(!mpGLThreadObj)
|
||||||
|
{
|
||||||
|
screeninfo.bits_per_pixel = 32;
|
||||||
|
screeninfo.xres = 720;
|
||||||
|
screeninfo.xres_virtual = screeninfo.xres;
|
||||||
|
screeninfo.yres = 576;
|
||||||
|
screeninfo.yres_virtual = screeninfo.yres;
|
||||||
|
screeninfo.bits_per_pixel = 32;
|
||||||
|
screeninfo.blue.length = 8;
|
||||||
|
screeninfo.blue.offset = 0;
|
||||||
|
screeninfo.green.length = 8;
|
||||||
|
screeninfo.green.offset = 8;
|
||||||
|
screeninfo.red.length = 8;
|
||||||
|
screeninfo.red.offset = 16;
|
||||||
|
screeninfo.transp.length = 8;
|
||||||
|
screeninfo.transp.offset = 24;
|
||||||
|
mpGLThreadObj = new GLThreadObj(screeninfo.xres, screeninfo.yres);
|
||||||
|
if(mpGLThreadObj)
|
||||||
|
{ /* kick off the GL thread for the window */
|
||||||
|
mpGLThreadObj->Start();
|
||||||
|
mpGLThreadObj->waitInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lfb = reinterpret_cast<fb_pixel_t*>(mpGLThreadObj->getOSDBuffer());
|
||||||
|
memset(lfb, 0x7f, screeninfo.xres * screeninfo.yres * 4);
|
||||||
|
#else
|
||||||
fd = open(fbDevice, O_RDWR);
|
fd = open(fbDevice, O_RDWR);
|
||||||
if(!fd) fd = open(fbDevice, O_RDWR);
|
if(!fd) fd = open(fbDevice, O_RDWR);
|
||||||
|
|
||||||
@@ -291,10 +325,11 @@ void CFrameBuffer::init(const char * const fbDevice)
|
|||||||
|
|
||||||
/* tell the GXA where the framebuffer to draw on starts */
|
/* tell the GXA where the framebuffer to draw on starts */
|
||||||
smem_start = (unsigned int) fix.smem_start;
|
smem_start = (unsigned int) fix.smem_start;
|
||||||
printf("smem_start %x\n", smem_start);
|
printf("smem_start %x\n", smem_start);
|
||||||
|
|
||||||
setupGXA();
|
setupGXA();
|
||||||
#endif
|
#endif /* USE_NEVIS_GXA */
|
||||||
|
#endif /* USE_OPENGL */
|
||||||
cache_size = 0;
|
cache_size = 0;
|
||||||
|
|
||||||
/* Windows Colors */
|
/* Windows Colors */
|
||||||
@@ -415,8 +450,14 @@ CFrameBuffer::~CFrameBuffer()
|
|||||||
delete[] virtual_fb;
|
delete[] virtual_fb;
|
||||||
virtual_fb = NULL;
|
virtual_fb = NULL;
|
||||||
}
|
}
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
active = false; /* keep people/infoclocks from accessing */
|
||||||
|
mpGLThreadObj->shutDown();
|
||||||
|
mpGLThreadObj->join();
|
||||||
|
#else
|
||||||
close(fd);
|
close(fd);
|
||||||
close(tty);
|
close(tty);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int CFrameBuffer::getFileHandle() const
|
int CFrameBuffer::getFileHandle() const
|
||||||
@@ -488,6 +529,7 @@ int CFrameBuffer::setMode(unsigned int /*nxRes*/, unsigned int /*nyRes*/, unsign
|
|||||||
if (!available&&!active)
|
if (!available&&!active)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#ifndef USE_OPENGL
|
||||||
#if HAVE_AZBOX_HARDWARE
|
#if HAVE_AZBOX_HARDWARE
|
||||||
#ifndef FBIO_BLIT
|
#ifndef FBIO_BLIT
|
||||||
#define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
|
#define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
|
||||||
@@ -535,11 +577,15 @@ int CFrameBuffer::setMode(unsigned int /*nxRes*/, unsigned int /*nyRes*/, unsign
|
|||||||
nxRes, nyRes, nbpp,
|
nxRes, nyRes, nbpp,
|
||||||
screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
|
screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xRes = screeninfo.xres;
|
xRes = screeninfo.xres;
|
||||||
yRes = screeninfo.yres;
|
yRes = screeninfo.yres;
|
||||||
bpp = screeninfo.bits_per_pixel;
|
bpp = screeninfo.bits_per_pixel;
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
stride = 4 * xRes;
|
||||||
|
#else
|
||||||
fb_fix_screeninfo _fix;
|
fb_fix_screeninfo _fix;
|
||||||
|
|
||||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &_fix)<0) {
|
if (ioctl(fd, FBIOGET_FSCREENINFO, &_fix)<0) {
|
||||||
@@ -548,6 +594,7 @@ int CFrameBuffer::setMode(unsigned int /*nxRes*/, unsigned int /*nyRes*/, unsign
|
|||||||
}
|
}
|
||||||
|
|
||||||
stride = _fix.line_length;
|
stride = _fix.line_length;
|
||||||
|
#endif
|
||||||
printf("FB: %dx%dx%d line length %d. %s nevis GXA accelerator.\n", xRes, yRes, bpp, stride,
|
printf("FB: %dx%dx%d line length %d. %s nevis GXA accelerator.\n", xRes, yRes, bpp, stride,
|
||||||
#ifdef USE_NEVIS_GXA
|
#ifdef USE_NEVIS_GXA
|
||||||
"Using"
|
"Using"
|
||||||
@@ -1724,6 +1771,7 @@ void CFrameBuffer::RestoreScreen(int x, int y, int dx, int dy, fb_pixel_t * cons
|
|||||||
|
|
||||||
void CFrameBuffer::switch_signal (int signal)
|
void CFrameBuffer::switch_signal (int signal)
|
||||||
{
|
{
|
||||||
|
#ifndef USE_OPENGL /* ignore signals for GL */
|
||||||
CFrameBuffer * thiz = CFrameBuffer::getInstance();
|
CFrameBuffer * thiz = CFrameBuffer::getInstance();
|
||||||
if (signal == SIGUSR1) {
|
if (signal == SIGUSR1) {
|
||||||
if (virtual_fb != NULL)
|
if (virtual_fb != NULL)
|
||||||
@@ -1745,6 +1793,7 @@ void CFrameBuffer::switch_signal (int signal)
|
|||||||
else
|
else
|
||||||
memset(thiz->lfb, 0, thiz->stride * thiz->yRes);
|
memset(thiz->lfb, 0, thiz->stride * thiz->yRes);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFrameBuffer::Clear()
|
void CFrameBuffer::Clear()
|
||||||
|
@@ -53,6 +53,13 @@ typedef struct fb_var_screeninfo t_fb_var_screeninfo;
|
|||||||
#define FADE_STEP 5
|
#define FADE_STEP 5
|
||||||
#define FADE_RESET 0xFFFF
|
#define FADE_RESET 0xFFFF
|
||||||
|
|
||||||
|
#if HAVE_GENERIC_HARDWARE
|
||||||
|
#define USE_OPENGL 1
|
||||||
|
#endif
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
class GLThreadObj;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Ausfuehrung als Singleton */
|
/** Ausfuehrung als Singleton */
|
||||||
class CFrameBuffer
|
class CFrameBuffer
|
||||||
{
|
{
|
||||||
@@ -121,6 +128,10 @@ class CFrameBuffer
|
|||||||
void blitIcon(int src_width, int src_height, int fb_x, int fb_y, int width, int height);
|
void blitIcon(int src_width, int src_height, int fb_x, int fb_y, int width, int height);
|
||||||
#endif
|
#endif
|
||||||
int m_transparent_default, m_transparent;
|
int m_transparent_default, m_transparent;
|
||||||
|
#ifdef USE_OPENGL
|
||||||
|
GLThreadObj *mpGLThreadObj; /* the thread object */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
fb_pixel_t realcolor[256];
|
fb_pixel_t realcolor[256];
|
||||||
|
529
src/driver/glthread.cpp
Normal file
529
src/driver/glthread.cpp
Normal file
@@ -0,0 +1,529 @@
|
|||||||
|
/*
|
||||||
|
Neutrino-GUI - DBoxII-Project
|
||||||
|
|
||||||
|
Copyright 2010 Carsten Juttner <carjay@gmx.net>
|
||||||
|
Copyright 2012 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
|
||||||
|
|
||||||
|
License: GPL
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY 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, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include "global.h"
|
||||||
|
#include "neutrinoMessages.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include "GL/glew.h"
|
||||||
|
#include "GL/freeglut.h"
|
||||||
|
}
|
||||||
|
#include "decodethread.h"
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#endif
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "glthread.h"
|
||||||
|
|
||||||
|
static GLThreadObj *gThiz = 0; /* GLUT does not allow for an arbitrary argument to the render func */
|
||||||
|
|
||||||
|
GLThreadObj::GLThreadObj(int x, int y) : mX(x), mY(y), mReInit(true), mShutDown(false), mInitDone(false)
|
||||||
|
{
|
||||||
|
mState.width = mX;
|
||||||
|
mState.height = mY;
|
||||||
|
mState.go3d = false;
|
||||||
|
|
||||||
|
initKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLThreadObj::~GLThreadObj()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
GLThreadObj::GLThreadObj(GLThreadObj &rhs)
|
||||||
|
{
|
||||||
|
/* lock rhs only since this is not usable yet */
|
||||||
|
// rhs.mMutex.lock();
|
||||||
|
mX = rhs.mX;
|
||||||
|
mY = rhs.mY;
|
||||||
|
mReInit = rhs.mReInit;
|
||||||
|
mOSDBuffer = rhs.mOSDBuffer;
|
||||||
|
mInitDone = rhs.mInitDone;
|
||||||
|
mState = rhs.mState;
|
||||||
|
mKeyMap = rhs.mKeyMap;
|
||||||
|
mSpecialMap = rhs.mSpecialMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLThreadObj const &GLThreadObj::operator= (GLThreadObj const &rhs)
|
||||||
|
{
|
||||||
|
if(&rhs != this)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* but here we need to lock both */
|
||||||
|
if (&mMutex < &rhs.mMutex)
|
||||||
|
{
|
||||||
|
mMutex.lock();
|
||||||
|
rhs.mMutex.lock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rhs.mMutex.lock();
|
||||||
|
mMutex.lock();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
mX = rhs.mX;
|
||||||
|
mY = rhs.mY;
|
||||||
|
mReInit = rhs.mReInit;
|
||||||
|
mOSDBuffer = rhs.mOSDBuffer;
|
||||||
|
mInitDone = rhs.mInitDone;
|
||||||
|
mState = rhs.mState;
|
||||||
|
mKeyMap = rhs.mKeyMap;
|
||||||
|
mSpecialMap = rhs.mSpecialMap;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void GLThreadObj::initKeys()
|
||||||
|
{
|
||||||
|
mSpecialMap[GLUT_KEY_UP] = CRCInput::RC_up;
|
||||||
|
mSpecialMap[GLUT_KEY_DOWN] = CRCInput::RC_down;
|
||||||
|
mSpecialMap[GLUT_KEY_LEFT] = CRCInput::RC_left;
|
||||||
|
mSpecialMap[GLUT_KEY_RIGHT] = CRCInput::RC_right;
|
||||||
|
|
||||||
|
mSpecialMap[GLUT_KEY_F1] = CRCInput::RC_red;
|
||||||
|
mSpecialMap[GLUT_KEY_F2] = CRCInput::RC_green;
|
||||||
|
mSpecialMap[GLUT_KEY_F3] = CRCInput::RC_blue;
|
||||||
|
mSpecialMap[GLUT_KEY_F4] = CRCInput::RC_yellow;
|
||||||
|
|
||||||
|
mSpecialMap[GLUT_KEY_PAGE_UP] = CRCInput::RC_page_up;
|
||||||
|
mSpecialMap[GLUT_KEY_PAGE_DOWN] = CRCInput::RC_page_down;
|
||||||
|
|
||||||
|
mKeyMap[0x0d] = CRCInput::RC_ok;
|
||||||
|
mKeyMap[0x1b] = CRCInput::RC_home;
|
||||||
|
mKeyMap['i'] = CRCInput::RC_info;
|
||||||
|
mKeyMap['m'] = CRCInput::RC_setup;
|
||||||
|
|
||||||
|
mKeyMap['-'] = CRCInput::RC_spkr;
|
||||||
|
mKeyMap['h'] = CRCInput::RC_help;
|
||||||
|
|
||||||
|
mKeyMap['0'] = CRCInput::RC_0;
|
||||||
|
mKeyMap['1'] = CRCInput::RC_1;
|
||||||
|
mKeyMap['2'] = CRCInput::RC_2;
|
||||||
|
mKeyMap['3'] = CRCInput::RC_3;
|
||||||
|
mKeyMap['4'] = CRCInput::RC_4;
|
||||||
|
mKeyMap['5'] = CRCInput::RC_5;
|
||||||
|
mKeyMap['6'] = CRCInput::RC_6;
|
||||||
|
mKeyMap['7'] = CRCInput::RC_7;
|
||||||
|
mKeyMap['8'] = CRCInput::RC_8;
|
||||||
|
mKeyMap['9'] = CRCInput::RC_9;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLThreadObj::run()
|
||||||
|
{
|
||||||
|
setupCtx();
|
||||||
|
setupOSDBuffer();
|
||||||
|
|
||||||
|
initDone(); /* signal that setup is finished */
|
||||||
|
|
||||||
|
/* init the good stuff */
|
||||||
|
GLenum err = glewInit();
|
||||||
|
if(err == GLEW_OK)
|
||||||
|
{
|
||||||
|
if((!GLEW_VERSION_1_5)||(!GLEW_EXT_pixel_buffer_object)||(!GLEW_ARB_texture_non_power_of_two))
|
||||||
|
{
|
||||||
|
std::cout << "Sorry, your graphics card is not supported. Needs at least OpenGL 1.5, pixel buffer objects and NPOT textures." << std::endl;
|
||||||
|
perror("incompatible graphics card");
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* start decode thread */
|
||||||
|
#if 0
|
||||||
|
mpSWDecoder = boost::shared_ptr<SWDecoder>(new SWDecoder());
|
||||||
|
if(mpSWDecoder)
|
||||||
|
{ /* kick off the GL thread for the window */
|
||||||
|
mSWDecoderThread = boost::thread(boost::ref(*mpSWDecoder));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
gThiz = this;
|
||||||
|
glutDisplayFunc(GLThreadObj::rendercb);
|
||||||
|
glutKeyboardFunc(GLThreadObj::keyboardcb);
|
||||||
|
glutSpecialFunc(GLThreadObj::specialcb);
|
||||||
|
setupGLObjects(); /* needs GLEW prototypes */
|
||||||
|
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
|
||||||
|
glutMainLoop();
|
||||||
|
releaseGLObjects();
|
||||||
|
#if 0
|
||||||
|
if(mpSWDecoder)
|
||||||
|
{
|
||||||
|
mpSWDecoder->doFinish();
|
||||||
|
mSWDecoderThread.join();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("GLThread: error initializing glew: %d\n", err);
|
||||||
|
}
|
||||||
|
if(g_RCInput)
|
||||||
|
{
|
||||||
|
g_RCInput->postMsg(NeutrinoMessages::SHUTDOWN, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* yeah, whatever... */
|
||||||
|
::kill(getpid(), SIGKILL);
|
||||||
|
}
|
||||||
|
std::cout << "GL thread stopping" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::setupCtx()
|
||||||
|
{
|
||||||
|
int argc = 1;
|
||||||
|
/* some dummy commandline for GLUT to be happy */
|
||||||
|
char const *argv[2] = { "neutrino", 0 };
|
||||||
|
std::cout << "GL thread starting" << std::endl;
|
||||||
|
glutInit(&argc, const_cast<char **>(argv));
|
||||||
|
glutInitWindowSize(mX, mY);
|
||||||
|
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
|
||||||
|
glutCreateWindow("Neutrino");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::setupOSDBuffer()
|
||||||
|
{ /* the OSD buffer size can be decoupled from the actual
|
||||||
|
window size since the GL can blit-stretch with no
|
||||||
|
trouble at all, ah, the luxury of ignorance... */
|
||||||
|
// mMutex.lock();
|
||||||
|
if(mState.width && mState.height)
|
||||||
|
{
|
||||||
|
mOSDBuffer.resize(mState.width * mState.height * 4);
|
||||||
|
printf("OSD buffer set to %d bytes\n", mState.width * mState.height * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::setupGLObjects()
|
||||||
|
{
|
||||||
|
glGenTextures(1, &mState.osdtex);
|
||||||
|
// glGenTextures(1, &mState.displaytex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mState.width, mState.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
|
||||||
|
// glBindTexture(GL_TEXTURE_2D, mState.displaytex); /* we do not yet know the size so will set that inline */
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
|
||||||
|
glGenBuffers(1, &mState.pbo);
|
||||||
|
// glGenBuffers(1, &mState.displaypbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::releaseGLObjects()
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &mState.osdtex);
|
||||||
|
// glDeleteTextures(1, &mState.displaytex);
|
||||||
|
glDeleteBuffers(1, &mState.pbo);
|
||||||
|
// glDeleteBuffers(1, &mState.displaypbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static */ void GLThreadObj::rendercb()
|
||||||
|
{
|
||||||
|
gThiz->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static */ void GLThreadObj::keyboardcb(unsigned char key, int /*x*/, int /*y*/)
|
||||||
|
{
|
||||||
|
std::map<unsigned char, neutrino_msg_t>::const_iterator i = gThiz->mKeyMap.find(key);
|
||||||
|
if(i != gThiz->mKeyMap.end())
|
||||||
|
{ /* let's assume globals are thread-safe */
|
||||||
|
if(g_RCInput)
|
||||||
|
{
|
||||||
|
g_RCInput->postMsg(i->second, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static */ void GLThreadObj::specialcb(int key, int /*x*/, int /*y*/)
|
||||||
|
{
|
||||||
|
std::map<int, neutrino_msg_t>::const_iterator i = gThiz->mSpecialMap.find(key);
|
||||||
|
if(key == GLUT_KEY_F12)
|
||||||
|
{
|
||||||
|
gThiz->mState.go3d = gThiz->mState.go3d ? false : true;
|
||||||
|
gThiz->mReInit = true;
|
||||||
|
}
|
||||||
|
else if(i != gThiz->mSpecialMap.end())
|
||||||
|
{
|
||||||
|
if(g_RCInput)
|
||||||
|
{
|
||||||
|
g_RCInput->postMsg(i->second, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLThreadObj::render() {
|
||||||
|
if(!mReInit)
|
||||||
|
{ /* for example if window is resized */
|
||||||
|
checkReinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mShutDown)
|
||||||
|
{
|
||||||
|
glutLeaveMainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mReInit)
|
||||||
|
{
|
||||||
|
mReInit = false;
|
||||||
|
glViewport(0, 0, mX, mY);
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
float aspect = static_cast<float>(mX)/mY;
|
||||||
|
float osdaspect = 1.0/(static_cast<float>(mState.width)/mState.height);
|
||||||
|
if(!mState.go3d)
|
||||||
|
{
|
||||||
|
glOrtho(aspect*-osdaspect, aspect*osdaspect, -1.0, 1.0, -1.0, 1.0 );
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* carjay is crazy... :-) */
|
||||||
|
gluPerspective(45.0, static_cast<float>(mX)/mY, 0.05, 1000.0);
|
||||||
|
glTranslatef(0.0, 0.0, -2.0);
|
||||||
|
glClearColor(0.25, 0.25, 0.25, 1.0);
|
||||||
|
}
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bltDisplayBuffer(); /* decoded video stream */
|
||||||
|
bltOSDBuffer(); /* OSD */
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
// cube test
|
||||||
|
if(mState.go3d)
|
||||||
|
{
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
static float ydeg = 0.0;
|
||||||
|
glPushMatrix();
|
||||||
|
glRotatef(ydeg, 0.0, 1.0, 0.0);
|
||||||
|
// glBindTexture(GL_TEXTURE_2D, mState.displaytex);
|
||||||
|
// drawCube(0.5);
|
||||||
|
glScalef(1.01, 1.01, 1.01);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
|
||||||
|
drawCube(0.5);
|
||||||
|
glPopMatrix();
|
||||||
|
ydeg += 0.75f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// glBindTexture(GL_TEXTURE_2D, mState.displaytex);
|
||||||
|
// drawSquare(1.0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
|
||||||
|
drawSquare(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
glutSwapBuffers();
|
||||||
|
|
||||||
|
GLuint err = glGetError();
|
||||||
|
if(err != 0)
|
||||||
|
{
|
||||||
|
printf("GLError:%d 0x%04x\n", err, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simply limit to 30 Hz, if anyone wants to do this properly, feel free */
|
||||||
|
// boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(34));
|
||||||
|
usleep(34000);
|
||||||
|
glutPostRedisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::checkReinit()
|
||||||
|
{
|
||||||
|
int x = glutGet(GLUT_WINDOW_WIDTH);
|
||||||
|
int y = glutGet(GLUT_WINDOW_HEIGHT);
|
||||||
|
if( x != mX || y != mY )
|
||||||
|
{
|
||||||
|
mX = x;
|
||||||
|
mY = y;
|
||||||
|
mReInit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::drawCube(float size)
|
||||||
|
{
|
||||||
|
GLfloat vertices[] = {
|
||||||
|
1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, -1.0f,
|
||||||
|
1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, -1.0f, -1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
GLubyte indices[] = {
|
||||||
|
0, 1, 2, 3, /* front */
|
||||||
|
0, 3, 4, 5, /* right */
|
||||||
|
0, 5, 6, 1, /* top */
|
||||||
|
1, 6, 7, 2, /* left */
|
||||||
|
7, 4, 3, 2, /* bottom */
|
||||||
|
4, 7, 6, 5 /* back */
|
||||||
|
};
|
||||||
|
|
||||||
|
GLfloat texcoords[] = {
|
||||||
|
1.0, 0.0, // v0
|
||||||
|
0.0, 0.0, // v1
|
||||||
|
0.0, 1.0, // v2
|
||||||
|
1.0, 1.0, // v3
|
||||||
|
0.0, 1.0, // v4
|
||||||
|
0.0, 0.0, // v5
|
||||||
|
1.0, 0.0, // v6
|
||||||
|
1.0, 1.0 // v7
|
||||||
|
};
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(size, size, size);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, vertices);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
|
||||||
|
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, indices);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::drawSquare(float size)
|
||||||
|
{
|
||||||
|
GLfloat vertices[] = {
|
||||||
|
1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f,
|
||||||
|
-1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
GLubyte indices[] = { 0, 1, 2, 3 };
|
||||||
|
|
||||||
|
GLfloat texcoords[] = {
|
||||||
|
1.0, 0.0,
|
||||||
|
0.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glScalef(size, size, size);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, vertices);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
|
||||||
|
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::initDone()
|
||||||
|
{
|
||||||
|
// mMutex.lock();
|
||||||
|
mInitDone = true;
|
||||||
|
// mInitCond.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::waitInit()
|
||||||
|
{
|
||||||
|
// mMutex.lock();
|
||||||
|
while(!mInitDone)
|
||||||
|
{
|
||||||
|
// mInitCond.wait(lock);
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLThreadObj::bltOSDBuffer()
|
||||||
|
{
|
||||||
|
/* FIXME: copy each time */
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mState.pbo);
|
||||||
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, mOSDBuffer.size(), &mOSDBuffer[0], GL_STREAM_DRAW_ARB);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mState.width, mState.height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void GLThreadObj::bltDisplayBuffer()
|
||||||
|
{
|
||||||
|
if(mpSWDecoder)
|
||||||
|
{
|
||||||
|
SWDecoder::pBuffer_t displaybuffer = mpSWDecoder->acquireDisplayBuffer();
|
||||||
|
if(displaybuffer != 0)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mState.displaypbo);
|
||||||
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, displaybuffer->size(), &(*displaybuffer)[0], GL_STREAM_DRAW_ARB);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mState.displaytex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, displaybuffer->width(), displaybuffer->height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
mpSWDecoder->returnDisplayBuffer(displaybuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void GLThreadObj::clear()
|
||||||
|
{
|
||||||
|
memset(&mOSDBuffer[0], 0, mOSDBuffer.size());
|
||||||
|
}
|
103
src/driver/glthread.h
Normal file
103
src/driver/glthread.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Neutrino-GUI - DBoxII-Project
|
||||||
|
|
||||||
|
Copyright 2010 Carsten Juttner <carjay@gmx.net>
|
||||||
|
Copyright 2012 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
|
||||||
|
|
||||||
|
License: GPL
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY 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, write to the Free Software
|
||||||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __glthread__
|
||||||
|
#define __glthread__
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
//#include <OpenThreads/Condition>
|
||||||
|
#include <vector>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <GL/freeglut.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
//class SWDecoder;
|
||||||
|
|
||||||
|
/* TODO: some stuff is probably not needed without the SW decoder... */
|
||||||
|
class GLThreadObj : public OpenThreads::Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GLThreadObj(int x, int y);
|
||||||
|
~GLThreadObj();
|
||||||
|
// GLThreadObj(GLThreadObj &rhs);
|
||||||
|
// GLThreadObj const &operator= (GLThreadObj const &rhs);
|
||||||
|
// void operator()();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void Start() { OpenThreads::Thread::start(); }
|
||||||
|
void waitInit(); /* wait until things are set up */
|
||||||
|
void shutDown() { mShutDown = true; } /* shut down event loop (causes thread to exit) */
|
||||||
|
void join() { OpenThreads::Thread::join(); }
|
||||||
|
unsigned char *getOSDBuffer() { return &mOSDBuffer[0]; } /* gets pointer to OSD bounce buffer */
|
||||||
|
|
||||||
|
int getOSDWidth() { return mState.width; }
|
||||||
|
int getOSDHeight() { return mState.height; }
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mX; /* window size */
|
||||||
|
int mY;
|
||||||
|
bool mReInit; /* setup things for GL */
|
||||||
|
bool mShutDown; /* if set main loop is left */
|
||||||
|
bool mInitDone; /* condition predicate */
|
||||||
|
// OpenThreads::Condition mInitCond; /* condition variable for init */
|
||||||
|
// mutable OpenThreads::Mutex mMutex; /* lock our data */
|
||||||
|
|
||||||
|
std::vector<unsigned char> mOSDBuffer; /* silly bounce buffer */
|
||||||
|
|
||||||
|
std::map<unsigned char, neutrino_msg_t> mKeyMap;
|
||||||
|
std::map<int, neutrino_msg_t> mSpecialMap;
|
||||||
|
|
||||||
|
void checkReinit(); /* e.g. in case window was resized */
|
||||||
|
static void rendercb(); /* callback for GLUT */
|
||||||
|
void render(); /* actual render function */
|
||||||
|
static void keyboardcb(unsigned char key, int x, int y);
|
||||||
|
static void specialcb(int key, int x, int y);
|
||||||
|
|
||||||
|
void initKeys(); /* setup key bindings for window */
|
||||||
|
void setupCtx(); /* create the window and make the context current */
|
||||||
|
void setupOSDBuffer(); /* create the OSD buffer */
|
||||||
|
void setupGLObjects(); /* PBOs, textures and stuff */
|
||||||
|
void releaseGLObjects();
|
||||||
|
void eventLoop(); /* enter the GL window event loop */
|
||||||
|
void drawCube(float size); /* cubes are the building blocks of our society */
|
||||||
|
void drawSquare(float size); /* do not be square */
|
||||||
|
void initDone(); /* "things are now set up", called by this */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int width; /* width and height, fixed for a framebuffer instance */
|
||||||
|
int height;
|
||||||
|
GLuint osdtex; /* holds the OSD texture */
|
||||||
|
GLuint pbo; /* PBO we use for transfer to texture */
|
||||||
|
// GLuint displaytex; /* holds the display texture */
|
||||||
|
// GLuint displaypbo;
|
||||||
|
int go3d;
|
||||||
|
} mState;
|
||||||
|
|
||||||
|
// boost::shared_ptr<SWDecoder>mpSWDecoder; /* our Decoder-Object that runs in its own thread */
|
||||||
|
// boost::thread mSWDecoderThread; /* thread running the decoder */
|
||||||
|
|
||||||
|
void bltOSDBuffer();
|
||||||
|
// void bltDisplayBuffer();
|
||||||
|
};
|
||||||
|
#endif
|
Reference in New Issue
Block a user