Commit 36bd0aa2 by Ludmány Balázs

Refactor

parent 14d916c7
......@@ -29,12 +29,11 @@ HEADERS += \
jpegdecoder.h \
qvnc.h \
uploader.h \
dispatcher.h
dispatcher.h \
concurrentqueue.h
DISTFILES += \
draw_shader.fsh \
draw_shader.vsh \
fill_shader.vsh \
fill_shader.fsh \
copy_shader.vsh \
copy_shader.fsh
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2016-07-11T16:48:08. -->
<!-- Written by QtCreator 3.5.1, 2016-07-19T13:32:08. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
......@@ -61,7 +61,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{9fe100e5-65f5-4993-908d-e24f092a1cff}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
......@@ -237,7 +237,9 @@
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes">
<value type="QString">QML_SHOW_FRAMERATE=1</value>
</valuelist>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">ThinClient</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/media/ldmnyblzs/files/Projects/ThinClient/ThinClient.pro</value>
......@@ -247,11 +249,11 @@
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
......
#ifndef CONCURRENTQUEUE_H
#define CONCURRENTQUEUE_H
#include <QSemaphore>
template <class T, const unsigned short S>
class ConcurrentQueue
{
public:
ConcurrentQueue();
void enqueue(const T &t);
T dequeue();
bool isEmpty() const;
private:
T m_buffer[S];
unsigned short m_next;
unsigned short m_first;
QSemaphore m_free;
QSemaphore m_used;
};
template <class T, const unsigned short S>
ConcurrentQueue<T, S>::ConcurrentQueue() :
m_next(0), m_first(0), m_free(S), m_used(0)
{
}
template <class T, const unsigned short S>
void ConcurrentQueue<T, S>::enqueue(const T &t)
{
m_free.acquire();
m_buffer[m_next] = t;
m_next = (m_next + 1) % S;
m_used.release();
}
template <class T, const unsigned short S>
T ConcurrentQueue<T, S>::dequeue()
{
T temp;
m_used.acquire();
temp = m_buffer[m_first];
m_first = (m_first + 1) % S;
m_free.release();
return temp;
}
template <class T, const unsigned short S>
bool ConcurrentQueue<T, S>::isEmpty() const
{
return (m_first == m_next);
}
#endif // CONCURRENTQUEUE_H
#include "dispatcher.h"
Dispatcher::Dispatcher(QObject *parent) : QObject(parent), m_uploader(this)
Dispatcher::Dispatcher(Uploader *uploader, QObject *parent) :
QObject(parent), m_client(NULL), m_uploader(uploader)
{
}
......@@ -14,7 +15,7 @@ rfbBool Dispatcher::MallocFrameBuffer(rfbClient *client)
void Dispatcher::GotCopyRect(rfbClient *client, int src_x, int src_y, int w, int h, int dest_x, int dest_y)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->uploader().gotCopyRect(src_x, src_y, w, h, dest_x, dest_y);
dispatcher->uploader()->gotCopy(src_x, src_y, w, h, dest_x, dest_y);
}
void Dispatcher::GotFillRect(rfbClient *client, int x, int y, int w, int h, uint32_t colour)
......@@ -23,138 +24,68 @@ void Dispatcher::GotFillRect(rfbClient *client, int x, int y, int w, int h, uint
int red = (colour >> client->format.redShift) & client->format.redMax;
int green = (colour >> client->format.greenShift) & client->format.greenMax;
int blue = (colour >> client->format.blueShift) & client->format.blueMax;
dispatcher->uploader().gotFillRect(x, y, w, h, red, green, blue);
dispatcher->uploader()->gotFill(x, y, w, h, red, green, blue);
}
void Dispatcher::GotBitmap(rfbClient *client, const uint8_t *buffer, int x, int y, int w, int h)
{
QImage img;
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
switch(dispatcher->bitsPerPixel()) {
case 8:
img = QImage(buffer, w, h, QImage::Format_Grayscale8);
break;
case 16:
img = QImage(buffer, w, h, QImage::Format_RGB16);
break;
case 32:
img = QImage(buffer, w, h, QImage::Format_RGBX8888);
break;
default:
emit dispatcher->error();
return;
}
// We have to make a deep copy because libvnc might free the buffer as soon as this function returns
dispatcher->uploader().gotBitmap(img.copy(), x, y, w, h);
dispatcher->uploader()->gotBitmap(QByteArray((const char *) buffer, w * h * (dispatcher->bitsPerPixel() / 8)), x, y, w, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE);
}
rfbBool Dispatcher::GotJpeg(rfbClient *client, const uint8_t *buffer, int length, int x, int y, int w, int h)
{
Dispatcher *dispatcher = static_cast<Dispatcher *>(rfbClientGetClientData(client, 0));
QByteArray jpeg;
jpeg.setRawData((const char*) buffer, length);
JpegDecoder *decoder = new JpegDecoder(jpeg, x, y, w, h);
dispatcher->incrementDecoderCount();
connect(decoder, &JpegDecoder::finished, dispatcher, &Dispatcher::decodingFinished, Qt::QueuedConnection);
QThreadPool::globalInstance()->start(decoder);
Jpeg *jpeg = new Jpeg(QByteArray::fromRawData((const char *) buffer, length),
dispatcher->uploader()->gotJpeg(x, y, w, h));
dispatcher->queue()->enqueue(jpeg);
return TRUE;
}
void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->setFinished(true);
if(dispatcher->decoderCount() == 0) {
dispatcher->uploader().finishedUpdate();
emit dispatcher->updateFramebuffer();
}
dispatcher->uploader()->finishedUpdate();
}
void Dispatcher::setMouse(int x, int y, bool left, bool middle, bool right)
bool Dispatcher::mouseEvent(const int x, const int y, const bool left, const bool middle, const bool right, const bool up, const bool down)
{
if(m_client == NULL)
return;
return false;
int buttonMask = 0;
if(left) buttonMask |= rfbButton1Mask;
if(middle) buttonMask |= rfbButton2Mask;
if(right) buttonMask |= rfbButton3Mask;
if(right) buttonMask |= rfbButton2Mask;
if(middle) buttonMask |= rfbButton3Mask;
if(up) buttonMask |= rfbButton4Mask;
if(down) buttonMask |= rfbButton5Mask;
SendPointerEvent(m_client, x, y, buttonMask);
}
unsigned int Dispatcher::decoderCount() const
{
return m_decoderCount;
}
unsigned int Dispatcher::incrementDecoderCount()
{
return ++m_decoderCount;
}
unsigned int Dispatcher::decrementDecoderCount()
{
return --m_decoderCount;
return true;
}
int Dispatcher::bitsPerPixel()
{
return m_client->format.bitsPerPixel;
}
Uploader &Dispatcher::uploader()
{
return m_uploader;
}
void Dispatcher::setFinished(bool finished)
{
m_finished = finished;
}
bool Dispatcher::finished() const
{
return m_finished;
}
unsigned int Dispatcher::fill_count()
{
if(m_finished && m_decoderCount == 0)
return m_uploader.fill_count();
else
return 0;
}
unsigned int Dispatcher::copy_count()
{
if(m_finished && m_decoderCount == 0)
return m_uploader.copy_count();
else
return 0;
}
unsigned int Dispatcher::draw_count()
{
if(m_finished && m_decoderCount == 0)
return m_uploader.draw_count();
else
if(m_client == NULL)
return 0;
return m_client->format.bitsPerPixel;
}
QVector3D Dispatcher::colorMax() const
{
if(m_client == NULL)
return QVector3D();
return QVector3D(m_client->format.redMax, m_client->format.greenMax, m_client->format.blueMax);
}
void Dispatcher::create_context(QOpenGLContext *context)
ConcurrentQueue<Jpeg *, 64u> *Dispatcher::queue()
{
m_uploader.create_context(context);
return &m_queue;
}
Uploader *Dispatcher::uploader() const
{
return m_uploader;
}
void Dispatcher::open(QString host, int port)
......@@ -174,13 +105,51 @@ void Dispatcher::open(QString host, int port)
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
m_client->appData.useRemoteCursor = TRUE;
// Set the format requested by the user
m_client->width = 1024;
m_client->height = 768;
m_client->appData.compressLevel = 0;
m_client->appData.qualityLevel = 0;
#ifdef __BIG_ENDIAN__
m_client->format.bigEndian = TRUE;
#else
m_client->format.bigEndian = FALSE;
#endif
// The Raspberry Pi supports 8 bit paletted images and RGB422 too but only through extensions
m_client->format.trueColour = TRUE;
m_client->format.bitsPerPixel = 32;
rfbClientSetClientData(m_client, 0, this);
if(!rfbInitClient(m_client, NULL, NULL)) {
emit error();
return;
}
emit colorMaxChanged(colorMax());
// Stick to the format sent by the server if we can render it easily, set a new one otherwise
//
// Formats OpenGL ES 2.0 can (should be able to) handle:
// Internal Format External Format Type Bytes per Pixel
// --------------- --------------- ---- ---------------
// RGBA RGBA UNSIGNED_BYTE 4
// RGB RGB UNSIGNED_BYTE 3
// RGBA RGBA UNSIGNED_SHORT_4_4_4_4 2
// RGBA RGBA UNSIGNED_SHORT_5_5_5_1 2
// RGB RGB UNSIGNED_SHORT_5_6_5 2
// The Raspberry Pi supports BGRA too but only through extensions
//
// JPEG is RGB UNSIGNED_BYTE
// Supported raw formats:
// 32 bit: RGB888
// 16 bit: RGB444, RGB555, RGB565
/*int message = WaitForMessage(m_client, 1000);
if(message < 0) {
terminate();
emit error();
return;
}*/
refresh();
}
void Dispatcher::refresh()
......@@ -188,25 +157,27 @@ void Dispatcher::refresh()
if(m_client == NULL)
return;
setFinished(false);
m_uploader.startedUpdate();
m_uploader->cleanup();
int message = 0;
if(!HandleRFBServerMessage(m_client)) {
terminate();
emit error();
return;
}
// Don't block uploading!
// Wait until we get something
while(message == 0) {
message = WaitForMessage(m_client, 10000);
QCoreApplication::processEvents();
message = WaitForMessage(m_client, 1000);
if(message < 0) {
terminate();
emit error();
return;
}
if (message) {
if(!HandleRFBServerMessage(m_client)) {
terminate();
emit error();
return;
}
}
}
}
......@@ -217,12 +188,3 @@ void Dispatcher::terminate()
rfbClientCleanup(m_client);
}
void Dispatcher::decodingFinished(const QImage &bitmap, const int x, const int y, const int w, const int h)
{
m_uploader.gotBitmap(bitmap, x, y, w, h);
if(m_finished && decrementDecoderCount() == 0) {
m_uploader.finishedUpdate();
emit updateFramebuffer();
}
}
......@@ -21,7 +21,7 @@ class Dispatcher : public QObject
Q_OBJECT
public:
Dispatcher(QObject *parent = 0);
Dispatcher(Uploader *uploader, QObject *parent = Q_NULLPTR);
// libvnc hooks
static rfbBool MallocFrameBuffer(rfbClient* client);
......@@ -31,37 +31,34 @@ public:
static rfbBool GotJpeg(rfbClient* client, const uint8_t* buffer, int length, int x, int y, int w, int h);
static void FinishedFrameBufferUpdate(rfbClient* client);
void setMouse(int x, int y, bool left, bool middle, bool right);
// input events
bool mouseEvent(const int x, const int y, const bool left, const bool middle, const bool right, const bool up, const bool down);
unsigned int decoderCount() const;
unsigned int incrementDecoderCount();
unsigned int decrementDecoderCount();
// parameters of the VNC connection
int bitsPerPixel();
Uploader &uploader();
void setFinished(bool finished);
bool finished() const;
unsigned int fill_count();
unsigned int copy_count();
unsigned int draw_count();
QVector3D colorMax() const;
// getters
ConcurrentQueue<Jpeg *, 64>* queue();
Uploader *uploader() const;
private:
rfbClient *m_client;
unsigned int m_decoderCount;
bool m_finished;
// TODO: move this to QVnc
Uploader m_uploader;
Uploader *m_uploader;
ConcurrentQueue<Jpeg*, 64> m_queue;
signals:
// libvnc events
void gotCopy(const int src_x, const int src_y, const int width, const int height, const int dest_x, const int dest_y);
void gotFill(const int x, const int y, const int width, const int height, const float red, const float green, const float blue);
void gotBitmap(const QImage &image, const quint32 x, const quint32 y, const quint32 width, const quint32 height);
void finishedUpdate();
void resizeFramebuffer(const QSize &size);
void updateFramebuffer();
void colorMaxChanged(const QVector3D &colorMax);
void error();
public slots:
void create_context(QOpenGLContext *context);
// manage VNC connection
void open(QString host, int port);
void refresh();
void terminate();
void decodingFinished(const QImage &bitmap, const int x, const int y, const int w, const int h);
};
#endif // RFBDISPATCH_H
uniform sampler2D texture;
varying lowp vec2 vartexcoord;
varying lowp vec3 varcolor;
varying highp vec2 vartexcoord;
varying highp vec3 varcolor;
void main(void)
{
gl_FragColor = vec4(texture2D(texture, vartexcoord).rgb + varcolor, 1.0);
gl_FragColor = vec4(texture2D(texture, vartexcoord).bgr + varcolor, 1.0);
}
uniform highp mat4 ortho;
uniform lowp vec3 colormax;
attribute highp vec2 position;
attribute lowp vec3 color;
attribute lowp vec2 texcoord;
varying lowp vec3 varcolor;
varying lowp vec2 vartexcoord;
attribute highp vec3 color;
attribute highp vec2 texcoord;
varying highp vec3 varcolor;
varying highp vec2 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color / colormax;
// varcolor = vec3(1.0, 1.0, 0.0);
vartexcoord = texcoord;
}
varying highp vec3 varcolor;
void main(void)
{
gl_FragColor = vec4(varcolor, 1.0);
}
uniform highp mat4 ortho;
uniform highp vec3 colormax;
attribute highp vec2 position;
attribute highp vec3 color;
varying highp vec3 varcolor;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color / colormax;
}
#include "jpegdecoder.h"
JpegDecoder::JpegDecoder(const QByteArray &jpeg, const int x, const int y, const int w, const int h, QObject *parent) :
QObject(parent), QRunnable(), m_jpeg(jpeg), m_x(x), m_y(y), m_w(w), m_h(h)
JpegDecoder::JpegDecoder(ConcurrentQueue<Jpeg *, 64u> *queue, QObject *parent) :
QObject(parent), m_queue(queue)
{
}
void JpegDecoder::run()
void JpegDecoder::operate()
{
m_image.loadFromData(m_jpeg, "JPG");
emit finished(m_image, m_x, m_y, m_w, m_h);
Jpeg *jpeg;
forever {
jpeg = m_queue->dequeue();
QImage image;
image.loadFromData(jpeg->data, "JPEG");
emit finished(image, image.width(), image.height(), jpeg->index);
delete jpeg;
}
}
......@@ -3,30 +3,45 @@
#include <QObject>
#include <QByteArray>
#include <QRunnable>
#include <QPoint>
#include <QSize>
#include <QImage>
#include <QDebug>
#include "concurrentqueue.h"
struct Jpeg {
Jpeg(const QByteArray &d, const int i) :
data(d), index(i)
{
}
~Jpeg()
{
// QByteArray::fromRawData: " QByteArray does not take ownership of data,
// so the QByteArray destructor will never delete the raw data,
// even when the last QByteArray referring to data is destroyed."
delete[] data.constData();
}
QByteArray data;
int index;
};
/*!
* \brief Loads JPEG files on a separate thread
* \brief Loads JPEG images
*
* Consumes
*/
class JpegDecoder : public QObject, public QRunnable
class JpegDecoder : public QObject
{
Q_OBJECT
public:
JpegDecoder(const QByteArray &jpeg, const int x, const int y, const int w, const int h, QObject *parent = 0);
void run();
JpegDecoder(ConcurrentQueue<Jpeg*, 64u> *queue, QObject *parent = 0);
ConcurrentQueue<Jpeg*, 64u> *m_queue;
signals:
void finished(const QImage &image, const int x, const int y, const int w, const int h);
private:
QByteArray m_jpeg;
QImage m_image;
int m_x;
int m_y;
int m_w;
int m_h;
void finished(const QImage &image, const int width, const int height, const int index);
public slots:
void operate();
};
#endif // JPEGDECODER_H
......@@ -29,31 +29,5 @@ ApplicationWindow {
port: 10495
width: 1024
height: 768
/* Keys {
onPressed:
}*/
MouseArea {
anchors.fill: parent
// cursorShape: Qt.BlankCursor
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
onPositionChanged: vnc.setMouse(mouse.x,
mouse.y,
mouse.buttons & Qt.LeftButton,
mouse.buttons & Qt.MiddleButton,
mouse.buttons & Qt.RightButton)
onPressed: vnc.setMouse(mouse.x,
mouse.y,
mouse.buttons & Qt.LeftButton,
mouse.buttons & Qt.MiddleButton,
mouse.buttons & Qt.RightButton)
onReleased: vnc.setMouse(mouse.x,
mouse.y,
mouse.buttons & Qt.LeftButton,
mouse.buttons & Qt.MiddleButton,
mouse.buttons & Qt.RightButton)
}
}
}
#include "qvnc.h"
QVnc::QVnc()
QVnc::QVnc(QQuickItem *parent) :
QQuickFramebufferObject(parent), m_decoders(DECODER_COUNT), m_threads(DECODER_COUNT + 1)
{
setAcceptedMouseButtons(Qt::AllButtons);
setAcceptHoverEvents(true);
setTextureFollowsItemSize(false);
for(int i = 0; i < m_threads.length(); i++)
m_threads[i] = new QThread(this);
connect(this, &QVnc::windowChanged, this, &QVnc::winChanged);
// Don't let Qt change the size of the OpenGL framebuffer
setTextureFollowsItemSize(false);
m_uploader = new Uploader;
m_uploader->moveToThread(m_threads[0]);
m_dispatcher = new Dispatcher;
m_dispatcher->moveToThread(&m_dispatcher_thread);
connect(m_threads[0], &QThread::finished, m_uploader, &QObject::deleteLater);
connect(m_uploader, &Uploader::uploadFinished, this, &QVnc::update);
connect(&m_dispatcher_thread, &QThread::finished, m_dispatcher, &QObject::deleteLater);
m_dispatcher = new Dispatcher(m_uploader);
m_dispatcher->moveToThread(m_threads[0]);
connect(m_threads[0], &QThread::finished, m_dispatcher, &QObject::deleteLater);
connect(this, &QVnc::open_connection, m_dispatcher, &Dispatcher::open);
connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate);
connect(m_dispatcher, &Dispatcher::updateFramebuffer, this, &QVnc::update);
connect(m_dispatcher, &Dispatcher::error, this, &QVnc::dispatch_error);
// QThreadPool::globalInstance()->reserveThread();
qDebug() << QThreadPool::globalInstance()->maxThreadCount();
m_dispatcher_thread.start();
int i = 1;
foreach(JpegDecoder* d, m_decoders) {
d = new JpegDecoder(m_dispatcher->queue());
d->moveToThread(m_threads[i]);
connect(m_threads[i], &QThread::finished, d, &QObject::deleteLater);
connect(d, &JpegDecoder::finished, m_uploader, &Uploader::finishedJpeg);
connect(this, &QVnc::operate, d, &JpegDecoder::operate);
i++;
}
for(int i = 0; i < m_threads.length(); i++)
m_threads.at(i)->start();
emit operate();
}
QVnc::~QVnc()
{
m_dispatcher_thread.quit();
m_dispatcher_thread.wait();
foreach(QThread* t, m_threads) {
t->quit();
t->wait();
}
}
void QVnc::open()
......@@ -57,11 +78,6 @@ void QVnc::setPort(int port)
emit portChanged(port);
}
void QVnc::setMouse(int x, int y, bool left, bool middle, bool right)
{
m_dispatcher->setMouse(x, y, left, middle, right);
}
void QVnc::dispatch_error()
{
qDebug() << "error";
......@@ -70,22 +86,17 @@ void QVnc::dispatch_error()
void QVnc::winChanged(QQuickWindow *window)
{
if(window != NULL)
connect(window, &QQuickWindow::openglContextCreated, m_dispatcher, &Dispatcher::create_context, Qt::BlockingQueuedConnection);
}
Dispatcher *QVnc::dispatcher() const
{
return m_dispatcher;
connect(window, &QQuickWindow::openglContextCreated, m_uploader, &Uploader::createContext, Qt::BlockingQueuedConnection);
}
QQuickFramebufferObject::Renderer *QVnc::createRenderer() const
{
VncRenderer *renderer = new VncRenderer(window(),
m_dispatcher->uploader().vertices(),
m_dispatcher->uploader().copy_textures(),
m_dispatcher->uploader().draw_textures());
m_uploader->vertices(),
m_uploader->textures());
connect(m_dispatcher, &Dispatcher::colorMaxChanged, renderer, &VncRenderer::setColorMax);
connect(renderer, &VncRenderer::finishedRendering, m_dispatcher, &Dispatcher::refresh);
connect(renderer, &VncRenderer::FBOTextureChanged, &(m_dispatcher->uploader()), &Uploader::changeFBOTexture);
connect(renderer, &VncRenderer::FBOTextureChanged, m_uploader, &Uploader::changeFBOTexture);
return renderer;
}
......@@ -98,3 +109,97 @@ int QVnc::port() const
{
return m_port;
}
void QVnc::mousePressEvent(QMouseEvent *event)
{
Qt::MouseButtons buttons = event->buttons();
m_lastMouseEvent = event->timestamp();
if(m_dispatcher->mouseEvent(event->x(),
event->y(),
buttons & Qt::LeftButton,
buttons & Qt::MiddleButton,
buttons & Qt::RightButton,
false,
false))
event->accept();
else
event->ignore();
}
void QVnc::mouseReleaseEvent(QMouseEvent *event)
{
Qt::MouseButtons buttons = event->buttons();
m_lastMouseEvent = event->timestamp();
if(m_dispatcher->mouseEvent(event->x(),
event->y(),
buttons & Qt::LeftButton,
buttons & Qt::MiddleButton,
buttons & Qt::RightButton,
false,
false))
event->accept();
else
event->ignore();
}
void QVnc::wheelEvent(QWheelEvent *event)
{
Qt::MouseButtons buttons = event->buttons();
QPoint rotated = event->angleDelta();
m_lastMouseEvent = event->timestamp();
if(m_dispatcher->mouseEvent(event->x(),
event->y(),
buttons & Qt::LeftButton,
buttons & Qt::MiddleButton,
buttons & Qt::RightButton,
rotated.x() > 0,
rotated.x() < 0))
event->accept();
else
event->ignore();
}
void QVnc::mouseMoveEvent(QMouseEvent *event)
{
// Filter mouse move events, we don't need 100+ of them in a second
if((event->timestamp() - m_lastMouseEvent) > 33) {
Qt::MouseButtons buttons = event->buttons();
m_lastMouseEvent = event->timestamp();
if(m_dispatcher->mouseEvent(event->x(),
event->y(),
buttons & Qt::LeftButton,
buttons & Qt::MiddleButton,
buttons & Qt::RightButton,
false,
false))
event->accept();
else
event->ignore();
}
}
void QVnc::hoverMoveEvent(QHoverEvent *event)
{
// Qt bug: timestamp is zero for QHoverEvent
// if((event->timestamp() - m_lastMouseEvent) > 33) {
// m_lastMouseEvent = event->timestamp();
QPoint position = event->pos();
if(m_dispatcher->mouseEvent(position.x(),
position.y(),
false,
false,
false,
false,
false))
event->accept();
else
event->ignore();
// }
}
void QVnc::keyPressEvent(QKeyEvent *event)
{
}
void QVnc::keyReleaseEvent(QKeyEvent *event)
{
}
#ifndef VNC_H
#define VNC_H
#define DECODER_COUNT 2
#include <QQuickWindow>
#include <QObject>
#include <QQuickFramebufferObject>
......@@ -22,35 +24,47 @@ class QVnc : public QQuickFramebufferObject
Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
public:
explicit QVnc();
explicit QVnc(QQuickItem *parent = Q_NULLPTR);
~QVnc();
Renderer *createRenderer() const;
QString host() const;
int port() const;
Dispatcher *dispatcher() const;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void wheelEvent(QWheelEvent *event);
void hoverMoveEvent(QHoverEvent *event);
private:
Dispatcher *m_dispatcher;
Uploader *m_uploader;
QVector<JpegDecoder*> m_decoders;
VncRenderer *m_renderer;
QVector<QThread*> m_threads;
QString m_host;
int m_port;
ulong m_lastMouseEvent;
signals:
void open_connection(QString host, int port);
void terminate_connection();
void hostChanged(QString host);
void portChanged(int port);
void operate();
public slots:
void open();
void terminate();
void setHost(QString host);
void setPort(int port);
void setMouse(int x, int y, bool left, bool middle, bool right);
void dispatch_error();
private:
Dispatcher *m_dispatcher;
QThread m_dispatcher_thread;
QString m_host;
int m_port;
private slots:
void winChanged(QQuickWindow *window);
};
......
......@@ -17,7 +17,15 @@
#include <QtAlgorithms>
#include <QSharedPointer>
#include <QtMath>
// #include <GLES/gl2ext.h>
class Bitmap {
public:
QByteArray data;
int x;
int y;
int width;
int height;
};
class Uploader : public QObject
{
......@@ -25,51 +33,43 @@ class Uploader : public QObject
public:
Uploader(QObject *parent = Q_NULLPTR);
~Uploader();
void create_context(QOpenGLContext *context);
void startedUpdate();
void gotCopyRect(const int src_x, const int src_y, const int width, const int height, const int dest_x, const int dest_y);
void gotFillRect(const int x, const int y, const int width, const int height, const float red, const float green, const float blue);
void gotBitmap(const QImage &image, const quint32 x, const quint32 y, const quint32 width, const quint32 height);
void finishedUpdate();
void setFramebufferHeight(int framebufferHeight);
unsigned int fill_count() const;
unsigned int copy_count() const;
unsigned int draw_count() const;
QSharedPointer<QVector<GLuint>> copy_textures();
QSharedPointer<QVector<QOpenGLTexture *>> draw_textures();
QOpenGLBuffer vertices() const;
QSharedPointer<QVector<GLuint>> textures() const;
QSharedPointer<QOpenGLBuffer> vertices() const;
// VNC events
void gotCopy(const int src_x, const int src_y, const int width, const int height, const int dest_x, const int dest_y);
void gotFill(const int x, const int y, const int width, const int height, const float red, const float green, const float blue);
int gotJpeg(const quint32 x, const quint32 y, const quint32 width, const quint32 height);
void gotBitmap(const QByteArray &bitmap, const quint32 x, const quint32 y, const quint32 width, const quint32 height, const GLenum format, const GLenum type);
void finishedUpdate();
private:
int m_framebufferHeight;
QOffscreenSurface m_surface;
QOpenGLContext m_uploader_context;
QOpenGLContext m_context;
QOpenGLFunctions *m_functions;
QSharedPointer<QOpenGLBuffer> m_vertices;
QOpenGLBuffer m_vertices;
unsigned int m_allocated;
QSharedPointer<QVector<GLuint>> m_textures;
QOpenGLShaderProgram m_copyProgram;
QOpenGLShaderProgram m_program;
GLuint m_FBOTexture;
unsigned int m_fill_count;
QVector<float> m_fill_data;
unsigned int m_copy_count;
QVector<float> m_copy_data;
QSharedPointer<QVector<GLuint>> m_copy_textures;
unsigned int m_draw_count;
QVector<float> m_draw_data;
QSharedPointer<QVector<QOpenGLTexture*>> m_draw_textures;
uchar m_decoders_running;
QVector<float> m_data;
QVector<Bitmap *> m_bitmaps;
int m_jpegs;
bool m_finished;
void swapBuffers();
signals:
void uploadFinished();
public slots:
void changeFBOTexture(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void createContext(QOpenGLContext *context);
void cleanup();
void finishedJpeg(const QImage &image, const quint32 width, const quint32 height, int index);
};
#endif // UPLOADER_H
......@@ -2,12 +2,12 @@
#include <cstring>
VncRenderer::VncRenderer(QQuickWindow *window,
QSharedPointer<QOpenGLBuffer> vertices,
QSharedPointer<QVector<GLuint>> copy_textures,
QSharedPointer<QVector<QOpenGLTexture*>> draw_textures,
QOpenGLBuffer vertices,
QSharedPointer<QVector<GLuint>> textures,
QObject *parent) :
QObject(parent), m_clear(true), m_window(window), m_vertices(vertices), m_copy_textures(copy_textures), m_draw_textures(draw_textures)
QObject(parent), m_window(window), m_vertices(vertices), m_textures(textures), m_rendered(false)
{
connect(m_window, &QQuickWindow::frameSwapped, this, &VncRenderer::frameSwapped);
m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "draw_shader.vsh");
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "draw_shader.fsh");
m_program.bind();
......@@ -20,19 +20,13 @@ VncRenderer::VncRenderer(QQuickWindow *window,
void VncRenderer::render()
{
/*if(m_frameCount == 0)
m_time.start();
else
qDebug() << (float(m_frameCount) / (float(m_time.elapsed()) / 1000.0f));
m_frameCount++;*/
if(m_clear) {
m_functions->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
m_functions->glClear(GL_COLOR_BUFFER_BIT);
m_clear = false;
}
static QTime frameTime;
qDebug() << qRound(1000.0 / frameTime.elapsed());
frameTime.restart();
m_program.bind();
m_vertices->bind();
m_vertices.bind();
m_program.setAttributeBuffer("position", GL_FLOAT, 0 * sizeof(float), 2, 7 * sizeof(float));
m_program.setAttributeBuffer("color", GL_FLOAT, 2 * sizeof(float), 3, 7 * sizeof(float));
m_program.setAttributeBuffer("texcoord", GL_FLOAT, 5 * sizeof(float), 2, 7 * sizeof(float));
......@@ -40,28 +34,18 @@ void VncRenderer::render()
m_program.enableAttributeArray("color");
m_program.enableAttributeArray("texcoord");
for(unsigned int i = 0; i < m_fill_count; i++)
for(int i = 0; i < m_textures->length(); i++) {
m_functions->glBindTexture(GL_TEXTURE_2D, m_textures->at(i));
if(m_textures->at(i) != 0) {
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
m_functions->glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
for(unsigned int i = 0; i < m_copy_count; i++) {
m_functions->glBindTexture(GL_TEXTURE_2D, m_copy_textures->at(i));
m_functions->glDrawArrays(GL_TRIANGLE_STRIP, (m_fill_count + i) * 4, 4);
}
for(unsigned int i = 0; i < m_draw_count; i++) {
m_draw_textures->at(i)->bind();
m_functions->glDrawArrays(GL_TRIANGLE_STRIP, (m_fill_count + m_copy_count + i) * 4, 4);
m_draw_textures->at(i)->release();
}
m_vertices->release();
m_program.release();
m_functions->glFlush();
m_window->resetOpenGLState();
emit finishedRendering();
m_rendered = true;
}
QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size)
......@@ -72,20 +56,33 @@ QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size
m_program.setUniformValue("ortho", ortho);
m_program.release();
QOpenGLFramebufferObject *framebufferObject = new QOpenGLFramebufferObject(size);
QOpenGLFramebufferObjectFormat format;
/* format.setTextureTarget(GL_TEXTURE_2D);
#ifdef GL_RGB8
format.setInternalTextureFormat(GL_RGB8);
#ifdef GL_RGB8_OES
format.setInternalTextureFormat(GL_RGB8_OES);
#else
format.setInternalTextureFormat(GL_RGBA);
#endif*/
QOpenGLFramebufferObject *framebufferObject = new QOpenGLFramebufferObject(size, format);
emit FBOTextureChanged(framebufferObject->texture(), ortho);
return framebufferObject;
}
void VncRenderer::synchronize(QQuickFramebufferObject *object)
void VncRenderer::setColorMax(const QVector3D &colorMax)
{
QVnc *vnc = static_cast<QVnc*>(object);
Dispatcher *dispatcher = vnc->dispatcher();
m_fill_count = dispatcher->fill_count();
m_copy_count = dispatcher->copy_count();
m_draw_count = dispatcher->draw_count();
if(m_program.bind()) {
m_program.setUniformValue("colormax", colorMax);
m_program.release();
}
}
m_program.bind();
m_program.setUniformValue("colormax", dispatcher->colorMax());
m_program.release();
void VncRenderer::frameSwapped()
{
if(m_rendered) {
m_rendered = false;
emit finishedRendering();
}
}
......@@ -9,40 +9,32 @@
#include <QMatrix4x4>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QSharedPointer>
#include <QTime>
#include "qvnc.h"
class VncRenderer : public QObject, public QQuickFramebufferObject::Renderer
{
Q_OBJECT
public:
VncRenderer(QQuickWindow *window,
QSharedPointer<QOpenGLBuffer> vertices,
QSharedPointer<QVector<GLuint>> copy_textures,
QSharedPointer<QVector<QOpenGLTexture*>> draw_textures,
QOpenGLBuffer vertices,
QSharedPointer<QVector<GLuint>> textures,
QObject *parent = 0);
protected:
void render() override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
void synchronize(QQuickFramebufferObject *) override;
private:
QSharedPointer<QOpenGLBuffer> m_vertices;
QOpenGLShaderProgram m_program;
QQuickWindow *m_window;
QOpenGLBuffer m_vertices;
QSharedPointer<QVector<GLuint>> m_textures;
QVector3D m_colorMax;
QOpenGLShaderProgram m_program;
QOpenGLFunctions *m_functions;
bool m_clear;
int m_frameCount;
QTime m_time;
unsigned int m_fill_count;
unsigned int m_copy_count;
unsigned int m_draw_count;
QSharedPointer<QVector<GLuint>> m_copy_textures;
QSharedPointer<QVector<QOpenGLTexture*>> m_draw_textures;
bool m_rendered;
public slots:
void setColorMax(const QVector3D &colorMax);
private slots:
void frameSwapped();
signals:
void FBOTextureChanged(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void finishedRendering();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment