Commit cb68f729 by Ludmány Balázs

Move copy to the rendering thread

parent 0b287fd5
...@@ -36,4 +36,8 @@ DISTFILES += \ ...@@ -36,4 +36,8 @@ DISTFILES += \
draw_shader.fsh \ draw_shader.fsh \
draw_shader.vsh \ draw_shader.vsh \
copy_shader.vsh \ copy_shader.vsh \
copy_shader.fsh copy_shader.fsh \
fill_shader.vsh \
fill_shader.fsh \
bitmap_shader.vsh \
bitmap_shader.fsh
<?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-29T11:10:46. --> <!-- Written by QtCreator 3.5.1, 2016-08-01T17:47:15. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">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="QString" key="ProjectExplorer.ProjectConfiguration.Id">{9fe100e5-65f5-4993-908d-e24f092a1cff}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value> <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
......
uniform sampler2D texture;
varying highp vec4 vartexcoord;
void main(void)
{
gl_FragColor = texture2D(texture, vartexcoord.st);
//gl_FragColor = vec4(vartexcoord.st, 0.0, 1.0);
}
uniform highp mat4 ortho;
uniform highp mat4 texortho;
attribute highp vec2 position;
attribute highp vec2 texcoord;
varying highp vec4 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
vartexcoord = texortho * vec4(texcoord, 0.0, 1.0);
}
...@@ -49,6 +49,13 @@ void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client) ...@@ -49,6 +49,13 @@ void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client)
dispatcher->uploader()->finishedUpdate(); dispatcher->uploader()->finishedUpdate();
} }
char *Dispatcher::GetPassword(rfbClient *client)
{
char* password = new char[9];
strcpy(password, "asdfasdf");
return password;
}
bool Dispatcher::mouseEvent(const int x, const int y, const bool left, const bool middle, const bool right, const bool up, const bool down) 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) if(m_client == NULL)
...@@ -96,12 +103,13 @@ void Dispatcher::open(const QString host, const int port, const int width, const ...@@ -96,12 +103,13 @@ void Dispatcher::open(const QString host, const int port, const int width, const
m_client->GotBitmap = Dispatcher::GotBitmap; m_client->GotBitmap = Dispatcher::GotBitmap;
m_client->GotJpeg = Dispatcher::GotJpeg; m_client->GotJpeg = Dispatcher::GotJpeg;
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate; m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
m_client->appData.useRemoteCursor = TRUE; m_client->GetPassword = Dispatcher::GetPassword;
// Set the format requested by the user // Set the format requested by the user
m_client->appData.useRemoteCursor = TRUE;
m_client->width = width; m_client->width = width;
m_client->height = height; m_client->height = height;
m_client->appData.compressLevel = 0; m_client->appData.compressLevel = 9;
m_client->appData.qualityLevel = 0; m_client->appData.qualityLevel = 0;
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
m_client->format.bigEndian = TRUE; m_client->format.bigEndian = TRUE;
...@@ -137,6 +145,7 @@ void Dispatcher::open(const QString host, const int port, const int width, const ...@@ -137,6 +145,7 @@ void Dispatcher::open(const QString host, const int port, const int width, const
// 16 bit: RGB444, RGB555, RGB565 // 16 bit: RGB444, RGB555, RGB565
refresh(); refresh();
decode();
} }
void Dispatcher::refresh() void Dispatcher::refresh()
{ {
...@@ -154,6 +163,13 @@ void Dispatcher::refresh() ...@@ -154,6 +163,13 @@ void Dispatcher::refresh()
return; return;
} }
} }
}
void Dispatcher::decode()
{
if(m_client == NULL)
return;
m_uploader->startDecoding();
if(!HandleRFBServerMessage(m_client)) { if(!HandleRFBServerMessage(m_client)) {
terminate(); terminate();
......
...@@ -33,6 +33,7 @@ public: ...@@ -33,6 +33,7 @@ public:
static void GotBitmap(rfbClient* client, const uint8_t* buffer, int x, int y, int w, int h); static void GotBitmap(rfbClient* client, const uint8_t* buffer, int x, int y, int w, int h);
static rfbBool GotJpeg(rfbClient* client, const uint8_t* buffer, int length, int x, int y, int w, int h); static rfbBool GotJpeg(rfbClient* client, const uint8_t* buffer, int length, int x, int y, int w, int h);
static void FinishedFrameBufferUpdate(rfbClient* client); static void FinishedFrameBufferUpdate(rfbClient* client);
static char *GetPassword(rfbClient* client);
// input events // 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); bool mouseEvent(const int x, const int y, const bool left, const bool middle, const bool right, const bool up, const bool down);
...@@ -59,6 +60,7 @@ public slots: ...@@ -59,6 +60,7 @@ public slots:
// manage VNC connection // manage VNC connection
void open(QString host, int port, const int width, const int height); void open(QString host, int port, const int width, const int height);
void refresh(); void refresh();
void decode();
void terminate(); void terminate();
}; };
......
varying highp vec4 varcolor;
void main(void)
{
gl_FragColor = varcolor;
}
uniform highp mat4 ortho;
attribute highp vec2 position;
attribute highp vec4 color;
varying highp vec4 varcolor;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color;
}
...@@ -18,8 +18,11 @@ int main(int argc, char *argv[]) ...@@ -18,8 +18,11 @@ int main(int argc, char *argv[])
format.setMajorVersion(2); format.setMajorVersion(2);
format.setMinorVersion(0); format.setMinorVersion(0);
format.setRenderableType(QSurfaceFormat::OpenGLES); format.setRenderableType(QSurfaceFormat::OpenGLES);
format.setSwapBehavior(QSurfaceFormat::SingleBuffer); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setSwapInterval(0); format.setSwapInterval(1);
#ifdef OGL_DEBUG
format.setOption(QSurfaceFormat::DebugContext, true);
#endif
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES, true); QGuiApplication::setAttribute(Qt::AA_UseOpenGLES, true);
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
......
...@@ -16,7 +16,6 @@ QVnc::QVnc(QQuickItem *parent) : ...@@ -16,7 +16,6 @@ QVnc::QVnc(QQuickItem *parent) :
m_uploader->moveToThread(m_threads[0]); m_uploader->moveToThread(m_threads[0]);
connect(m_threads[0], &QThread::finished, m_uploader, &QObject::deleteLater); connect(m_threads[0], &QThread::finished, m_uploader, &QObject::deleteLater);
// connect(m_uploader, &Uploader::uploadFinished, this, &QVnc::update);
m_dispatcher = new Dispatcher(m_uploader); m_dispatcher = new Dispatcher(m_uploader);
m_dispatcher->moveToThread(m_threads[0]); m_dispatcher->moveToThread(m_threads[0]);
...@@ -25,7 +24,10 @@ QVnc::QVnc(QQuickItem *parent) : ...@@ -25,7 +24,10 @@ QVnc::QVnc(QQuickItem *parent) :
connect(this, &QVnc::open_connection, m_dispatcher, &Dispatcher::open); connect(this, &QVnc::open_connection, m_dispatcher, &Dispatcher::open);
connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate); connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate);
connect(m_dispatcher, &Dispatcher::error, this, &QVnc::dispatch_error); connect(m_dispatcher, &Dispatcher::error, this, &QVnc::dispatch_error);
connect(m_uploader, &Uploader::uploadFinished, m_dispatcher, &Dispatcher::refresh); connect(m_uploader, &Uploader::uploadFinished, m_dispatcher, &Dispatcher::refresh);
// connect(m_uploader, &Uploader::uploadFinished, this, &QVnc::update);
connect(m_uploader, &Uploader::buffersSwapped, m_dispatcher, &Dispatcher::decode);
int i = 1; int i = 1;
foreach(JpegDecoder* d, m_decoders) { foreach(JpegDecoder* d, m_decoders) {
...@@ -88,20 +90,23 @@ void QVnc::winChanged(QQuickWindow *window) ...@@ -88,20 +90,23 @@ void QVnc::winChanged(QQuickWindow *window)
{ {
if(window != NULL) { if(window != NULL) {
connect(window, &QQuickWindow::openglContextCreated, m_uploader, &Uploader::createContext, Qt::BlockingQueuedConnection); connect(window, &QQuickWindow::openglContextCreated, m_uploader, &Uploader::createContext, Qt::BlockingQueuedConnection);
connect(window, &QQuickWindow::frameSwapped, m_uploader, &Uploader::frameSwapped); connect(window, &QQuickWindow::frameSwapped, m_uploader, &Uploader::swapBuffers, Qt::BlockingQueuedConnection);
} }
} }
QQuickFramebufferObject::Renderer *QVnc::createRenderer() const QQuickFramebufferObject::Renderer *QVnc::createRenderer() const
{ {
VncRenderer *renderer = new VncRenderer(window(), return new VncRenderer(window(),
m_uploader->vertices(), m_uploader->fillBuffer(),
m_uploader->indices(), m_uploader->copyBuffer(),
m_uploader->texture(), m_uploader->bitmapBuffer(),
m_uploader->drawCount()); m_uploader->texture(),
connect(renderer, &VncRenderer::FBOTextureChanged, m_uploader, &Uploader::changeFBOTexture); NULL,
connect(renderer, &VncRenderer::finishedRendering, m_uploader, &Uploader::finishedRendering); NULL,
return renderer; NULL,
m_uploader->fillCount(),
m_uploader->copyCount(),
m_uploader->bitmapCount());
} }
QString QVnc::host() const QString QVnc::host() const
...@@ -200,6 +205,11 @@ void QVnc::hoverMoveEvent(QHoverEvent *event) ...@@ -200,6 +205,11 @@ void QVnc::hoverMoveEvent(QHoverEvent *event)
// } // }
} }
Uploader *QVnc::uploader() const
{
return m_uploader;
}
void QVnc::keyPressEvent(QKeyEvent *event) void QVnc::keyPressEvent(QKeyEvent *event)
{ {
} }
......
#ifndef VNC_H #ifndef VNC_H
#define VNC_H #define VNC_H
#define DECODER_COUNT 8 #define DECODER_COUNT 5
// #define OGL_DEBUG
#include <QQuickWindow> #include <QQuickWindow>
#include <QObject> #include <QObject>
...@@ -9,11 +11,14 @@ ...@@ -9,11 +11,14 @@
#include <QThread> #include <QThread>
#include <QOffscreenSurface> #include <QOffscreenSurface>
#include <QMouseEvent> #include <QMouseEvent>
#include <QOpenGLDebugLogger>
#include "dispatcher.h" #include "dispatcher.h"
#include "vncrenderer.h" #include "vncrenderer.h"
#include "uploader.h" #include "uploader.h"
class VncRenderer;
/*! /*!
* \brief The public interface of the VNC functionality * \brief The public interface of the VNC functionality
*/ */
...@@ -30,6 +35,7 @@ public: ...@@ -30,6 +35,7 @@ public:
Renderer *createRenderer() const; Renderer *createRenderer() const;
QString host() const; QString host() const;
int port() const; int port() const;
Uploader *uploader() const;
protected: protected:
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);
...@@ -49,6 +55,9 @@ private: ...@@ -49,6 +55,9 @@ private:
int m_port; int m_port;
ulong m_lastMouseEvent; ulong m_lastMouseEvent;
bool m_swapped;
bool m_finished;
signals: signals:
void open_connection(const QString host, const int port, const int width, const int height); void open_connection(const QString host, const int port, const int width, const int height);
void terminate_connection(); void terminate_connection();
...@@ -57,6 +66,8 @@ signals: ...@@ -57,6 +66,8 @@ signals:
void portChanged(int port); void portChanged(int port);
void operate(); void operate();
void refresh();
public slots: public slots:
void open(); void open();
void terminate(); void terminate();
......
#include "uploader.h" #include "uploader.h"
Uploader::Uploader(QObject *parent) : Uploader::Uploader(QObject *parent) :
QObject(parent), m_context(this), m_indices(QOpenGLBuffer::IndexBuffer), QObject(parent), m_context(this),
m_uploadVertices(new QOpenGLBuffer*), m_renderVertices(new QOpenGLBuffer*), m_uploadFill(new QOpenGLBuffer*), m_renderFill(new QOpenGLBuffer*),
m_uploadTexture(new GLuint*), m_renderTexture(new GLuint*), m_program(this), m_jpegs(0), m_uploadCopy(new QOpenGLBuffer*), m_renderCopy(new QOpenGLBuffer*),
m_atlasX(1), m_atlasY(1), m_atlasRowHeight(0), m_atlasLastWidth(0), m_copyIndex(0) m_uploadBitmap(new QOpenGLBuffer*), m_renderBitmap(new QOpenGLBuffer*),
m_uploadTexture(new GLuint*), m_renderTexture(new GLuint*),
m_jpegs(0), m_atlasX(0), m_atlasY(0), m_atlasRowHeight(0), m_atlasLastWidth(0)
{ {
// "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"
QSurfaceFormat format;
format.setAlphaBufferSize(8);
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
format.setDepthBufferSize(0);
format.setStencilBufferSize(0);
format.setMajorVersion(2);
format.setMinorVersion(0);
format.setRenderableType(QSurfaceFormat::OpenGLES);
format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
format.setSwapInterval(0);
m_surface.setFormat(format);
m_surface.create(); m_surface.create();
m_drawCount = new unsigned int(0);
m_rendered = true; m_fillCount = new unsigned int(0);
m_copyCount = new unsigned int(0);
m_bitmapCount = new unsigned int(0);
} }
Uploader::~Uploader() Uploader::~Uploader()
{ {
m_program.release(); }
void Uploader::handleDebugMessage(const QOpenGLDebugMessage &debugMessage)
{
qDebug() << debugMessage;
} }
void Uploader::createContext(QOpenGLContext *context) void Uploader::createContext(QOpenGLContext *context)
...@@ -23,74 +44,73 @@ void Uploader::createContext(QOpenGLContext *context) ...@@ -23,74 +44,73 @@ void Uploader::createContext(QOpenGLContext *context)
m_context.create(); m_context.create();
m_context.makeCurrent(&m_surface); m_context.makeCurrent(&m_surface);
m_functions = m_context.functions(); #ifdef OGL_DEBUG
m_functions->glEnable(GL_CULL_FACE); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
connect(logger, &QOpenGLDebugLogger::messageLogged, this, &Uploader::handleDebugMessage, Qt::DirectConnection);
m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "copy_shader.vsh"); logger->initialize();
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "copy_shader.fsh"); logger->startLogging();
m_program.bind(); #endif
m_program.setUniformValue("texture", 1);
m_program.enableAttributeArray("position"); m_gl = m_context.functions();
m_program.enableAttributeArray("texcoord");
*m_renderFill = new QOpenGLBuffer;
m_indices.create(); (*m_renderFill)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_indices.bind(); (*m_renderFill)->create();
m_indices.allocate(ind.i, (VERTEX_BUFFER * 6 - 2) * sizeof(unsigned short)); (*m_renderFill)->bind();
(*m_renderFill)->allocate(VERTEX_BUFFER * sizeof(Fill));
m_copyBuffer.create();
m_copyBuffer.bind(); *m_uploadFill = new QOpenGLBuffer;
m_copyBuffer.allocate(COPY_BUFFER * sizeof(Copy)); (*m_uploadFill)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_copyPointer = (Copy*) m_copyBuffer.map(QOpenGLBuffer::WriteOnly); (*m_uploadFill)->create();
(*m_uploadFill)->bind();
*m_renderVertices = new QOpenGLBuffer; (*m_uploadFill)->allocate(VERTEX_BUFFER * sizeof(Fill));
(*m_renderVertices)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderVertices)->create(); *m_renderCopy = new QOpenGLBuffer;
(*m_renderVertices)->bind(); (*m_renderCopy)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderVertices)->allocate(VERTEX_BUFFER * sizeof(Vertex)); (*m_renderCopy)->create();
(*m_renderCopy)->bind();
*m_uploadVertices = new QOpenGLBuffer; (*m_renderCopy)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
(*m_uploadVertices)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadVertices)->create(); *m_uploadCopy = new QOpenGLBuffer;
(*m_uploadVertices)->bind(); (*m_uploadCopy)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadVertices)->allocate(VERTEX_BUFFER * sizeof(Vertex)); (*m_uploadCopy)->create();
(*m_uploadCopy)->bind();
m_vertexPointer = (Vertex*) (*m_uploadVertices)->map(QOpenGLBuffer::WriteOnly); (*m_uploadCopy)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
m_vertexIndex = 0;
*m_renderBitmap = new QOpenGLBuffer;
m_functions->glEnable(GL_TEXTURE_2D); (*m_renderBitmap)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_functions->glActiveTexture(GL_TEXTURE0); (*m_renderBitmap)->create();
m_functions->glGenTextures(2, m_texId); (*m_renderBitmap)->bind();
unsigned char black[] = {0, 0, 0, 0}; (*m_renderBitmap)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
*m_uploadBitmap = new QOpenGLBuffer;
(*m_uploadBitmap)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadBitmap)->create();
(*m_uploadBitmap)->bind();
(*m_uploadBitmap)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
m_gl->glActiveTexture(GL_TEXTURE0);
m_gl->glGenTextures(2, m_texId);
for(size_t i = 0; i < 2; i++) { for(size_t i = 0; i < 2; i++) {
m_functions->glBindTexture(GL_TEXTURE_2D, m_texId[i]); m_gl->glBindTexture(GL_TEXTURE_2D, m_texId[i]);
m_functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
m_functions->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, black);
} }
*m_uploadTexture = m_texId; *m_renderTexture = &m_texId[0];
*m_renderTexture = m_texId + 1; *m_uploadTexture = &m_texId[1];
m_functions->glGenFramebuffers(1, &m_FBOId); m_gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
m_functions->glBindFramebuffer(GL_FRAMEBUFFER, m_FBOId);
m_functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, **m_uploadTexture, 0);
m_functions->glBindTexture(GL_TEXTURE_2D, **m_uploadTexture);
m_functions->glViewport(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
m_functions->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
} }
void Uploader::gotFill(const GLushort x, const GLushort y, void Uploader::gotFill(const GLushort x, const GLushort y,
const GLushort width, const GLushort height, const GLushort width, const GLushort height,
const GLubyte red, const GLubyte green, const GLubyte blue) const GLubyte red, const GLubyte green, const GLubyte blue)
{ {
if(m_vertexIndex + 4 < VERTEX_BUFFER) { if(m_fillIndex + 4 < VERTEX_BUFFER) {
// bottom left m_fillPointer[m_fillIndex++] = Fill({x, (GLushort) (y + height), red, green, blue, 0xFF});
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), red, green, blue, 0xFF, 0, 0}); m_fillPointer[m_fillIndex++] = Fill({x, y, red, green, blue, 0xFF});
// top left m_fillPointer[m_fillIndex++] = Fill({(GLushort) (x + width), (GLushort) (y + height), red, green, blue, 0xFF});
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, red, green, blue, 0xFF, 0, 0}); m_fillPointer[m_fillIndex++] = Fill({(GLushort) (x + width), y, red, green, blue, 0xFF});
// bottom right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), (GLushort) (y + height), red, green, blue, 0xFF, 0, 0});
// top right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), y, red, green, blue, 0xFF, 0, 0});
} else { } else {
qDebug() << "Out of memory"; qDebug() << "Out of memory";
} }
...@@ -103,26 +123,20 @@ void Uploader::gotCopy(const GLushort src_x, const GLushort src_y, ...@@ -103,26 +123,20 @@ void Uploader::gotCopy(const GLushort src_x, const GLushort src_y,
if(!refreshAtlas(width, height)) if(!refreshAtlas(width, height))
return; return;
// copy from source if(m_copyIndex + 4 < VERTEX_BUFFER) {
if(m_copyIndex + 4 < COPY_BUFFER) { m_copyPointer[m_copyIndex++] = Bitmap({m_atlasX, (GLushort) (m_atlasY + height), src_x, (GLushort) (src_y + height)});
m_copyPointer[m_copyIndex++] = Copy({m_atlasX, (GLushort) (m_atlasY + height), src_x, (GLushort) (src_y + height)}); m_copyPointer[m_copyIndex++] = Bitmap({m_atlasX, m_atlasY, src_x, src_y});
m_copyPointer[m_copyIndex++] = Copy({m_atlasX, m_atlasY, src_x, src_y}); m_copyPointer[m_copyIndex++] = Bitmap({(GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height), (GLushort) (src_x + width), (GLushort) (src_y + height)});
m_copyPointer[m_copyIndex++] = Copy({(GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height), (GLushort) (src_x + width), (GLushort) (src_y + height)}); m_copyPointer[m_copyIndex++] = Bitmap({(GLushort) (m_atlasX + width), m_atlasY, (GLushort) (src_x + width), src_y});
m_copyPointer[m_copyIndex++] = Copy({(GLushort) (m_atlasX + width), m_atlasY, (GLushort) (src_x + width), src_y});
} else { } else {
qDebug() << "Out of memory"; qDebug() << "Out of memory";
} }
// copy to destination if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
if(m_vertexIndex + 4 < VERTEX_BUFFER) { m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, (GLushort) (dest_y + height), m_atlasX, (GLushort) (m_atlasY + height)});
// bottom left m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, dest_y, m_atlasX, m_atlasY});
m_vertexPointer[m_vertexIndex++] = Vertex({dest_x, (GLushort) (dest_y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)}); m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), (GLushort) (dest_y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
// top left m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), dest_y, (GLushort) (m_atlasX + width), m_atlasY});
m_vertexPointer[m_vertexIndex++] = Vertex({dest_x, dest_y, 0, 0, 0, 0, m_atlasX, m_atlasY});
// bottom right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (dest_x + width), (GLushort) (dest_y + height), 0, 0, 0, 0, (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
// top right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (dest_x + width), dest_y, 0, 0, 0, 0, (GLushort) (m_atlasX + width), m_atlasY});
} else { } else {
qDebug() << "Out of memory"; qDebug() << "Out of memory";
} }
...@@ -135,17 +149,13 @@ void Uploader::gotBitmap(const unsigned char *image, ...@@ -135,17 +149,13 @@ void Uploader::gotBitmap(const unsigned char *image,
if(!refreshAtlas(width, height)) if(!refreshAtlas(width, height))
return; return;
m_functions->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image); m_gl->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
if(m_vertexIndex + 4 < VERTEX_BUFFER) { if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
// bottom left m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, (GLushort) (y + height), m_atlasX, (GLushort) (m_atlasY + height)});
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)}); m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, y, m_atlasX, m_atlasY});
// top left m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), (GLushort) (y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, 0, 0, 0, 0, m_atlasX, m_atlasY}); m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), y, (GLushort) (m_atlasX + width), m_atlasY});
// bottom right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), (GLushort) (y + height), 0, 0, 0, 0, (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
// top right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), y, 0, 0, 0, 0, (GLushort) (m_atlasX + width), m_atlasY});
} else { } else {
qDebug() << "Out of memory"; qDebug() << "Out of memory";
} }
...@@ -165,61 +175,38 @@ void Uploader::finishedJpeg(const unsigned char *image, ...@@ -165,61 +175,38 @@ void Uploader::finishedJpeg(const unsigned char *image,
m_jpegs--; m_jpegs--;
m_functions->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image); m_gl->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
delete[] image; delete[] image;
if(m_vertexIndex + 4 < VERTEX_BUFFER) { if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
// bottom left m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, (GLushort) (y + height), m_atlasX, (GLushort) (m_atlasY + height)});
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)}); m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, y, m_atlasX, m_atlasY});
// top left m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), (GLushort) (y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, 0, 0, 0, 0, m_atlasX, m_atlasY}); m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), y, (GLushort) (m_atlasX + width), m_atlasY});
// bottom right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), (GLushort) (y + height), 0, 0, 0, 0, (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
// top right
m_vertexPointer[m_vertexIndex++] = Vertex({(GLushort) (x + width), y, 0, 0, 0, 0, (GLushort) (m_atlasX + width), m_atlasY});
} else { } else {
qDebug() << "Out of memory"; qDebug() << "Out of memory";
} }
if(m_jpegs == 0 && m_finished && m_swapped) { if(m_jpegs == 0)
startRendering(); qDebug() << "jpeg" << elapsed.elapsed();
}
}
// The previous frame finished rendering
void Uploader::finishedRendering()
{
m_rendered = true;
}
void Uploader::frameSwapped() if(m_jpegs == 0 && m_finished) {
{ startRendering();
if(m_rendered) {
m_swapped = true;
if(m_finished) {
copyRectangles();
if(m_jpegs == 0) {
startRendering();
}
}
} }
} }
void Uploader::finishedUpdate() void Uploader::finishedUpdate()
{ {
m_finished = true; m_finished = true;
if(m_swapped) { if(m_jpegs == 0)
copyRectangles(); startRendering();
if(m_jpegs == 0)
startRendering();
}
} }
bool Uploader::refreshAtlas(const int width, const int height) bool Uploader::refreshAtlas(const int width, const int height)
{ {
if(m_atlasX + m_atlasLastWidth + width <= TEXTURE_WIDTH) { if(m_atlasX + m_atlasLastWidth + width <= TEXTURE_WIDTH) {
if(m_atlasY + height > TEXTURE_HEIGHT) { if(m_atlasY + height > TEXTURE_HEIGHT) {
qDebug() << "Out of memory"; qDebug() << "Atlas out of memory" << m_atlasX << m_atlasY << width << height;
return false; return false;
} }
...@@ -230,7 +217,7 @@ bool Uploader::refreshAtlas(const int width, const int height) ...@@ -230,7 +217,7 @@ bool Uploader::refreshAtlas(const int width, const int height)
m_atlasRowHeight = height; m_atlasRowHeight = height;
} else { } else {
if(m_atlasY + m_atlasRowHeight + height > TEXTURE_HEIGHT) { if(m_atlasY + m_atlasRowHeight + height > TEXTURE_HEIGHT) {
qDebug() << "Out of memory"; qDebug() << "Atlas out of memory" << m_atlasX << m_atlasY << width << height;
return false; return false;
} }
...@@ -242,99 +229,97 @@ bool Uploader::refreshAtlas(const int width, const int height) ...@@ -242,99 +229,97 @@ bool Uploader::refreshAtlas(const int width, const int height)
return true; return true;
} }
void Uploader::startRendering() void Uploader::startDecoding()
{ {
if(m_vertexIndex > 0) { (*m_uploadFill)->bind();
(*m_uploadVertices)->unmap(); m_fillPointer = (Fill*) (*m_uploadFill)->map(QOpenGLBuffer::WriteOnly);
m_functions->glFlush(); (*m_uploadCopy)->bind();
std::swap(*m_uploadVertices, *m_renderVertices); m_copyPointer = (Bitmap*) (*m_uploadCopy)->map(QOpenGLBuffer::WriteOnly);
(*m_uploadBitmap)->bind();
(*m_uploadVertices)->bind(); m_bitmapPointer = (Bitmap*) (*m_uploadBitmap)->map(QOpenGLBuffer::WriteOnly);
m_vertexPointer = (Vertex*) (*m_uploadVertices)->map(QOpenGLBuffer::WriteOnly);
m_gl->glBindTexture(GL_TEXTURE_2D, **m_uploadTexture);
m_fillIndex = 0;
m_copyIndex = 0;
m_bitmapIndex = 0;
m_atlasX = 1;
m_atlasY = 1;
m_atlasRowHeight = 0;
m_atlasLastWidth = 0;
elapsed.restart();
}
std::swap(*m_uploadTexture, *m_renderTexture); void Uploader::startRendering()
m_functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, **m_uploadTexture, 0); {
m_functions->glBindTexture(GL_TEXTURE_2D, **m_uploadTexture); (*m_uploadFill)->bind();
(*m_uploadFill)->unmap();
(*m_uploadCopy)->bind();
(*m_uploadCopy)->unmap();
(*m_uploadBitmap)->bind();
(*m_uploadBitmap)->unmap();
*m_drawCount = (m_vertexIndex / 4) * 6 - 2; qDebug() << "rendering" << elapsed.elapsed();
m_gl->glFlush();
m_vertexIndex = 0; m_finished = false;
m_swap = true;
m_atlasX = 1; qDebug() << "flush" << elapsed.elapsed();
m_atlasY = 1;
m_atlasRowHeight = 0;
m_atlasLastWidth = 0;
m_rendered = false;
m_swapped = false;
m_finished = false;
} else {
m_rendered = true;
}
emit uploadFinished(); emit uploadFinished();
} }
void Uploader::copyRectangles() void Uploader::swapBuffers()
{ {
if(m_copyIndex > 0) { if(m_swap) {
m_functions->glActiveTexture(GL_TEXTURE1); std::swap(*m_uploadFill, *m_renderFill);
m_copyBuffer.bind(); std::swap(*m_uploadCopy, *m_renderCopy);
m_copyBuffer.unmap(); std::swap(*m_uploadBitmap, *m_renderBitmap);
m_functions->glVertexAttribPointer(m_program.attributeLocation("position"), std::swap(*m_uploadTexture, *m_renderTexture);
2,
GL_UNSIGNED_SHORT, *m_fillCount = m_fillIndex ? (m_fillIndex / 4) * 6 - 2 : 0;
GL_FALSE, *m_copyCount = m_copyIndex ? (m_copyIndex / 4) * 6 - 2 : 0;
sizeof(Copy), *m_bitmapCount = m_bitmapIndex ? (m_bitmapIndex / 4) * 6 - 2 : 0;
(void*) 0);
m_functions->glVertexAttribPointer(m_program.attributeLocation("texcoord"), m_swap = false;
2, qDebug() << "swap" << elapsed.elapsed();
GL_UNSIGNED_SHORT, emit buffersSwapped();
GL_FALSE,
sizeof(Copy),
(void*) (2 * sizeof(GLushort)));
m_indices.bind();
m_functions->glDrawElements(GL_TRIANGLE_STRIP, (m_copyIndex / 4) * 6 - 2, GL_UNSIGNED_SHORT, (GLvoid*) 0);
m_copyPointer = (Copy*) m_copyBuffer.map(QOpenGLBuffer::WriteOnly);
(*m_uploadVertices)->bind();
m_functions->glActiveTexture(GL_TEXTURE0);
m_copyIndex = 0;
} }
} }
QOpenGLBuffer **Uploader::vertices() const GLuint **Uploader::texture() const
{ {
return m_renderVertices; return m_renderTexture;
} }
GLuint **Uploader::texture() const QOpenGLBuffer **Uploader::fillBuffer() const
{ {
return m_renderTexture; return m_renderFill;
} }
QOpenGLBuffer Uploader::indices() const QOpenGLBuffer **Uploader::copyBuffer() const
{ {
return m_indices; return m_renderCopy;
} }
unsigned int *Uploader::drawCount() const QOpenGLBuffer **Uploader::bitmapBuffer() const
{ {
return m_drawCount; return m_renderBitmap;
} }
void Uploader::changeFBOTexture(const unsigned int FBOTexture, const QMatrix4x4 &ortho) unsigned int *Uploader::fillCount() const
{ {
m_FBOTexture = FBOTexture; return m_fillCount;
}
m_functions->glActiveTexture(GL_TEXTURE1); unsigned int *Uploader::copyCount() const
m_functions->glBindTexture(GL_TEXTURE_2D, m_FBOTexture); {
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); return m_copyCount;
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->glActiveTexture(GL_TEXTURE0);
m_program.setUniformValue("texortho", ortho); unsigned int *Uploader::bitmapCount() const
{
return m_bitmapCount;
} }
...@@ -16,64 +16,42 @@ ...@@ -16,64 +16,42 @@
#ifndef UPLOADER_H #ifndef UPLOADER_H
#define UPLOADER_H #define UPLOADER_H
#define TEXTURE_WIDTH 2048 #define TEXTURE_WIDTH 4096
#define TEXTURE_HEIGHT 2048 #define TEXTURE_HEIGHT 4096
#define COPY_BUFFER 1024
#define VERTEX_BUFFER 1024 #define VERTEX_BUFFER 1024
// #define OGL_DEBUG
#include <utility> #include <utility>
#include <QObject> #include <QObject>
#include <QQuickWindow>
#include <QDebug> #include <QDebug>
#include <QVector>
#include <QOffscreenSurface> #include <QOffscreenSurface>
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLFramebufferObject>
#include <QSharedPointer>
#include <QtMath> #include <QtMath>
#include <QTime> #include <QTime>
#include <QOpenGLDebugLogger>
extern QTime elapsed; extern QTime elapsed;
struct Indices struct Bitmap
{
// 4 corner/rectangle and the first and last one duplicated except for the first and last rectangle
unsigned short i[(VERTEX_BUFFER / 4) * 6 - 2];
Indices() : i()
{
i[0] = 0;
auto index = 1;
for(auto value = 1; value < VERTEX_BUFFER; value++) {
i[index++] = value;
if(value % 4 == 0 || value % 4 == 3)
i[index++] = value;
}
}
};
const struct Indices ind;
struct Vertex
{ {
GLushort x; GLushort x;
GLushort y; GLushort y;
GLubyte red;
GLubyte green;
GLubyte blue;
GLubyte alpha;
GLushort texX; GLushort texX;
GLushort texY; GLushort texY;
}; };
struct Copy struct Fill
{ {
GLushort x; GLushort x;
GLushort y; GLushort y;
GLushort texX; GLubyte red;
GLushort texY; GLubyte green;
GLubyte blue;
GLubyte alpha;
}; };
/*! /*!
...@@ -88,10 +66,14 @@ public: ...@@ -88,10 +66,14 @@ public:
Uploader(QObject *parent = Q_NULLPTR); Uploader(QObject *parent = Q_NULLPTR);
~Uploader(); ~Uploader();
QOpenGLBuffer **vertices() const;
QOpenGLBuffer indices() const;
GLuint **texture() const; GLuint **texture() const;
unsigned int *drawCount() const; QOpenGLBuffer **fillBuffer() const;
QOpenGLBuffer **copyBuffer() const;
QOpenGLBuffer **bitmapBuffer() const;
unsigned int *fillCount() const;
unsigned int *copyCount() const;
unsigned int *bitmapCount() const;
void swapBuffers();
// VNC events // VNC events
void gotFill(const GLushort x, const GLushort y, void gotFill(const GLushort x, const GLushort y,
...@@ -105,69 +87,56 @@ public: ...@@ -105,69 +87,56 @@ public:
const GLushort width, const GLushort height); const GLushort width, const GLushort height);
void gotJpeg(); void gotJpeg();
void finishedUpdate(); void finishedUpdate();
void startDecoding();
private: private:
QOffscreenSurface m_surface; QOffscreenSurface m_surface;
QOpenGLContext m_context; QOpenGLContext m_context;
QOpenGLFunctions *m_functions; QOpenGLFunctions *m_gl;
QOpenGLBuffer m_indices; QOpenGLBuffer **m_uploadFill;
QOpenGLBuffer **m_renderFill;
Fill *m_fillPointer;
size_t m_fillIndex;
unsigned int *m_fillCount;
QOpenGLBuffer **m_uploadCopy;
QOpenGLBuffer **m_renderCopy;
Bitmap *m_copyPointer;
size_t m_copyIndex;
unsigned int *m_copyCount;
QOpenGLBuffer **m_uploadVertices; QOpenGLBuffer **m_uploadBitmap;
QOpenGLBuffer **m_renderVertices; QOpenGLBuffer **m_renderBitmap;
Vertex *m_vertexPointer; Bitmap *m_bitmapPointer;
size_t m_vertexIndex; size_t m_bitmapIndex;
unsigned int *m_bitmapCount;
GLuint m_FBOId;
GLuint m_texId[2]; GLuint m_texId[2];
GLuint **m_uploadTexture; GLuint **m_uploadTexture;
GLuint **m_renderTexture; GLuint **m_renderTexture;
unsigned int *m_drawCount;
QOpenGLShaderProgram m_program;
GLuint m_FBOTexture;
int m_jpegs; int m_jpegs;
// Got a FinishedUpdate event from libvnc
bool m_finished; bool m_finished;
// The rendering thread finished rendering the previous frame bool m_swap;
bool m_rendered;
// Framebuffer swapped
bool m_swapped;
unsigned short m_atlasX; unsigned short m_atlasX;
unsigned short m_atlasY; unsigned short m_atlasY;
unsigned short m_atlasRowHeight; unsigned short m_atlasRowHeight;
unsigned short m_atlasLastWidth; unsigned short m_atlasLastWidth;
QOpenGLBuffer m_copyBuffer;
Copy *m_copyPointer;
size_t m_copyIndex;
bool refreshAtlas(const int width, const int height); bool refreshAtlas(const int width, const int height);
// Called when:
// - got a Finished update event from libvnc
// - and every jpeg was uploaded
// - and the rendering thread swapped buffers
void startRendering(); void startRendering();
// Called when:
// - got a Finished update event from libvnc
// - and the rendering thread swapped buffers
void copyRectangles();
signals: signals:
// Emit from startRendering only!
void uploadFinished(); void uploadFinished();
void buffersSwapped();
public slots: public slots:
void changeFBOTexture(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void createContext(QOpenGLContext *context); void createContext(QOpenGLContext *context);
void finishedJpeg(const unsigned char *image, void finishedJpeg(const unsigned char *image,
const GLushort x, const GLushort y, const GLushort x, const GLushort y,
const GLushort width, const GLushort height); const GLushort width, const GLushort height);
void finishedRendering(); private slots:
void frameSwapped(); void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
}; };
#endif // UPLOADER_H #endif // UPLOADER_H
...@@ -3,92 +3,210 @@ ...@@ -3,92 +3,210 @@
#include "uploader.h" #include "uploader.h"
VncRenderer::VncRenderer(QQuickWindow *window, VncRenderer::VncRenderer(QQuickWindow *window,
QOpenGLBuffer **vertices, QOpenGLBuffer **fillBuffer,
QOpenGLBuffer indices, QOpenGLBuffer **copyBuffer,
GLuint **texture, QOpenGLBuffer **bitmapBuffer,
unsigned int *drawCount, GLuint **rgbTexture,
QObject *parent) : GLuint **yTexture,
QObject(parent), m_window(window), m_vertices(vertices), m_indices(indices), m_texture(texture), m_drawCount(drawCount), m_rendered(false) GLuint **cbTexture,
GLuint **crTexture,
unsigned int *fillCount,
unsigned int *copyCount,
unsigned int *bitmapCount, QObject *parent) :
QObject(parent), m_window(window),
m_fillBuffer(fillBuffer), m_copyBuffer(copyBuffer), m_bitmapBuffer(bitmapBuffer),
m_rgbTexture(rgbTexture), m_yTexture(yTexture), m_cbTexture(cbTexture), m_crTexture(crTexture),
m_fillCount(fillCount), m_copyCount(copyCount), m_bitmapCount(bitmapCount),
m_indices(QOpenGLBuffer::IndexBuffer)
{ {
m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "draw_shader.vsh"); #ifdef OGL_DEBUG
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "draw_shader.fsh"); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
m_program.bind(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, &VncRenderer::handleDebugMessage, Qt::DirectConnection);
m_program.setUniformValue("texture", 0); logger->initialize();
QMatrix4x4 ortho; logger->startLogging();
ortho.ortho(QRect(QPoint(0, 0), QSize(2048, 2048))); #endif
m_program.setUniformValue("texortho", ortho);
m_program.release(); m_copyOrtho.ortho(QRect(QPoint(0, TEXTURE_HEIGHT), QSize(TEXTURE_WIDTH, -1 * TEXTURE_HEIGHT)));
m_bitmapTexortho.ortho(QRect(QPoint(-1 * TEXTURE_WIDTH, TEXTURE_HEIGHT), QSize(2 * TEXTURE_WIDTH, -2 * TEXTURE_HEIGHT)));
m_functions = QOpenGLContext::currentContext()->functions();
m_functions->glActiveTexture(GL_TEXTURE0); m_fillProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "/home/ldmnyblzs/Projects/ThinClient/fill_shader.vsh");
m_fillProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "/home/ldmnyblzs/Projects/ThinClient/fill_shader.fsh");
m_fillProgram.link();
m_bitmapProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "/home/ldmnyblzs/Projects/ThinClient/bitmap_shader.vsh");
m_bitmapProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "/home/ldmnyblzs/Projects/ThinClient/bitmap_shader.fsh");
m_bitmapProgram.link();
/*m_ycbcrProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "/home/ldmnyblzs/Projects/ThinClient/bitmap_shader.vsh");
m_ycbcrProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "/home/ldmnyblzs/Projects/ThinClient/ycbcr_shader.fsh");
m_ycbcrProgram.bind();
m_ycbcrProgram.enableAttributeArray("position");
m_ycbcrProgram.enableAttributeArray("texcoord");
m_ycbcrProgram.setUniformValue("y_texture", 2);
m_ycbcrProgram.setUniformValue("cb_texture", 3);
m_ycbcrProgram.setUniformValue("cr_texture", 4);*/
m_indices.create();
m_indices.bind();
m_indices.allocate(ind.i, (VERTEX_BUFFER / 4) * 6 - 2);
m_gl = QOpenGLContext::currentContext()->functions();
m_gl->glGenFramebuffers(0, &m_textureTarget);
frameTime.start();
}
void VncRenderer::handleDebugMessage(const QOpenGLDebugMessage &debugMessage)
{
qDebug() << debugMessage;
} }
void VncRenderer::render() void VncRenderer::render()
{ {
if(*m_drawCount > 0) { frameCount++;
static QTime frameTime; if(frameTime.elapsed() > 1000) {
qDebug() << qRound(1000.0 / frameTime.restart()); // qDebug() << frameCount;
m_program.bind(); frameCount = 0;
(*m_vertices)->bind(); frameTime.restart();
m_indices.bind(); }
m_functions->glVertexAttribPointer(m_program.attributeLocation("position"),
/* Rendering:
* 1. Draw filled rectangles
* 2. Copy rectangles from the framebuffer to a temporary texture
* 3. Draw RGB textured rectangles
* 4. Draw YCbCr textured rectangles
*/
/*m_gl->glActiveTexture(GL_TEXTURE0);
m_gl->glBindTexture(GL_TEXTURE_2D, m_framebufferObject->texture());
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/
m_gl->glActiveTexture(GL_TEXTURE1);
m_gl->glBindTexture(GL_TEXTURE_2D, **m_rgbTexture);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/*m_gl->glActiveTexture(GL_TEXTURE2);
m_gl->glBindTexture(GL_TEXTURE_2D, **m_yTexture);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_gl->glActiveTexture(GL_TEXTURE3);
m_gl->glBindTexture(GL_TEXTURE_2D, **m_crTexture);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_gl->glActiveTexture(GL_TEXTURE4);
m_gl->glBindTexture(GL_TEXTURE_2D, **m_cbTexture);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);*/
m_indices.bind();
if(*m_fillCount > 0) {
m_fillProgram.bind();
m_fillProgram.enableAttributeArray("position");
m_fillProgram.enableAttributeArray("color");
(*m_fillBuffer)->bind();
m_gl->glVertexAttribPointer(m_fillProgram.attributeLocation("position"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Fill),
(void*) 0);
m_gl->glVertexAttribPointer(m_fillProgram.attributeLocation("color"),
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
sizeof(Fill),
(void*) (2 * sizeof(GLushort)));
m_fillProgram.setUniformValue("ortho", m_bitmapOrtho);
m_gl->glDrawElements(GL_TRIANGLE_STRIP, *m_fillCount, GL_UNSIGNED_SHORT, (void*) 0);
}
if(*m_bitmapCount > 0) {
m_bitmapProgram.bind();
m_bitmapProgram.enableAttributeArray("position");
m_bitmapProgram.enableAttributeArray("texcoord");
}
if(*m_copyCount > 0) {
(*m_copyBuffer)->bind();
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("position"),
2, 2,
GL_UNSIGNED_SHORT, GL_UNSIGNED_SHORT,
GL_FALSE, GL_FALSE,
sizeof(Vertex), sizeof(Bitmap),
(void*) 0); (void*) 0);
m_functions->glVertexAttribPointer(m_program.attributeLocation("color"), m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("texcoord"),
4, 2,
GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT,
GL_TRUE, GL_FALSE,
sizeof(Vertex), sizeof(Bitmap),
(void*) (2 * sizeof(GLushort))); (void*) (2 * sizeof(GLushort)));
m_functions->glVertexAttribPointer(m_program.attributeLocation("texcoord"),
// copy to the texture
m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_textureTarget);
m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, **m_rgbTexture, 0);
m_gl->glViewport(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
m_bitmapProgram.setUniformValue("texture", 0);
m_bitmapProgram.setUniformValue("ortho", m_copyOrtho);
m_bitmapProgram.setUniformValue("texortho", m_copyTexortho);
m_gl->glDrawElements(GL_TRIANGLE_STRIP, *m_copyCount, GL_UNSIGNED_SHORT, (void*) 0);
m_framebufferObject->bind();
m_gl->glViewport(0, 0, 1920, 1080);
}
if(*m_bitmapCount > 0) {
// rgb
(*m_bitmapBuffer)->bind();
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("position"),
2, 2,
GL_UNSIGNED_SHORT, GL_UNSIGNED_SHORT,
GL_FALSE, GL_FALSE,
sizeof(Vertex), sizeof(Bitmap),
(void*) (2 * sizeof(GLushort) + 4 * sizeof(GLubyte))); (void*) 0);
m_program.enableAttributeArray("position"); m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("texcoord"),
m_program.enableAttributeArray("color"); 2,
m_program.enableAttributeArray("texcoord"); GL_UNSIGNED_SHORT,
m_functions->glBindTexture(GL_TEXTURE_2D, **m_texture); GL_FALSE,
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); sizeof(Bitmap),
m_functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); (void*) (2 * sizeof(GLushort)));
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_bitmapProgram.setUniformValue("texture", 1);
m_bitmapProgram.setUniformValue("ortho", m_bitmapOrtho);
m_functions->glDrawElements(GL_TRIANGLE_STRIP, *m_drawCount, GL_UNSIGNED_SHORT, (void*) 0); m_bitmapProgram.setUniformValue("texortho", m_bitmapTexortho);
*m_drawCount = 0;
m_gl->glDrawElements(GL_TRIANGLE_STRIP, *m_bitmapCount, GL_UNSIGNED_SHORT, (void*) 0);
m_window->resetOpenGLState();
emit finishedRendering();
} }
*m_fillCount = 0;
*m_copyCount = 0;
*m_bitmapCount = 0;
update(); update();
m_window->resetOpenGLState();
} }
QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size) QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size)
{ {
QMatrix4x4 ortho; m_copyTexortho.ortho(QRect(QPoint(-1 * size.width(), size.height()), QSize(2 * size.width(), -2 * size.height())));
ortho.ortho(QRect(QPoint(0, size.height()), QSize(size.width(), -1 * size.height()))); m_bitmapOrtho.ortho(QRect(QPoint(0, size.height()), QSize(size.width(), -1 * size.height())));
m_program.bind();
m_program.setUniformValue("ortho", ortho);
m_program.release();
QOpenGLFramebufferObjectFormat format;
format.setTextureTarget(GL_TEXTURE_2D);
#ifdef GL_RGBA8
format.setInternalTextureFormat(GL_RGBA8);
#else
#ifdef RGBA8_OES
format.setInternalTextureFormat(RGBA8_OES);
#else
format.setInternalTextureFormat(GL_RGBA);
#endif
#endif
QOpenGLFramebufferObject *framebufferObject = new QOpenGLFramebufferObject(size); m_framebufferObject = new QOpenGLFramebufferObject(size);
emit FBOTextureChanged(framebufferObject->texture(), ortho); return m_framebufferObject;
return framebufferObject;
} }
...@@ -11,32 +11,78 @@ ...@@ -11,32 +11,78 @@
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QTime> #include <QTime>
#include "qvnc.h"
struct Indices
{
// 4 corner/rectangle and the first and last one duplicated except for the first and last rectangle
unsigned short i[(VERTEX_BUFFER / 4) * 6 - 2];
Indices() : i()
{
i[0] = 0;
auto index = 1;
for(auto value = 1; value < VERTEX_BUFFER; value++) {
i[index++] = value;
if(value % 4 == 0 || value % 4 == 3)
i[index++] = value;
}
}
};
const struct Indices ind;
class VncRenderer : public QObject, public QQuickFramebufferObject::Renderer class VncRenderer : public QObject, public QQuickFramebufferObject::Renderer
{ {
Q_OBJECT Q_OBJECT
public: public:
VncRenderer(QQuickWindow *window, VncRenderer(QQuickWindow *window,
QOpenGLBuffer **vertices, QOpenGLBuffer **fillBuffer,
QOpenGLBuffer indices, QOpenGLBuffer **copyBuffer,
GLuint **textures, QOpenGLBuffer **bitmapBuffer,
unsigned int *drawCount, GLuint **rgbTexture,
QObject *parent = 0); GLuint **yTexture,
GLuint **cbTexture,
GLuint **crTexture,
unsigned int *fillCount,
unsigned int *copyCount,
unsigned int *bitmapCount,
QObject *parent = nullptr);
protected: protected:
void render() override; void render() override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override; QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
private: private:
QQuickWindow *m_window; QQuickWindow *m_window;
QOpenGLBuffer **m_vertices;
QMatrix4x4 m_copyOrtho;
QMatrix4x4 m_copyTexortho;
QMatrix4x4 m_bitmapOrtho;
QMatrix4x4 m_bitmapTexortho;
QOpenGLBuffer **m_fillBuffer;
QOpenGLBuffer **m_copyBuffer;
QOpenGLBuffer **m_bitmapBuffer;
GLuint **m_rgbTexture;
GLuint **m_yTexture;
GLuint **m_cbTexture;
GLuint **m_crTexture;
unsigned int *m_fillCount;
unsigned int *m_copyCount;
unsigned int *m_bitmapCount;
QOpenGLBuffer m_indices; QOpenGLBuffer m_indices;
GLuint **m_texture; QOpenGLShaderProgram m_fillProgram;
unsigned int *m_drawCount; QOpenGLShaderProgram m_bitmapProgram;
QVector3D m_colorMax; QOpenGLShaderProgram m_ycbcrProgram;
QOpenGLShaderProgram m_program; GLuint m_textureTarget;
QOpenGLFunctions *m_functions; QOpenGLFunctions *m_gl;
bool m_rendered;
signals: QOpenGLFramebufferObject *m_framebufferObject;
void FBOTextureChanged(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void finishedRendering(); int frameCount;
QTime frameTime;
private slots:
void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
}; };
#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