summaryrefslogtreecommitdiffstats
path: root/src/adaptationlayers/threadedtexturemanager.cpp
blob: a1af9cfa026d8302962a1b95fba701694efaf02c (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
#include "threadedtexturemanager.h"

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

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


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;

            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);

            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;
}