Commit cb68f729 by Ludmány Balázs

Move copy to the rendering thread

parent 0b287fd5
......@@ -36,4 +36,8 @@ DISTFILES += \
draw_shader.fsh \
draw_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"?>
<!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>
<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">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.ActiveRunConfiguration">0</value>
<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)
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)
{
if(m_client == NULL)
......@@ -96,12 +103,13 @@ void Dispatcher::open(const QString host, const int port, const int width, const
m_client->GotBitmap = Dispatcher::GotBitmap;
m_client->GotJpeg = Dispatcher::GotJpeg;
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
m_client->appData.useRemoteCursor = TRUE;
m_client->GetPassword = Dispatcher::GetPassword;
// Set the format requested by the user
m_client->appData.useRemoteCursor = TRUE;
m_client->width = width;
m_client->height = height;
m_client->appData.compressLevel = 0;
m_client->appData.compressLevel = 9;
m_client->appData.qualityLevel = 0;
#ifdef __BIG_ENDIAN__
m_client->format.bigEndian = TRUE;
......@@ -137,6 +145,7 @@ void Dispatcher::open(const QString host, const int port, const int width, const
// 16 bit: RGB444, RGB555, RGB565
refresh();
decode();
}
void Dispatcher::refresh()
{
......@@ -154,6 +163,13 @@ void Dispatcher::refresh()
return;
}
}
}
void Dispatcher::decode()
{
if(m_client == NULL)
return;
m_uploader->startDecoding();
if(!HandleRFBServerMessage(m_client)) {
terminate();
......
......@@ -33,6 +33,7 @@ public:
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 void FinishedFrameBufferUpdate(rfbClient* client);
static char *GetPassword(rfbClient* client);
// 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);
......@@ -59,6 +60,7 @@ public slots:
// manage VNC connection
void open(QString host, int port, const int width, const int height);
void refresh();
void decode();
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[])
format.setMajorVersion(2);
format.setMinorVersion(0);
format.setRenderableType(QSurfaceFormat::OpenGLES);
format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
format.setSwapInterval(0);
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setSwapInterval(1);
#ifdef OGL_DEBUG
format.setOption(QSurfaceFormat::DebugContext, true);
#endif
QSurfaceFormat::setDefaultFormat(format);
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES, true);
QGuiApplication app(argc, argv);
......
......@@ -16,7 +16,6 @@ QVnc::QVnc(QQuickItem *parent) :
m_uploader->moveToThread(m_threads[0]);
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->moveToThread(m_threads[0]);
......@@ -25,7 +24,10 @@ QVnc::QVnc(QQuickItem *parent) :
connect(this, &QVnc::open_connection, m_dispatcher, &Dispatcher::open);
connect(this, &QVnc::terminate_connection, m_dispatcher, &Dispatcher::terminate);
connect(m_dispatcher, &Dispatcher::error, this, &QVnc::dispatch_error);
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;
foreach(JpegDecoder* d, m_decoders) {
......@@ -88,20 +90,23 @@ void QVnc::winChanged(QQuickWindow *window)
{
if(window != NULL) {
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
{
VncRenderer *renderer = new VncRenderer(window(),
m_uploader->vertices(),
m_uploader->indices(),
m_uploader->texture(),
m_uploader->drawCount());
connect(renderer, &VncRenderer::FBOTextureChanged, m_uploader, &Uploader::changeFBOTexture);
connect(renderer, &VncRenderer::finishedRendering, m_uploader, &Uploader::finishedRendering);
return renderer;
return new VncRenderer(window(),
m_uploader->fillBuffer(),
m_uploader->copyBuffer(),
m_uploader->bitmapBuffer(),
m_uploader->texture(),
NULL,
NULL,
NULL,
m_uploader->fillCount(),
m_uploader->copyCount(),
m_uploader->bitmapCount());
}
QString QVnc::host() const
......@@ -200,6 +205,11 @@ void QVnc::hoverMoveEvent(QHoverEvent *event)
// }
}
Uploader *QVnc::uploader() const
{
return m_uploader;
}
void QVnc::keyPressEvent(QKeyEvent *event)
{
}
......
#ifndef VNC_H
#define VNC_H
#define DECODER_COUNT 8
#define DECODER_COUNT 5
// #define OGL_DEBUG
#include <QQuickWindow>
#include <QObject>
......@@ -9,11 +11,14 @@
#include <QThread>
#include <QOffscreenSurface>
#include <QMouseEvent>
#include <QOpenGLDebugLogger>
#include "dispatcher.h"
#include "vncrenderer.h"
#include "uploader.h"
class VncRenderer;
/*!
* \brief The public interface of the VNC functionality
*/
......@@ -30,6 +35,7 @@ public:
Renderer *createRenderer() const;
QString host() const;
int port() const;
Uploader *uploader() const;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
......@@ -49,6 +55,9 @@ private:
int m_port;
ulong m_lastMouseEvent;
bool m_swapped;
bool m_finished;
signals:
void open_connection(const QString host, const int port, const int width, const int height);
void terminate_connection();
......@@ -57,6 +66,8 @@ signals:
void portChanged(int port);
void operate();
void refresh();
public slots:
void open();
void terminate();
......
#include "uploader.h"
Uploader::Uploader(QObject *parent) :
QObject(parent), m_context(this), m_indices(QOpenGLBuffer::IndexBuffer),
m_uploadVertices(new QOpenGLBuffer*), m_renderVertices(new QOpenGLBuffer*),
m_uploadTexture(new GLuint*), m_renderTexture(new GLuint*), m_program(this), m_jpegs(0),
m_atlasX(1), m_atlasY(1), m_atlasRowHeight(0), m_atlasLastWidth(0), m_copyIndex(0)
QObject(parent), m_context(this),
m_uploadFill(new QOpenGLBuffer*), m_renderFill(new QOpenGLBuffer*),
m_uploadCopy(new QOpenGLBuffer*), m_renderCopy(new QOpenGLBuffer*),
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"
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_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()
{
m_program.release();
}
void Uploader::handleDebugMessage(const QOpenGLDebugMessage &debugMessage)
{
qDebug() << debugMessage;
}
void Uploader::createContext(QOpenGLContext *context)
......@@ -23,74 +44,73 @@ void Uploader::createContext(QOpenGLContext *context)
m_context.create();
m_context.makeCurrent(&m_surface);
m_functions = m_context.functions();
m_functions->glEnable(GL_CULL_FACE);
m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, "copy_shader.vsh");
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "copy_shader.fsh");
m_program.bind();
m_program.setUniformValue("texture", 1);
m_program.enableAttributeArray("position");
m_program.enableAttributeArray("texcoord");
m_indices.create();
m_indices.bind();
m_indices.allocate(ind.i, (VERTEX_BUFFER * 6 - 2) * sizeof(unsigned short));
m_copyBuffer.create();
m_copyBuffer.bind();
m_copyBuffer.allocate(COPY_BUFFER * sizeof(Copy));
m_copyPointer = (Copy*) m_copyBuffer.map(QOpenGLBuffer::WriteOnly);
*m_renderVertices = new QOpenGLBuffer;
(*m_renderVertices)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderVertices)->create();
(*m_renderVertices)->bind();
(*m_renderVertices)->allocate(VERTEX_BUFFER * sizeof(Vertex));
*m_uploadVertices = new QOpenGLBuffer;
(*m_uploadVertices)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadVertices)->create();
(*m_uploadVertices)->bind();
(*m_uploadVertices)->allocate(VERTEX_BUFFER * sizeof(Vertex));
m_vertexPointer = (Vertex*) (*m_uploadVertices)->map(QOpenGLBuffer::WriteOnly);
m_vertexIndex = 0;
m_functions->glEnable(GL_TEXTURE_2D);
m_functions->glActiveTexture(GL_TEXTURE0);
m_functions->glGenTextures(2, m_texId);
unsigned char black[] = {0, 0, 0, 0};
#ifdef OGL_DEBUG
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
connect(logger, &QOpenGLDebugLogger::messageLogged, this, &Uploader::handleDebugMessage, Qt::DirectConnection);
logger->initialize();
logger->startLogging();
#endif
m_gl = m_context.functions();
*m_renderFill = new QOpenGLBuffer;
(*m_renderFill)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderFill)->create();
(*m_renderFill)->bind();
(*m_renderFill)->allocate(VERTEX_BUFFER * sizeof(Fill));
*m_uploadFill = new QOpenGLBuffer;
(*m_uploadFill)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadFill)->create();
(*m_uploadFill)->bind();
(*m_uploadFill)->allocate(VERTEX_BUFFER * sizeof(Fill));
*m_renderCopy = new QOpenGLBuffer;
(*m_renderCopy)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderCopy)->create();
(*m_renderCopy)->bind();
(*m_renderCopy)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
*m_uploadCopy = new QOpenGLBuffer;
(*m_uploadCopy)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_uploadCopy)->create();
(*m_uploadCopy)->bind();
(*m_uploadCopy)->allocate(VERTEX_BUFFER * sizeof(Bitmap));
*m_renderBitmap = new QOpenGLBuffer;
(*m_renderBitmap)->setUsagePattern(QOpenGLBuffer::DynamicDraw);
(*m_renderBitmap)->create();
(*m_renderBitmap)->bind();
(*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++) {
m_functions->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_functions->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, black);
m_gl->glBindTexture(GL_TEXTURE_2D, m_texId[i]);
m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
*m_uploadTexture = m_texId;
*m_renderTexture = m_texId + 1;
*m_renderTexture = &m_texId[0];
*m_uploadTexture = &m_texId[1];
m_functions->glGenFramebuffers(1, &m_FBOId);
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);
m_gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
void Uploader::gotFill(const GLushort x, const GLushort y,
const GLushort width, const GLushort height,
const GLubyte red, const GLubyte green, const GLubyte blue)
{
if(m_vertexIndex + 4 < VERTEX_BUFFER) {
// bottom left
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), red, green, blue, 0xFF, 0, 0});
// top left
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, red, green, blue, 0xFF, 0, 0});
// 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});
if(m_fillIndex + 4 < VERTEX_BUFFER) {
m_fillPointer[m_fillIndex++] = Fill({x, (GLushort) (y + height), red, green, blue, 0xFF});
m_fillPointer[m_fillIndex++] = Fill({x, y, red, green, blue, 0xFF});
m_fillPointer[m_fillIndex++] = Fill({(GLushort) (x + width), (GLushort) (y + height), red, green, blue, 0xFF});
m_fillPointer[m_fillIndex++] = Fill({(GLushort) (x + width), y, red, green, blue, 0xFF});
} else {
qDebug() << "Out of memory";
}
......@@ -103,26 +123,20 @@ void Uploader::gotCopy(const GLushort src_x, const GLushort src_y,
if(!refreshAtlas(width, height))
return;
// copy from source
if(m_copyIndex + 4 < COPY_BUFFER) {
m_copyPointer[m_copyIndex++] = Copy({m_atlasX, (GLushort) (m_atlasY + height), src_x, (GLushort) (src_y + height)});
m_copyPointer[m_copyIndex++] = Copy({m_atlasX, m_atlasY, src_x, src_y});
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++] = Copy({(GLushort) (m_atlasX + width), m_atlasY, (GLushort) (src_x + width), src_y});
if(m_copyIndex + 4 < VERTEX_BUFFER) {
m_copyPointer[m_copyIndex++] = Bitmap({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++] = Bitmap({(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});
} else {
qDebug() << "Out of memory";
}
// copy to destination
if(m_vertexIndex + 4 < VERTEX_BUFFER) {
// bottom left
m_vertexPointer[m_vertexIndex++] = Vertex({dest_x, (GLushort) (dest_y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)});
// top left
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});
if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, (GLushort) (dest_y + height), m_atlasX, (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, dest_y, m_atlasX, m_atlasY});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), (GLushort) (dest_y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), dest_y, (GLushort) (m_atlasX + width), m_atlasY});
} else {
qDebug() << "Out of memory";
}
......@@ -135,17 +149,13 @@ void Uploader::gotBitmap(const unsigned char *image,
if(!refreshAtlas(width, height))
return;
m_functions->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
if(m_vertexIndex + 4 < VERTEX_BUFFER) {
// bottom left
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)});
// top left
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, 0, 0, 0, 0, m_atlasX, 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});
m_gl->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, (GLushort) (y + height), m_atlasX, (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, y, m_atlasX, m_atlasY});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), (GLushort) (y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), y, (GLushort) (m_atlasX + width), m_atlasY});
} else {
qDebug() << "Out of memory";
}
......@@ -165,61 +175,38 @@ void Uploader::finishedJpeg(const unsigned char *image,
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;
if(m_vertexIndex + 4 < VERTEX_BUFFER) {
// bottom left
m_vertexPointer[m_vertexIndex++] = Vertex({x, (GLushort) (y + height), 0, 0, 0, 0, m_atlasX, (GLushort) (m_atlasY + height)});
// top left
m_vertexPointer[m_vertexIndex++] = Vertex({x, y, 0, 0, 0, 0, m_atlasX, 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});
if(m_bitmapIndex + 4 < VERTEX_BUFFER) {
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, (GLushort) (y + height), m_atlasX, (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, y, m_atlasX, m_atlasY});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), (GLushort) (y + height), (GLushort) (m_atlasX + width), (GLushort) (m_atlasY + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), y, (GLushort) (m_atlasX + width), m_atlasY});
} else {
qDebug() << "Out of memory";
}
if(m_jpegs == 0 && m_finished && m_swapped) {
startRendering();
}
}
// The previous frame finished rendering
void Uploader::finishedRendering()
{
m_rendered = true;
}
if(m_jpegs == 0)
qDebug() << "jpeg" << elapsed.elapsed();
void Uploader::frameSwapped()
{
if(m_rendered) {
m_swapped = true;
if(m_finished) {
copyRectangles();
if(m_jpegs == 0) {
startRendering();
}
}
if(m_jpegs == 0 && m_finished) {
startRendering();
}
}
void Uploader::finishedUpdate()
{
m_finished = true;
if(m_swapped) {
copyRectangles();
if(m_jpegs == 0)
startRendering();
}
if(m_jpegs == 0)
startRendering();
}
bool Uploader::refreshAtlas(const int width, const int height)
{
if(m_atlasX + m_atlasLastWidth + width <= TEXTURE_WIDTH) {
if(m_atlasY + height > TEXTURE_HEIGHT) {
qDebug() << "Out of memory";
qDebug() << "Atlas out of memory" << m_atlasX << m_atlasY << width << height;
return false;
}
......@@ -230,7 +217,7 @@ bool Uploader::refreshAtlas(const int width, const int height)
m_atlasRowHeight = height;
} else {
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;
}
......@@ -242,99 +229,97 @@ bool Uploader::refreshAtlas(const int width, const int height)
return true;
}
void Uploader::startRendering()
void Uploader::startDecoding()
{
if(m_vertexIndex > 0) {
(*m_uploadVertices)->unmap();
m_functions->glFlush();
std::swap(*m_uploadVertices, *m_renderVertices);
(*m_uploadVertices)->bind();
m_vertexPointer = (Vertex*) (*m_uploadVertices)->map(QOpenGLBuffer::WriteOnly);
(*m_uploadFill)->bind();
m_fillPointer = (Fill*) (*m_uploadFill)->map(QOpenGLBuffer::WriteOnly);
(*m_uploadCopy)->bind();
m_copyPointer = (Bitmap*) (*m_uploadCopy)->map(QOpenGLBuffer::WriteOnly);
(*m_uploadBitmap)->bind();
m_bitmapPointer = (Bitmap*) (*m_uploadBitmap)->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);
m_functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, **m_uploadTexture, 0);
m_functions->glBindTexture(GL_TEXTURE_2D, **m_uploadTexture);
void Uploader::startRendering()
{
(*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;
m_atlasY = 1;
m_atlasRowHeight = 0;
m_atlasLastWidth = 0;
qDebug() << "flush" << elapsed.elapsed();
m_rendered = false;
m_swapped = false;
m_finished = false;
} else {
m_rendered = true;
}
emit uploadFinished();
}
void Uploader::copyRectangles()
void Uploader::swapBuffers()
{
if(m_copyIndex > 0) {
m_functions->glActiveTexture(GL_TEXTURE1);
m_copyBuffer.bind();
m_copyBuffer.unmap();
m_functions->glVertexAttribPointer(m_program.attributeLocation("position"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Copy),
(void*) 0);
m_functions->glVertexAttribPointer(m_program.attributeLocation("texcoord"),
2,
GL_UNSIGNED_SHORT,
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;
if(m_swap) {
std::swap(*m_uploadFill, *m_renderFill);
std::swap(*m_uploadCopy, *m_renderCopy);
std::swap(*m_uploadBitmap, *m_renderBitmap);
std::swap(*m_uploadTexture, *m_renderTexture);
*m_fillCount = m_fillIndex ? (m_fillIndex / 4) * 6 - 2 : 0;
*m_copyCount = m_copyIndex ? (m_copyIndex / 4) * 6 - 2 : 0;
*m_bitmapCount = m_bitmapIndex ? (m_bitmapIndex / 4) * 6 - 2 : 0;
m_swap = false;
qDebug() << "swap" << elapsed.elapsed();
emit buffersSwapped();
}
}
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);
m_functions->glBindTexture(GL_TEXTURE_2D, m_FBOTexture);
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->glActiveTexture(GL_TEXTURE0);
unsigned int *Uploader::copyCount() const
{
return m_copyCount;
}
m_program.setUniformValue("texortho", ortho);
unsigned int *Uploader::bitmapCount() const
{
return m_bitmapCount;
}
......@@ -16,64 +16,42 @@
#ifndef UPLOADER_H
#define UPLOADER_H
#define TEXTURE_WIDTH 2048
#define TEXTURE_HEIGHT 2048
#define COPY_BUFFER 1024
#define TEXTURE_WIDTH 4096
#define TEXTURE_HEIGHT 4096
#define VERTEX_BUFFER 1024
// #define OGL_DEBUG
#include <utility>
#include <QObject>
#include <QQuickWindow>
#include <QDebug>
#include <QVector>
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLFramebufferObject>
#include <QSharedPointer>
#include <QtMath>
#include <QTime>
#include <QOpenGLDebugLogger>
extern QTime elapsed;
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;
struct Vertex
struct Bitmap
{
GLushort x;
GLushort y;
GLubyte red;
GLubyte green;
GLubyte blue;
GLubyte alpha;
GLushort texX;
GLushort texY;
};
struct Copy
struct Fill
{
GLushort x;
GLushort y;
GLushort texX;
GLushort texY;
GLubyte red;
GLubyte green;
GLubyte blue;
GLubyte alpha;
};
/*!
......@@ -88,10 +66,14 @@ public:
Uploader(QObject *parent = Q_NULLPTR);
~Uploader();
QOpenGLBuffer **vertices() const;
QOpenGLBuffer indices() 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
void gotFill(const GLushort x, const GLushort y,
......@@ -105,69 +87,56 @@ public:
const GLushort width, const GLushort height);
void gotJpeg();
void finishedUpdate();
void startDecoding();
private:
QOffscreenSurface m_surface;
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_renderVertices;
Vertex *m_vertexPointer;
size_t m_vertexIndex;
QOpenGLBuffer **m_uploadBitmap;
QOpenGLBuffer **m_renderBitmap;
Bitmap *m_bitmapPointer;
size_t m_bitmapIndex;
unsigned int *m_bitmapCount;
GLuint m_FBOId;
GLuint m_texId[2];
GLuint **m_uploadTexture;
GLuint **m_renderTexture;
unsigned int *m_drawCount;
QOpenGLShaderProgram m_program;
GLuint m_FBOTexture;
int m_jpegs;
// Got a FinishedUpdate event from libvnc
bool m_finished;
// The rendering thread finished rendering the previous frame
bool m_rendered;
// Framebuffer swapped
bool m_swapped;
bool m_swap;
unsigned short m_atlasX;
unsigned short m_atlasY;
unsigned short m_atlasRowHeight;
unsigned short m_atlasLastWidth;
QOpenGLBuffer m_copyBuffer;
Copy *m_copyPointer;
size_t m_copyIndex;
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();
// Called when:
// - got a Finished update event from libvnc
// - and the rendering thread swapped buffers
void copyRectangles();
signals:
// Emit from startRendering only!
void uploadFinished();
void buffersSwapped();
public slots:
void changeFBOTexture(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void createContext(QOpenGLContext *context);
void finishedJpeg(const unsigned char *image,
const GLushort x, const GLushort y,
const GLushort width, const GLushort height);
void finishedRendering();
void frameSwapped();
private slots:
void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
};
#endif // UPLOADER_H
......@@ -3,92 +3,210 @@
#include "uploader.h"
VncRenderer::VncRenderer(QQuickWindow *window,
QOpenGLBuffer **vertices,
QOpenGLBuffer indices,
GLuint **texture,
unsigned int *drawCount,
QObject *parent) :
QObject(parent), m_window(window), m_vertices(vertices), m_indices(indices), m_texture(texture), m_drawCount(drawCount), m_rendered(false)
QOpenGLBuffer **fillBuffer,
QOpenGLBuffer **copyBuffer,
QOpenGLBuffer **bitmapBuffer,
GLuint **rgbTexture,
GLuint **yTexture,
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");
m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, "draw_shader.fsh");
m_program.bind();
m_program.setUniformValue("texture", 0);
QMatrix4x4 ortho;
ortho.ortho(QRect(QPoint(0, 0), QSize(2048, 2048)));
m_program.setUniformValue("texortho", ortho);
m_program.release();
m_functions = QOpenGLContext::currentContext()->functions();
m_functions->glActiveTexture(GL_TEXTURE0);
#ifdef OGL_DEBUG
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
connect(logger, &QOpenGLDebugLogger::messageLogged, this, &VncRenderer::handleDebugMessage, Qt::DirectConnection);
logger->initialize();
logger->startLogging();
#endif
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_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()
{
if(*m_drawCount > 0) {
static QTime frameTime;
qDebug() << qRound(1000.0 / frameTime.restart());
m_program.bind();
(*m_vertices)->bind();
m_indices.bind();
m_functions->glVertexAttribPointer(m_program.attributeLocation("position"),
frameCount++;
if(frameTime.elapsed() > 1000) {
// qDebug() << frameCount;
frameCount = 0;
frameTime.restart();
}
/* 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,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Vertex),
sizeof(Bitmap),
(void*) 0);
m_functions->glVertexAttribPointer(m_program.attributeLocation("color"),
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
sizeof(Vertex),
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("texcoord"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Bitmap),
(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,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Vertex),
(void*) (2 * sizeof(GLushort) + 4 * sizeof(GLubyte)));
m_program.enableAttributeArray("position");
m_program.enableAttributeArray("color");
m_program.enableAttributeArray("texcoord");
m_functions->glBindTexture(GL_TEXTURE_2D, **m_texture);
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->glDrawElements(GL_TRIANGLE_STRIP, *m_drawCount, GL_UNSIGNED_SHORT, (void*) 0);
*m_drawCount = 0;
m_window->resetOpenGLState();
emit finishedRendering();
sizeof(Bitmap),
(void*) 0);
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("texcoord"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Bitmap),
(void*) (2 * sizeof(GLushort)));
m_bitmapProgram.setUniformValue("texture", 1);
m_bitmapProgram.setUniformValue("ortho", m_bitmapOrtho);
m_bitmapProgram.setUniformValue("texortho", m_bitmapTexortho);
m_gl->glDrawElements(GL_TRIANGLE_STRIP, *m_bitmapCount, GL_UNSIGNED_SHORT, (void*) 0);
}
*m_fillCount = 0;
*m_copyCount = 0;
*m_bitmapCount = 0;
update();
m_window->resetOpenGLState();
}
QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size)
{
QMatrix4x4 ortho;
ortho.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
m_copyTexortho.ortho(QRect(QPoint(-1 * size.width(), size.height()), QSize(2 * size.width(), -2 * size.height())));
m_bitmapOrtho.ortho(QRect(QPoint(0, size.height()), QSize(size.width(), -1 * size.height())));
QOpenGLFramebufferObject *framebufferObject = new QOpenGLFramebufferObject(size);
emit FBOTextureChanged(framebufferObject->texture(), ortho);
return framebufferObject;
m_framebufferObject = new QOpenGLFramebufferObject(size);
return m_framebufferObject;
}
......@@ -11,32 +11,78 @@
#include <QOpenGLBuffer>
#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
{
Q_OBJECT
public:
VncRenderer(QQuickWindow *window,
QOpenGLBuffer **vertices,
QOpenGLBuffer indices,
GLuint **textures,
unsigned int *drawCount,
QObject *parent = 0);
QOpenGLBuffer **fillBuffer,
QOpenGLBuffer **copyBuffer,
QOpenGLBuffer **bitmapBuffer,
GLuint **rgbTexture,
GLuint **yTexture,
GLuint **cbTexture,
GLuint **crTexture,
unsigned int *fillCount,
unsigned int *copyCount,
unsigned int *bitmapCount,
QObject *parent = nullptr);
protected:
void render() override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
private:
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;
GLuint **m_texture;
unsigned int *m_drawCount;
QVector3D m_colorMax;
QOpenGLShaderProgram m_program;
QOpenGLFunctions *m_functions;
bool m_rendered;
signals:
void FBOTextureChanged(const unsigned int FBOTexture, const QMatrix4x4 &ortho);
void finishedRendering();
QOpenGLShaderProgram m_fillProgram;
QOpenGLShaderProgram m_bitmapProgram;
QOpenGLShaderProgram m_ycbcrProgram;
GLuint m_textureTarget;
QOpenGLFunctions *m_gl;
QOpenGLFramebufferObject *m_framebufferObject;
int frameCount;
QTime frameTime;
private slots:
void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
};
#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