summaryrefslogtreecommitdiffstats
path: root/src/adaptationlayers/threadedtexturemanager.cpp
blob: 616f0ec32320ce77d7412ae43468b6e66d988ac4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "threadedtexturemanager.h"

#include <QWaitCondition>
#include <QMutex>
#include <QThread>

#include <QQueue>
#include <QPaintDevice>
#include <QGLWidget>

#include <qdatetime.h>

#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif

struct TextureToUpload
{
    QImage image;
    TextureReference *texture;
    TextureManager::UploadHints hints;
};

class QSGTTMUploadThread : public QThread
{
public:
    QSGTTMUploadThread() {
        QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
        // Getting the share widget from the current context is rather nasty and
        // will not work for lighthouse based
        Q_ASSERT(ctx->device() && ctx->device()->devType() == QInternal::Widget);

        QGLWidget *share = static_cast<QGLWidget *>(ctx->device());

        widget = new QGLWidget(0, share);
        widget->resize(8, 8);

        context = const_cast<QGLContext *>(widget->context());

        widget->doneCurrent();

        ctx->makeCurrent();

        start();
    }

    void run() {

        context->makeCurrent();

        while (true) {

            mutex.lock();
            if (requests.isEmpty()) {
                condition.wait(&mutex);
            }

            if (requests.isEmpty()) {
                mutex.unlock();
                continue;
            }

            TextureToUpload work = requests.dequeue();
            mutex.unlock();

            if (work.image.isNull())
                continue;

#ifdef QT_OPENGL_ES
            qWarning("ThreadedTextureManager: Chances are that BGRA does not work on GLES");
#endif

            GLuint id;
            glGenTextures(1, &id);
            glBindTexture(GL_TEXTURE_2D, id);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, work.image.width(), work.image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, work.image.constBits());

            if (work.hints & TextureManager::GenerateMipmapUploadHint)
                glGenerateMipmap(GL_TEXTURE_2D);

            glBindTexture(GL_TEXTURE_2D, 0);

            work.texture->setTextureId(id);
            work.texture->setTextureSize(work.image.size());
            work.texture->setMipmaps(work.hints & TextureManager::GenerateMipmapUploadHint);
            work.texture->setStatus(TextureReference::Uploaded);
        }
    }

    QGLWidget *widget;
    QGLContext *context;

    QWaitCondition condition;
    QMutex mutex;

    QQueue<TextureToUpload> requests;
};

class QSGThreadedTextureManagerPrivate
{
public:
    QSGTTMUploadThread thread;
};

QSGThreadedTextureManager::QSGThreadedTextureManager()
{
    d = new QSGThreadedTextureManagerPrivate;
}

const TextureReference *QSGThreadedTextureManager::requestUploadedTexture(const QImage &image, UploadHints hints, QObject *listener, const char *slot)
{
    Q_ASSERT(!image.isNull());

    if (hints & SynchronousUploadHint) {
        return TextureManager::requestUploadedTexture(image, hints, listener, slot);
    }

    TextureToUpload work;
    work.texture = new TextureReference;
    work.image = image;
    work.hints = hints;

    QObject::connect(work.texture, SIGNAL(statusChanged(int)), listener, slot);

    d->thread.mutex.lock();

    d->thread.requests << work;
    d->thread.condition.wakeOne();
    d->thread.mutex.unlock();

    return work.texture;
}