diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-06 13:54:07 +0100 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-12-06 13:54:07 +0100 |
commit | ba1c7be72879f9954029aa54023ac30a6e66710d (patch) | |
tree | 9b542ef6f9fc29756b630397fe911ab8438e87f0 /src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp | |
parent | ab405ff9fcb670367454ceb18c02175b9d74de7e (diff) |
threaded texture uploader for lighthouse's EglFStexturemanager
Diffstat (limited to 'src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp')
-rw-r--r-- | src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp b/src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp new file mode 100644 index 0000000..b868979 --- /dev/null +++ b/src/adaptationlayers/qsgeglfsthreadedtexturemanager.cpp @@ -0,0 +1,169 @@ +#include "qsgeglfsthreadedtexturemanager.h" + +#include <QThread> +#include <qdatetime.h> + +#include <EGL/egl.h> +#include <GLES2/gl2.h> + + +class QSGEglFSThreadedTextureManagerPrivate +{ +public: + EGLDisplay display; + EGLSurface surface; + EGLContext context; + + bool uploadsScanlines; +}; + + +QSGEglFSThreadedTextureManager::QSGEglFSThreadedTextureManager() + : d(new QSGEglFSThreadedTextureManagerPrivate) +{ + d->uploadsScanlines = false; +} + + +void QSGEglFSThreadedTextureManager::setUploadsScanlines(bool b) +{ + d->uploadsScanlines = b; +} + + +bool QSGEglFSThreadedTextureManager::uploadsScanlines() const +{ + return d->uploadsScanlines; +} + + +void QSGEglFSThreadedTextureManager::initializeThreadContext() +{ + d->display = eglGetCurrentDisplay(); + + EGLint attribs[] = { + EGL_WIDTH, 8, + EGL_HEIGHT, 8, + + EGL_NONE + }; + + EGLConfig configs[256]; + EGLint count; + + d->surface = 0; + EGLConfig *config = 0; + if (eglGetConfigs(d->display, configs, 256, &count)) { + for (int i=0; i<count; ++i) { + int type; + eglGetConfigAttrib(d->display, configs[i], EGL_RENDERABLE_TYPE, &type); + if (!(type & EGL_OPENGL_ES2_BIT)) + continue; + + int r, g, b, a; + eglGetConfigAttrib(d->display, configs[i], EGL_RED_SIZE, &r); + eglGetConfigAttrib(d->display, configs[i], EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(d->display, configs[i], EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(d->display, configs[i], EGL_ALPHA_SIZE, &a); + + if ((r & g & b & a) == 8) { + d->surface = eglCreatePbufferSurface(d->display, configs[i], attribs); + config = configs + i; + break; + } + } + } + d->context = eglCreateContext(d->display, *config, eglGetCurrentContext(), 0); +} + + +void QSGEglFSThreadedTextureManager::makeThreadContextCurrent() +{ + eglMakeCurrent(d->display, d->surface, d->surface, d->context); +} + +class ThreadAccess : public QThread +{ +public: + static void doSleep(int us) { + usleep(us); + } +}; + + +static inline void qgl_byteSwapImage(QImage &img) +{ + const int width = img.width(); + const int height = img.height(); + + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } +} + +#define DO_TIMING + +void QSGEglFSThreadedTextureManager::uploadInThread(TextureReference *texture, const QImage &im, UploadHints hints) +{ + while (glGetError() != GL_NO_ERROR) printf("bust...\n"); + +#ifdef DO_TIMING + QTime time; + time.start(); +#endif + + QImage image = im; + qgl_byteSwapImage(image); + +#ifdef DO_TIMING + int time_byteswap = time.elapsed(); +#endif + + int w = image.width(); + int h = image.height(); + int bpl = image.bytesPerLine(); + const uchar *bits = image.constBits(); + + // This should not be neccesary... + if (d->uploadsScanlines) + makeThreadContextCurrent(); + + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + + if (d->uploadsScanlines) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, id); // Should also not be required, but it fails without... driver bug, for sure.. + for (int y=0; y<h; ++y) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, w, 1, GL_RGBA, GL_UNSIGNED_BYTE, y * bpl + bits); + if (glGetError() != GL_NO_ERROR) { + qWarning("ERROR: failed to upload chunk...\n"); + break; + } + ThreadAccess::doSleep(2); + } + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits); + } + + glBindTexture(GL_TEXTURE_2D, 0); + +#ifdef DO_TIMING + int time_upload = time.elapsed(); + printf("EGLFS Threaded upload: byteSwap: %d ms, upload: %d ms\n", + time_byteswap, + time_upload); +#endif + + + texture->setOwnsTexture(true); + texture->setTextureId(id); + texture->setTextureSize(image.size()); + texture->setMipmaps(hints & TextureManager::GenerateMipmapUploadHint); + texture->setStatus(TextureReference::Uploaded); +} + + |