Commit d4f375e9 by Ludmány Balázs

First somewhat working version

parent f37580d7
Pipeline #124 skipped in 0 seconds
...@@ -32,4 +32,5 @@ HEADERS += \ ...@@ -32,4 +32,5 @@ HEADERS += \
dispatcher.h dispatcher.h
DISTFILES += \ DISTFILES += \
draw_shader.fsh draw_shader.fsh \
draw_shader.vsh
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2016-07-01T15:26:59. --> <!-- Written by QtCreator 3.5.1, 2016-07-06T14:51:57. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
......
#include "dispatcher.h" #include "dispatcher.h"
Dispatcher::Dispatcher(QObject *parent) : QObject(parent)
{
}
rfbBool Dispatcher::MallocFrameBuffer(rfbClient *client) rfbBool Dispatcher::MallocFrameBuffer(rfbClient *client)
{ {
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0); Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->uploader().setFramebufferHeight(client->height);
emit dispatcher->resizeFramebuffer(QSize(client->width, client->height)); emit dispatcher->resizeFramebuffer(QSize(client->width, client->height));
return TRUE; return TRUE;
} }
...@@ -16,9 +21,9 @@ void Dispatcher::GotCopyRect(rfbClient *client, int src_x, int src_y, int w, int ...@@ -16,9 +21,9 @@ void Dispatcher::GotCopyRect(rfbClient *client, int src_x, int src_y, int w, int
void Dispatcher::GotFillRect(rfbClient *client, int x, int y, int w, int h, uint32_t colour) void Dispatcher::GotFillRect(rfbClient *client, int x, int y, int w, int h, uint32_t colour)
{ {
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0); Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
int red = (colour >> m_client->format.redShift) & m_client->format.redMax; int red = (colour >> client->format.redShift) & client->format.redMax;
int green = (colour >> m_client->format.greenShift) & m_client->format.greenMax; int green = (colour >> client->format.greenShift) & client->format.greenMax;
int blue = (colour >> m_client->format.blueShift) & m_client->format.blueMax; int blue = (colour >> client->format.blueShift) & client->format.blueMax;
dispatcher->uploader().gotFillRect(x, y, w, h, red, green, blue); dispatcher->uploader().gotFillRect(x, y, w, h, red, green, blue);
} }
...@@ -46,15 +51,15 @@ void Dispatcher::GotBitmap(rfbClient *client, const uint8_t *buffer, int x, int ...@@ -46,15 +51,15 @@ void Dispatcher::GotBitmap(rfbClient *client, const uint8_t *buffer, int x, int
rfbBool Dispatcher::GotJpeg(rfbClient *client, const uint8_t *buffer, int length, int x, int y, int w, int h) rfbBool Dispatcher::GotJpeg(rfbClient *client, const uint8_t *buffer, int length, int x, int y, int w, int h)
{ {
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0); Dispatcher *dispatcher = static_cast<Dispatcher *>(rfbClientGetClientData(client, 0));
QByteArray jpeg; QByteArray jpeg;
jpeg.setRawData(buffer, length); jpeg.setRawData((const char*) buffer, length);
JpegDecoder *decoder = new JpegDecoder(jpeg, position, size); JpegDecoder *decoder = new JpegDecoder(jpeg, x, y, w, h);
connect(decoder, &JpegDecoder::finished, dispatcher, &Dispatcher::decodingFinished);
QThreadPool::globalInstance()->start(decoder);
dispatcher->incrementDecoderCount(); dispatcher->incrementDecoderCount();
connect(decoder, &JpegDecoder::finished, dispatcher, &Dispatcher::decodingFinished, Qt::QueuedConnection);
QThreadPool::globalInstance()->start(decoder);
return TRUE; return TRUE;
} }
...@@ -63,7 +68,7 @@ void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client) ...@@ -63,7 +68,7 @@ void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client)
{ {
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0); Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->setFinished(true); dispatcher->setFinished(true);
if(decoderCount() == 0) { if(dispatcher->decoderCount() == 0) {
dispatcher->uploader().finishedUpdate(); dispatcher->uploader().finishedUpdate();
emit dispatcher->updateFramebuffer(); emit dispatcher->updateFramebuffer();
} }
...@@ -89,7 +94,7 @@ int Dispatcher::bitsPerPixel() ...@@ -89,7 +94,7 @@ int Dispatcher::bitsPerPixel()
return m_client->format.bitsPerPixel; return m_client->format.bitsPerPixel;
} }
Uploader &Dispatcher::uploader() const Uploader &Dispatcher::uploader()
{ {
return m_uploader; return m_uploader;
} }
...@@ -104,12 +109,43 @@ bool Dispatcher::finished() const ...@@ -104,12 +109,43 @@ bool Dispatcher::finished() const
return m_finished; 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
return 0;
}
void Dispatcher::create_context(QOpenGLContext *context)
{
m_uploader.create_context(context);
}
void Dispatcher::open(QString host, int port) void Dispatcher::open(QString host, int port)
{ {
QByteArray tmp = host.toLocal8Bit();
m_client = rfbGetClient(8, 3, 4); m_client = rfbGetClient(8, 3, 4);
m_client->canHandleNewFBSize = FALSE; m_client->canHandleNewFBSize = FALSE;
m_client->serverHost = host.toLocal8Bit().data(); m_client->serverHost = new char[tmp.size() + 1];
strcpy(m_client->serverHost, tmp.constData());
m_client->serverPort = port; m_client->serverPort = port;
m_client->MallocFrameBuffer = Dispatcher::MallocFrameBuffer; m_client->MallocFrameBuffer = Dispatcher::MallocFrameBuffer;
m_client->GotCopyRect = Dispatcher::GotCopyRect; m_client->GotCopyRect = Dispatcher::GotCopyRect;
...@@ -118,21 +154,32 @@ void Dispatcher::open(QString host, int port) ...@@ -118,21 +154,32 @@ void Dispatcher::open(QString host, int port)
m_client->GotJpeg = Dispatcher::GotJpeg; m_client->GotJpeg = Dispatcher::GotJpeg;
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate; m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
rfbInitClient(m_client, NULL, NULL);
rfbClientSetClientData(m_client, 0, this); rfbClientSetClientData(m_client, 0, this);
if(!rfbInitClient(m_client, NULL, NULL)) {
emit error();
return;
}
refresh();
} }
void Dispatcher::refresh() void Dispatcher::refresh()
{ {
if(m_client == NULL) if(m_client == NULL)
return; return;
m_finished = false; setFinished(false);
int message = WaitForMessage(m_client, 500); m_uploader.startedUpdate();
int message = WaitForMessage(m_client, 10000);
if(message < 0) { if(message < 0) {
terminate();
emit error(); emit error();
return; return;
} else if (message) { }
if (message) {
if(!HandleRFBServerMessage(m_client)) { if(!HandleRFBServerMessage(m_client)) {
terminate();
emit error(); emit error();
return; return;
} }
...@@ -147,9 +194,9 @@ void Dispatcher::terminate() ...@@ -147,9 +194,9 @@ void Dispatcher::terminate()
rfbClientCleanup(m_client); rfbClientCleanup(m_client);
} }
void Dispatcher::decodingFinished(const QImage &bitmap, const QPoint &position, const QSize &size) void Dispatcher::decodingFinished(const QImage &bitmap, const int x, const int y, const int w, const int h)
{ {
m_uploader.gotBitmap(bitmap, position, size); m_uploader.gotBitmap(bitmap, x, y, w, h);
if(m_finished && decrementDecoderCount() == 0) { if(m_finished && decrementDecoderCount() == 0) {
m_uploader.finishedUpdate(); m_uploader.finishedUpdate();
emit updateFramebuffer(); emit updateFramebuffer();
......
#ifndef RFBDISPATCH_H #ifndef RFBDISPATCH_H
#define RFBDISPATCH_H #define RFBDISPATCH_H
#include <QOpenGLContext>
#include <QCoreApplication> #include <QCoreApplication>
#include <QImage>
#include <QThreadPool> #include <QThreadPool>
#include <QObject> #include <QObject>
#include <QPoint> #include <QPoint>
...@@ -17,6 +19,8 @@ class Dispatcher : public QObject ...@@ -17,6 +19,8 @@ class Dispatcher : public QObject
Q_OBJECT Q_OBJECT
public: public:
Dispatcher(QObject *parent = 0);
// libvnc hooks // libvnc hooks
static rfbBool MallocFrameBuffer(rfbClient* client); static rfbBool MallocFrameBuffer(rfbClient* client);
static void GotCopyRect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y); static void GotCopyRect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y);
...@@ -30,8 +34,13 @@ public: ...@@ -30,8 +34,13 @@ public:
unsigned int incrementDecoderCount(); unsigned int incrementDecoderCount();
unsigned int decrementDecoderCount(); unsigned int decrementDecoderCount();
int bitsPerPixel(); int bitsPerPixel();
Uploader &uploader() const; Uploader &uploader();
void setFinished(bool finished); void setFinished(bool finished);
bool finished() const;
unsigned int fill_count();
unsigned int copy_count();
unsigned int draw_count();
private: private:
rfbClient *m_client; rfbClient *m_client;
...@@ -43,10 +52,11 @@ signals: ...@@ -43,10 +52,11 @@ signals:
void updateFramebuffer(); void updateFramebuffer();
void error(); void error();
public slots: public slots:
void create_context(QOpenGLContext *context);
void open(QString host, int port); void open(QString host, int port);
void refresh(); void refresh();
void terminate(); void terminate();
void decodingFinished(const QImage &bitmap, const QPoint &position, const QSize &size); void decodingFinished(const QImage &bitmap, const int x, const int y, const int w, const int h);
}; };
#endif // RFBDISPATCH_H #endif // RFBDISPATCH_H
uniform sampler2D qt_Texture0; uniform sampler2D texture;
varying highp vec4 qt_TexCoord0; varying highp vec2 vartexcoord;
void main(void) void main(void)
{ {
gl_FragColor = texture2D(qt_Texture0, qt_TexCoord0.st); gl_FragColor = texture2D(texture, vartexcoord);
} }
uniform highp mat4 ortho;
attribute highp vec2 position;
attribute highp vec2 texcoord;
varying highp vec2 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
vartexcoord = texcoord;
}
#include "jpegdecoder.h" #include "jpegdecoder.h"
JpegDecoder::JpegDecoder(const QByteArray &jpeg, const QPoint &position, const QSize &size) : JpegDecoder::JpegDecoder(const QByteArray &jpeg, const int x, const int y, const int w, const int h, QObject *parent) :
m_jpeg(jpeg), m_position(position), m_size(size) QObject(parent), QRunnable(), m_jpeg(jpeg), m_x(x), m_y(y), m_w(w), m_h(h)
{ {
} }
void JpegDecoder::run() void JpegDecoder::run()
{ {
m_image.loadFromData(m_jpeg, "JPG"); m_image.loadFromData(m_jpeg, "JPG");
emit finished(m_image, m_position, m_size); emit finished(m_image, m_x, m_y, m_w, m_h);
} }
...@@ -7,23 +7,26 @@ ...@@ -7,23 +7,26 @@
#include <QPoint> #include <QPoint>
#include <QSize> #include <QSize>
#include <QImage> #include <QImage>
#include <QDebug>
/*! /*!
* \brief Loads JPEG files on a separate thread * \brief Loads JPEG files on a separate thread
*/ */
class JpegDecoder : public QRunnable class JpegDecoder : public QObject, public QRunnable
{ {
Q_OBJECT Q_OBJECT
public: public:
JpegDecoder(const QByteArray &jpeg, const QPoint &position, const QSize &size); JpegDecoder(const QByteArray &jpeg, const int x, const int y, const int w, const int h, QObject *parent = 0);
void run(); void run();
signals: signals:
void finished(const QImage &image, const QPoint &position, QSize &size); void finished(const QImage &image, const int x, const int y, const int w, const int h);
private: private:
QByteArray m_jpeg; QByteArray m_jpeg;
QImage m_image; QImage m_image;
QPoint m_position; int m_x;
QSize m_size; int m_y;
int m_w;
int m_h;
}; };
#endif // JPEGDECODER_H #endif // JPEGDECODER_H
...@@ -6,9 +6,6 @@ ...@@ -6,9 +6,6 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES);
QGuiApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
qmlRegisterType<QVnc>("thinclient", 1, 1, "QVnc"); qmlRegisterType<QVnc>("thinclient", 1, 1, "QVnc");
......
...@@ -4,8 +4,8 @@ import thinclient 1.1 ...@@ -4,8 +4,8 @@ import thinclient 1.1
ApplicationWindow { ApplicationWindow {
visible: true visible: true
width: 640 width: 1280
height: 480 height: 1024
header: TabBar { header: TabBar {
width: parent.width width: parent.width
...@@ -26,7 +26,7 @@ ApplicationWindow { ...@@ -26,7 +26,7 @@ ApplicationWindow {
id: vnc id: vnc
host: "vm.ik.bme.hu" host: "vm.ik.bme.hu"
port: 10495 port: 10495
width: 1024 width: 1280
height: 768 height: 1024
} }
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
QVnc::QVnc() QVnc::QVnc()
{ {
connect(this, &QVnc::windowChanged, this, &QVnc::winChanged);
// Don't let Qt change the size of the OpenGL framebuffer // Don't let Qt change the size of the OpenGL framebuffer
setTextureFollowsItemSize(false); setTextureFollowsItemSize(false);
...@@ -14,6 +16,7 @@ QVnc::QVnc() ...@@ -14,6 +16,7 @@ QVnc::QVnc()
connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate); connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate);
connect(m_dispatcher, &Dispatcher::updateFramebuffer, this, &QVnc::update); connect(m_dispatcher, &Dispatcher::updateFramebuffer, this, &QVnc::update);
connect(m_dispatcher, &Dispatcher::error, this, &QVnc::dispatch_error);
QThreadPool::globalInstance()->reserveThread(); QThreadPool::globalInstance()->reserveThread();
m_dispatcher_thread.start(); m_dispatcher_thread.start();
...@@ -53,11 +56,31 @@ void QVnc::setPort(int port) ...@@ -53,11 +56,31 @@ void QVnc::setPort(int port)
emit portChanged(port); emit portChanged(port);
} }
void QVnc::dispatch_error()
{
qDebug() << "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;
}
QQuickFramebufferObject::Renderer *QVnc::createRenderer() const QQuickFramebufferObject::Renderer *QVnc::createRenderer() const
{ {
VncRenderer *renderer = new VncRenderer(); VncRenderer *renderer = new VncRenderer(window(),
connect(renderer, &VncRenderer::rendered, m_dispatcher, &Dispatcher::refresh); m_dispatcher->uploader().fill_buffer(),
connect(m_dispatcher &Dispatcher::resizeFramebuffer, renderer, &VncRenderer::invalidateFramebufferObject); m_dispatcher->uploader().copy_source(),
m_dispatcher->uploader().copy_buffer(),
m_dispatcher->uploader().draw_buffer(),
m_dispatcher->uploader().draw_textures());
connect(renderer, &VncRenderer::finishedRendering, m_dispatcher, &Dispatcher::refresh);
return renderer; return renderer;
} }
......
#ifndef VNC_H #ifndef VNC_H
#define VNC_H #define VNC_H
#include <QQuickWindow>
#include <QObject> #include <QObject>
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
#include <QThread> #include <QThread>
...@@ -26,6 +27,8 @@ public: ...@@ -26,6 +27,8 @@ public:
Renderer *createRenderer() const; Renderer *createRenderer() const;
QString host() const; QString host() const;
int port() const; int port() const;
Dispatcher *dispatcher() const;
signals: signals:
void open_connection(QString host, int port); void open_connection(QString host, int port);
void terminate_connection(); void terminate_connection();
...@@ -34,17 +37,20 @@ signals: ...@@ -34,17 +37,20 @@ signals:
void portChanged(int port); void portChanged(int port);
public slots: public slots:
void open(); void open();
void update();
void terminate(); void terminate();
void setHost(QString host); void setHost(QString host);
void setPort(int port); void setPort(int port);
void dispatch_error();
private: private:
Dispatcher *m_dispatcher; Dispatcher *m_dispatcher;
QThread m_dispatcher_thread; QThread m_dispatcher_thread;
QString m_host; QString m_host;
int m_port; int m_port;
private slots:
void winChanged(QQuickWindow *window);
}; };
#endif // VNC_H #endif // VNC_H
#include "uploader.h" #include "uploader.h"
Uploader::Uploader() : m_fill_buffer(QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)) Uploader::Uploader()
{ {
// "applications must ensure that create() is only called on the main (GUI) thread" // "applications must ensure that create() is only called on the main (GUI) thread"
m_surface.create(); m_surface.create();
m_uploader_context.setShareContext(QOpenGLContext::globalShareContext());
m_uploader_context.create();
m_uploader_context.makeCurrent(m_surface);
m_fill_buffer.create(); m_copy_source = QSharedPointer<QVector<copy>>(new QVector<copy>);
m_draw_buffer.create(); m_draw_textures = QSharedPointer<QVector<QOpenGLTexture*>>(new QVector<QOpenGLTexture*>);
// A single rectangle takes 20 float values to describe (4 vertices * (2 coordinate + 3 color)) // A single rectangle takes 20 float values to describe (4 vertices * (2 coordinate + 3 color))
m_fill_data.reserve(100); m_fill_data.reserve(100);
m_draw_data.reserve(100); m_draw_data.reserve(100);
m_copy_data.reserve(5);
m_copy_source->reserve(5);
m_draw_textures->reserve(5);
m_draw_buffer = QSharedPointer<QOpenGLBuffer>(new QOpenGLBuffer);
m_draw_buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
}
void Uploader::create_context(QOpenGLContext *context)
{
m_uploader_context = new QOpenGLContext();
m_uploader_context->setShareContext(context);
m_uploader_context->create();
m_uploader_context->makeCurrent(&m_surface);
} }
void Uploader::startedUpdate() void Uploader::startedUpdate()
{ {
// TODO: bind the framebuffer as texture // Clean up the data from the previous round
for(unsigned int i = 0; i < m_copy_count; i++) {
m_copy_source->at(i).texture->destroy();
delete m_copy_source->at(i).texture;
}
m_copy_data.clear();
m_copy_count = 0;
m_fill_data.clear();
m_fill_count = 0;
for(unsigned int i = 0; i < m_draw_count; i++) {
m_draw_textures->at(i)->destroy();
delete m_draw_textures->at(i);
}
m_draw_data.clear();
m_draw_count = 0;
} }
void Uploader::gotCopyRect(const int &src_x, const int &src_y, const int &w, const int &h, const int &dest_x, const int &dest_y) void Uploader::gotCopyRect(const int src_x, const int src_y, const int width, const int height, const int dest_x, const int dest_y)
{ {
// TODO: render parts of the framebuffer to temporary texture QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::Float32);
// "Specify the window coordinates of the lower left corner
// of the rectangular region of pixels to be copied."
m_copy_source->append({src_x,
m_framebufferHeight - src_y,
width,
height,
texture});
// bottom left
m_copy_data.append((float) dest_x);
m_copy_data.append((float) (dest_y + height));
m_copy_data.append(0.0f);
m_copy_data.append(0.0f);
// top left
m_copy_data.append((float) dest_x);
m_copy_data.append((float) dest_y);
m_copy_data.append(0.0f);
m_copy_data.append(1.0f);
// bottom right
m_copy_data.append((float) (dest_x + width));
m_copy_data.append((float) (dest_y + height));
m_copy_data.append(1.0f);
m_copy_data.append(0.0f);
// top right
m_copy_data.append((float) (dest_x + width));
m_copy_data.append((float) dest_y);
m_copy_data.append(1.0f);
m_copy_data.append(1.0f);
m_copy_count++;
} }
void Uploader::gotFillRect(const int x, const int y, const int width, const int height, const float red, const float green, const float blue) void Uploader::gotFillRect(const int x, const int y, const int width, const int height, const float red, const float green, const float blue)
...@@ -59,11 +118,13 @@ void Uploader::gotFillRect(const int x, const int y, const int width, const int ...@@ -59,11 +118,13 @@ void Uploader::gotFillRect(const int x, const int y, const int width, const int
m_fill_data.append(red); m_fill_data.append(red);
m_fill_data.append(green); m_fill_data.append(green);
m_fill_data.append(blue); m_fill_data.append(blue);
m_fill_count++;
} }
void Uploader::gotBitmap(const QImage &image, const int x, const int y, const int width, const int height) void Uploader::gotBitmap(const QImage &image, const int x, const int y, const int width, const int height)
{ {
m_draw_textures.append(new QOpenGLTexture(image, QOpenGLTexture::DontGenerateMipMaps)); m_draw_textures->append(new QOpenGLTexture(image, QOpenGLTexture::DontGenerateMipMaps));
// bottom left // bottom left
m_draw_data.append((float) x); m_draw_data.append((float) x);
...@@ -85,35 +146,77 @@ void Uploader::gotBitmap(const QImage &image, const int x, const int y, const in ...@@ -85,35 +146,77 @@ void Uploader::gotBitmap(const QImage &image, const int x, const int y, const in
m_draw_data.append((float) y); m_draw_data.append((float) y);
m_draw_data.append(1.0f); m_draw_data.append(1.0f);
m_draw_data.append(1.0f); m_draw_data.append(1.0f);
m_draw_count++;
} }
void Uploader::finishedUpdate() void Uploader::finishedUpdate()
{ {
QOpenGLFunctions *fun = QOpenGLContext::currentContext()->functions(); if(m_copy_count > 0) {
m_copy_buffer->bind();
m_copy_buffer->allocate(m_copy_data.constData(), m_copy_data.size() * sizeof(float));
m_copy_buffer->release();
}
// Upload fill if(m_fill_count > 0) {
int fill_size = m_fill_data.size() * sizeof(float); m_fill_buffer->bind();
m_fill_buffer.bind(); m_fill_buffer->allocate(m_fill_data.constData(), m_fill_data.size() * sizeof(float));
m_fill_buffer.allocate(fill_size); m_fill_buffer->release();
m_fill_buffer.write(0, m_fill_data.constData(), fill_size); }
m_fill_buffer.release();
m_fill_data.clear();
// Upload draw if(m_draw_count > 0) {
int draw_size = m_draw_data.size() * sizeof(float); m_draw_buffer->bind();
m_draw_buffer.bind(); m_draw_buffer->allocate(m_draw_data.data(), m_draw_data.size() * sizeof(float));
m_draw_buffer.allocate(draw_size); m_draw_buffer->release();
m_fill_buffer.write(0, m_fill_data.constData(), fill_size); }
m_fill_buffer.release();
m_fill_data.clear();
} }
void Uploader::setFramebufferHeight(int framebufferHeight)
{
m_framebufferHeight = framebufferHeight;
}
QOpenGLBuffer Uploader::draw_buffer() const unsigned int Uploader::fill_count() const
{ {
return m_draw_buffer; return m_fill_count;
}
unsigned int Uploader::copy_count() const
{
return m_copy_count;
}
unsigned int Uploader::draw_count() const
{
return m_draw_count;
}
QSharedPointer<QVector<copy>> Uploader::copy_source()
{
return m_copy_source;
}
QSharedPointer<QOpenGLBuffer> Uploader::copy_buffer()
{
return m_copy_buffer;
} }
QOpenGLBuffer Uploader::fill_buffer() const
QSharedPointer<QOpenGLBuffer> Uploader::fill_buffer()
{ {
return m_fill_buffer; return m_fill_buffer;
} }
QSharedPointer<QOpenGLBuffer> Uploader::draw_buffer()
{
return m_draw_buffer;
}
QSharedPointer<QVector<QOpenGLTexture *>> Uploader::draw_textures()
{
return m_draw_textures;
}
QOpenGLContext *Uploader::uploader_context() const
{
return m_uploader_context;
}
#ifndef UPLOADER_H #ifndef UPLOADER_H
#define UPLOADER_H #define UPLOADER_H
#include <QQuickWindow>
#include <QDebug>
#include <QVector> #include <QVector>
#include <QOffscreenSurface> #include <QOffscreenSurface>
#include <QOpenGLContext> #include <QOpenGLContext>
...@@ -9,29 +11,59 @@ ...@@ -9,29 +11,59 @@
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QThreadPool> #include <QThreadPool>
#include <QtAlgorithms> #include <QtAlgorithms>
#include <QSharedPointer>
class Uploader : public QObject typedef struct {
int src_x;
int src_y;
int width;
int height;
QOpenGLTexture *texture;
} copy;
class Uploader
{ {
public: public:
Uploader(); Uploader();
QOpenGLBuffer fill_buffer() const; void create_context(QOpenGLContext *context);
QOpenGLBuffer draw_buffer() const;
void startedUpdate(); 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 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 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 int x, const int y, const int width, const int height); void gotBitmap(const QImage &image, const int x, const int y, const int width, const int height);
void finishedUpdate(); void finishedUpdate();
void setFramebufferHeight(int framebufferHeight);
unsigned int fill_count() const;
unsigned int copy_count() const;
unsigned int draw_count() const;
QSharedPointer<QVector<copy>> copy_source();
QSharedPointer<QOpenGLBuffer> copy_buffer();
QSharedPointer<QOpenGLBuffer> fill_buffer();
QSharedPointer<QOpenGLBuffer> draw_buffer();
QSharedPointer<QVector<QOpenGLTexture *>> draw_textures();
QOpenGLContext *uploader_context() const;
private: private:
int m_framebufferHeight;
QOffscreenSurface m_surface; QOffscreenSurface m_surface;
QOpenGLContext m_uploader_context; QOpenGLContext *m_uploader_context;
unsigned int m_copy_count;
QVector<float> m_copy_data;
QSharedPointer<QVector<copy>> m_copy_source;
QSharedPointer<QOpenGLBuffer> m_copy_buffer;
unsigned int m_fill_count;
QVector<float> m_fill_data; QVector<float> m_fill_data;
QOpenGLBuffer m_fill_buffer; QSharedPointer<QOpenGLBuffer> m_fill_buffer;
unsigned int m_draw_count;
QVector<float> m_draw_data; QVector<float> m_draw_data;
QOpenGLBuffer m_draw_buffer; QSharedPointer<QOpenGLBuffer> m_draw_buffer;
QSharedPointer<QVector<QOpenGLTexture*>> m_draw_textures;
QVector<*QOpenGLTexture> m_draw_textures;
uchar m_decoders_running; uchar m_decoders_running;
}; };
......
#include "vncrenderer.h" #include "vncrenderer.h"
VncRenderer::VncRenderer(QOpenGLBuffer fill_buffer, QOpenGLBuffer draw_buffer, QOpenGLTexture draw_texture) : VncRenderer::VncRenderer(QQuickWindow *window,
m_fill_buffer(fill_buffer), m_draw_buffer(draw_buffer), m_draw_texture(draw_texture) QSharedPointer<QOpenGLBuffer> fill_buffer,
QSharedPointer<QVector<copy>> copy_source,
QSharedPointer<QOpenGLBuffer> copy_buffer,
QSharedPointer<QOpenGLBuffer> draw_buffer,
QSharedPointer<QVector<QOpenGLTexture*>> draw_textures,
QObject *parent) :
QObject(parent), m_window(window), m_fill_buffer(fill_buffer), m_copy_source(copy_source),
m_copy_buffer(copy_buffer), m_draw_buffer(draw_buffer), m_draw_textures(draw_textures), m_clear(true)
{ {
QOpenGLShader fill_vshader(QOpenGLShader::Vertex, &m_fill_program); m_draw_buffer->create();
/*QOpenGLShader fill_vshader(QOpenGLShader::Vertex, &m_fill_program);
fill_vshader.compileSourceCode("uniform highp mat4 ortho;\n" fill_vshader.compileSourceCode("uniform highp mat4 ortho;\n"
"attribute highp vec2 position;\n" "attribute highp vec2 position;\n"
"attribute lowp vec3 color;\n" "attribute lowp vec3 color;\n"
...@@ -25,76 +33,95 @@ VncRenderer::VncRenderer(QOpenGLBuffer fill_buffer, QOpenGLBuffer draw_buffer, Q ...@@ -25,76 +33,95 @@ VncRenderer::VncRenderer(QOpenGLBuffer fill_buffer, QOpenGLBuffer draw_buffer, Q
m_fill_program.addShader(&fill_fshader); m_fill_program.addShader(&fill_fshader);
m_fill_program.link(); m_fill_program.link();
m_fill_program.enableAttributeArray("position"); m_fill_program.enableAttributeArray("position");
m_fill_program.enableAttributeArray("color"); m_fill_program.enableAttributeArray("color");*/
QOpenGLShader draw_vshader(QOpenGLShader::Vertex, &m_fill_program); m_draw_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "draw_shader.vsh");
draw_vshader.compileSourceCode("uniform highp mat2 ortho;\n" m_draw_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "draw_shader.fsh");
"uniform highp mat4 atlasortho;\n" m_draw_program.bind();
"attribute highp vec2 position;\n" m_draw_program.setUniformValue("texture", GL_TEXTURE_2D);
"attribute lowp vec2 texture;\n"
"varying lowp vec2 vartexture;\n"
"void main(void)\n"
"{\n"
" vartexture = atlasortho * texture;\n"
" gl_Position = ortho * vec4(position, 0.0, 1.0);\n"
"}\n");
QOpenGLShader draw_fshader(QOpenGLShader::Fragment, &m_fill_program);
draw_fshader.compileSourceCode("uniform sampler2D atlas;\n"
"varying lowp vec2 vartexture;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(atlas, vartexture);\n"
"}\n");
m_draw_program.addShader(&draw_vshader);
m_draw_program.addShader(&draw_fshader);
m_draw_program.link();
m_draw_program.enableAttributeArray("position"); m_draw_program.enableAttributeArray("position");
m_draw_program.enableAttributeArray("texture"); m_draw_program.enableAttributeArray("texcoord");
m_draw_program.release();
} }
void VncRenderer::render() void VncRenderer::render()
{ {
QOpenGLFunctions *fun = QOpenGLContext::currentContext()->functions(); QOpenGLFunctions *fun = m_window->openglContext()->functions();
// fill rectangles with solid color if(m_clear) {
m_fill_program.bind(); fun->glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
m_fill_buffer.bind(); fun->glClear(GL_COLOR_BUFFER_BIT);
for(unsigned int i = 0; i < m_fill_count; i++) m_clear = false;
fun->glDrawArrays(GL_TRIANGLES, 0, 4); }
m_fill_buffer.release();
m_fill_program.release(); /*if(m_fill_count > 0) {
m_fill_program.bind();
m_draw_program.bind(); m_fill_buffer.bind();
m_draw_buffer.bind(); m_fill_program.setAttributeBuffer("position", GL_FLOAT, 0, 2, 3 * sizeof(float));
m_draw_texture.bind(); m_fill_program.setAttributeBuffer("color", GL_FLOAT, 2, 3, 2 * sizeof(float));
for(unsigned int i = 0; i < m_fill_count; i++)
foreach(const Uploader::CopyToAtlas &copy, m_copy_data) fun->glDrawArrays(GL_TRIANGLES, i * 4, 4);
fun->glTexImage2D(GL_TEXTURE_2D, m_fill_buffer.release();
0, m_fill_program.release();
GL_RGBA32,); }
*/
// draw the vertices of the texture atlas if(m_copy_count > 0 || m_draw_count > 0)
for(int i = 0; i < m_draw_count; i++) m_draw_program.bind();
fun->glDrawArrays(GL_TRIANGLES, 0, 4); m_draw_program.enableAttributeArray("position");
m_draw_program.enableAttributeArray("texcoord");
m_draw_texture.release(); /*
m_draw_buffer.release(); if(m_copy_count > 0){
m_draw_program.release(); m_copy_buffer.bind();
m_draw_program.setAttributeBuffer("position", GL_FLOAT, 0 * sizeof(float), 2, 4 * sizeof(float));
QQuickWindow::resetOpenGLState(); m_draw_program.setAttributeBuffer("texcoord", GL_FLOAT, 2 * sizeof(float), 2, 4 * sizeof(float));
emit rendered();
for(unsigned int i = 0; i < m_copy_count; i++) {
m_copy_source->at(i).texture->bind();
fun->glCopyTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
m_copy_source->at(i).src_x,
m_copy_source->at(i).src_y,
m_copy_source->at(i).width,
m_copy_source->at(i).height,
0);
fun->glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
m_copy_source->at(i).texture->release();
}
m_copy_buffer.release();
}*/
if(m_draw_count > 0) {
m_draw_buffer->bind();
m_draw_program.setAttributeBuffer("position", GL_FLOAT, 0 * sizeof(float), 2, 4 * sizeof(float));
m_draw_program.setAttributeBuffer("texcoord", GL_FLOAT, 2 * sizeof(float), 2, 4 * sizeof(float));
for(unsigned int i = 0; i < m_draw_count; i++) {
m_draw_textures->at(i)->bind();
fun->glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
m_draw_textures->at(i)->release();
}
m_draw_buffer->release();
}
if(m_copy_count > 0 || m_draw_count > 0)
m_draw_program.release();
m_window->resetOpenGLState();
emit finishedRendering();
} }
QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size) QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size)
{ {
// Set the orthogonal transformation matrix
m_fill_program.bind();
QMatrix4x4 ortho; QMatrix4x4 ortho;
ortho.ortho(QRect(QPoint(0, 0), size)); ortho.ortho(QRect(QPoint(0, size.height()), QSize(size.width(), -1 * size.height())));
m_fill_program.setUniformValue("ortho", mat); //m_fill_program.bind();
m_fill_program.release(); //m_fill_program.setUniformValue("ortho", ortho);
m_draw_program.bind();
m_draw_program.setUniformValue("ortho", ortho);
m_draw_program.release();
return new QOpenGLFramebufferObject(size); return new QOpenGLFramebufferObject(size);
} }
...@@ -102,4 +129,8 @@ QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size ...@@ -102,4 +129,8 @@ QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size
void VncRenderer::synchronize(QQuickFramebufferObject *object) void VncRenderer::synchronize(QQuickFramebufferObject *object)
{ {
QVnc *vnc = static_cast<QVnc*>(object); 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();
} }
#ifndef VNCRENDERER_H #ifndef VNCRENDERER_H
#define VNCRENDERER_H #define VNCRENDERER_H
#include <QObject>
#include <QQuickWindow> #include <QQuickWindow>
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
...@@ -11,35 +10,46 @@ ...@@ -11,35 +10,46 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QSharedPointer>
#include "qvnc.h" #include "qvnc.h"
#include "uploader.h"
class VncRenderer : public QQuickFramebufferObject::Renderer class VncRenderer : public QObject, public QQuickFramebufferObject::Renderer
{ {
Q_OBJECT Q_OBJECT
public: public:
VncRenderer(QOpenGLBuffer fill_buffer, QOpenGLBuffer draw_buffer, QOpenGLTexture draw_texture); VncRenderer(QQuickWindow* window,
QSharedPointer<QOpenGLBuffer> fill_buffer,
QSharedPointer<QVector<copy>> copy_source,
QSharedPointer<QOpenGLBuffer> copy_buffer,
QSharedPointer<QOpenGLBuffer> draw_buffer,
QSharedPointer<QVector<QOpenGLTexture*>> draw_textures,
QObject *parent = 0);
protected: protected:
void render() override; void render() override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override; QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
void synchronize(QQuickFramebufferObject *) override; void synchronize(QQuickFramebufferObject *) override;
private: private:
// for filling a rectangle with a solid color QQuickWindow *m_window;
QOpenGLShaderProgram m_fill_program;
QOpenGLBuffer m_fill_buffer;
unsigned int m_fill_count; unsigned int m_fill_count;
// for copying portions of the framebuffer QOpenGLShaderProgram m_fill_program;
QVector<Uploader::CopyToAtlas> m_copy_data; QSharedPointer<QOpenGLBuffer> m_fill_buffer;
// for drawing from a texture atlas
QOpenGLShaderProgram m_draw_program; unsigned int m_copy_count;
QOpenGLBuffer m_draw_buffer; QSharedPointer<QVector<copy>> m_copy_source;
QVector<*QOpenGLTexture> m_draw_texture; QSharedPointer<QOpenGLBuffer> m_copy_buffer;
unsigned int m_draw_count; unsigned int m_draw_count;
QOpenGLShaderProgram m_draw_program;
QSharedPointer<QOpenGLBuffer> m_draw_buffer;
QSharedPointer<QVector<QOpenGLTexture*>> m_draw_textures;
QMatrix4x4 m_ortho; QMatrix4x4 m_ortho;
bool m_clear;
signals: signals:
void rendered(); void finishedRendering();
}; };
#endif // VNCRENDERER_H #endif // VNCRENDERER_H
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