Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Ludmány Balázs
/
thin-client
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
36bd0aa2
authored
Jul 19, 2016
by
Ludmány Balázs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor
parent
14d916c7
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
664 additions
and
540 deletions
+664
-540
ThinClient.pro
+2
-3
ThinClient.pro.user
+8
-6
concurrentqueue.h
+54
-0
dispatcher.cpp
+76
-114
dispatcher.h
+17
-20
draw_shader.fsh
+3
-3
draw_shader.vsh
+5
-4
fill_shader.fsh
+0
-5
fill_shader.vsh
+0
-10
jpegdecoder.cpp
+11
-5
jpegdecoder.h
+28
-13
main.qml
+0
-26
qvnc.cpp
+133
-28
qvnc.h
+23
-9
uploader.cpp
+220
-199
uploader.h
+32
-32
vncrenderer.cpp
+41
-44
vncrenderer.h
+11
-19
No files found.
ThinClient.pro
View file @
36bd0aa2
...
...
@@ -29,12 +29,11 @@ HEADERS += \
jpegdecoder
.
h
\
qvnc
.
h
\
uploader
.
h
\
dispatcher
.
h
dispatcher
.
h
\
concurrentqueue
.
h
DISTFILES
+=
\
draw_shader
.
fsh
\
draw_shader
.
vsh
\
fill_shader
.
vsh
\
fill_shader
.
fsh
\
copy_shader
.
vsh
\
copy_shader
.
fsh
ThinClient.pro.user
View file @
36bd0aa2
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2016-07-1
1T16:48
:08. -->
<!-- Written by QtCreator 3.5.1, 2016-07-1
9T13:32
:08. -->
<qtcreator>
<data>
<variable>
EnvironmentId
</variable>
...
...
@@ -61,7 +61,7 @@
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.DefaultDisplayName"
>
Desktop
</value>
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.DisplayName"
>
Desktop
</value>
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.Id"
>
{9fe100e5-65f5-4993-908d-e24f092a1cff}
</value>
<value
type=
"int"
key=
"ProjectExplorer.Target.ActiveBuildConfiguration"
>
0
</value>
<value
type=
"int"
key=
"ProjectExplorer.Target.ActiveBuildConfiguration"
>
1
</value>
<value
type=
"int"
key=
"ProjectExplorer.Target.ActiveDeployConfiguration"
>
0
</value>
<value
type=
"int"
key=
"ProjectExplorer.Target.ActiveRunConfiguration"
>
0
</value>
<valuemap
type=
"QVariantMap"
key=
"ProjectExplorer.Target.BuildConfiguration.0"
>
...
...
@@ -237,7 +237,9 @@
<value
type=
"int"
>
14
</value>
</valuelist>
<value
type=
"int"
key=
"PE.EnvironmentAspect.Base"
>
2
</value>
<valuelist
type=
"QVariantList"
key=
"PE.EnvironmentAspect.Changes"
/>
<valuelist
type=
"QVariantList"
key=
"PE.EnvironmentAspect.Changes"
>
<value
type=
"QString"
>
QML_SHOW_FRAMERATE=1
</value>
</valuelist>
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.DefaultDisplayName"
>
ThinClient
</value>
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.DisplayName"
></value>
<value
type=
"QString"
key=
"ProjectExplorer.ProjectConfiguration.Id"
>
Qt4ProjectManager.Qt4RunConfiguration:/media/ldmnyblzs/files/Projects/ThinClient/ThinClient.pro
</value>
...
...
@@ -247,11 +249,11 @@
<value
type=
"bool"
key=
"Qt4ProjectManager.Qt4RunConfiguration.UseTerminal"
>
false
</value>
<value
type=
"QString"
key=
"Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"
></value>
<value
type=
"uint"
key=
"RunConfiguration.QmlDebugServerPort"
>
3768
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseCppDebugger"
>
fals
e
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseCppDebuggerAuto"
>
tru
e
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseCppDebugger"
>
tru
e
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseCppDebuggerAuto"
>
fals
e
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseMultiProcess"
>
false
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseQmlDebugger"
>
false
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseQmlDebuggerAuto"
>
tru
e
</value>
<value
type=
"bool"
key=
"RunConfiguration.UseQmlDebuggerAuto"
>
fals
e
</value>
</valuemap>
<value
type=
"int"
key=
"ProjectExplorer.Target.RunConfigurationCount"
>
1
</value>
</valuemap>
...
...
concurrentqueue.h
0 → 100644
View file @
36bd0aa2
#ifndef CONCURRENTQUEUE_H
#define CONCURRENTQUEUE_H
#include <QSemaphore>
template
<
class
T
,
const
unsigned
short
S
>
class
ConcurrentQueue
{
public
:
ConcurrentQueue
();
void
enqueue
(
const
T
&
t
);
T
dequeue
();
bool
isEmpty
()
const
;
private
:
T
m_buffer
[
S
];
unsigned
short
m_next
;
unsigned
short
m_first
;
QSemaphore
m_free
;
QSemaphore
m_used
;
};
template
<
class
T
,
const
unsigned
short
S
>
ConcurrentQueue
<
T
,
S
>::
ConcurrentQueue
()
:
m_next
(
0
),
m_first
(
0
),
m_free
(
S
),
m_used
(
0
)
{
}
template
<
class
T
,
const
unsigned
short
S
>
void
ConcurrentQueue
<
T
,
S
>::
enqueue
(
const
T
&
t
)
{
m_free
.
acquire
();
m_buffer
[
m_next
]
=
t
;
m_next
=
(
m_next
+
1
)
%
S
;
m_used
.
release
();
}
template
<
class
T
,
const
unsigned
short
S
>
T
ConcurrentQueue
<
T
,
S
>::
dequeue
()
{
T
temp
;
m_used
.
acquire
();
temp
=
m_buffer
[
m_first
];
m_first
=
(
m_first
+
1
)
%
S
;
m_free
.
release
();
return
temp
;
}
template
<
class
T
,
const
unsigned
short
S
>
bool
ConcurrentQueue
<
T
,
S
>::
isEmpty
()
const
{
return
(
m_first
==
m_next
);
}
#endif // CONCURRENTQUEUE_H
dispatcher.cpp
View file @
36bd0aa2
#include "dispatcher.h"
Dispatcher
::
Dispatcher
(
QObject
*
parent
)
:
QObject
(
parent
),
m_uploader
(
this
)
Dispatcher
::
Dispatcher
(
Uploader
*
uploader
,
QObject
*
parent
)
:
QObject
(
parent
),
m_client
(
NULL
),
m_uploader
(
uploader
)
{
}
...
...
@@ -14,7 +15,7 @@ rfbBool Dispatcher::MallocFrameBuffer(rfbClient *client)
void
Dispatcher
::
GotCopyRect
(
rfbClient
*
client
,
int
src_x
,
int
src_y
,
int
w
,
int
h
,
int
dest_x
,
int
dest_y
)
{
Dispatcher
*
dispatcher
=
(
Dispatcher
*
)
rfbClientGetClientData
(
client
,
0
);
dispatcher
->
uploader
()
.
gotCopyRect
(
src_x
,
src_y
,
w
,
h
,
dest_x
,
dest_y
);
dispatcher
->
uploader
()
->
gotCopy
(
src_x
,
src_y
,
w
,
h
,
dest_x
,
dest_y
);
}
void
Dispatcher
::
GotFillRect
(
rfbClient
*
client
,
int
x
,
int
y
,
int
w
,
int
h
,
uint32_t
colour
)
...
...
@@ -23,138 +24,68 @@ void Dispatcher::GotFillRect(rfbClient *client, int x, int y, int w, int h, uint
int
red
=
(
colour
>>
client
->
format
.
redShift
)
&
client
->
format
.
redMax
;
int
green
=
(
colour
>>
client
->
format
.
greenShift
)
&
client
->
format
.
greenMax
;
int
blue
=
(
colour
>>
client
->
format
.
blueShift
)
&
client
->
format
.
blueMax
;
dispatcher
->
uploader
()
.
gotFillRect
(
x
,
y
,
w
,
h
,
red
,
green
,
blue
);
dispatcher
->
uploader
()
->
gotFill
(
x
,
y
,
w
,
h
,
red
,
green
,
blue
);
}
void
Dispatcher
::
GotBitmap
(
rfbClient
*
client
,
const
uint8_t
*
buffer
,
int
x
,
int
y
,
int
w
,
int
h
)
{
QImage
img
;
Dispatcher
*
dispatcher
=
(
Dispatcher
*
)
rfbClientGetClientData
(
client
,
0
);
switch
(
dispatcher
->
bitsPerPixel
())
{
case
8
:
img
=
QImage
(
buffer
,
w
,
h
,
QImage
::
Format_Grayscale8
);
break
;
case
16
:
img
=
QImage
(
buffer
,
w
,
h
,
QImage
::
Format_RGB16
);
break
;
case
32
:
img
=
QImage
(
buffer
,
w
,
h
,
QImage
::
Format_RGBX8888
);
break
;
default
:
emit
dispatcher
->
error
();
return
;
}
// We have to make a deep copy because libvnc might free the buffer as soon as this function returns
dispatcher
->
uploader
()
.
gotBitmap
(
img
.
copy
(),
x
,
y
,
w
,
h
);
dispatcher
->
uploader
()
->
gotBitmap
(
QByteArray
((
const
char
*
)
buffer
,
w
*
h
*
(
dispatcher
->
bitsPerPixel
()
/
8
)),
x
,
y
,
w
,
h
,
GL_BGRA_EXT
,
GL_UNSIGNED_BYTE
);
}
rfbBool
Dispatcher
::
GotJpeg
(
rfbClient
*
client
,
const
uint8_t
*
buffer
,
int
length
,
int
x
,
int
y
,
int
w
,
int
h
)
{
Dispatcher
*
dispatcher
=
static_cast
<
Dispatcher
*>
(
rfbClientGetClientData
(
client
,
0
));
QByteArray
jpeg
;
jpeg
.
setRawData
((
const
char
*
)
buffer
,
length
);
JpegDecoder
*
decoder
=
new
JpegDecoder
(
jpeg
,
x
,
y
,
w
,
h
);
dispatcher
->
incrementDecoderCount
();
connect
(
decoder
,
&
JpegDecoder
::
finished
,
dispatcher
,
&
Dispatcher
::
decodingFinished
,
Qt
::
QueuedConnection
);
QThreadPool
::
globalInstance
()
->
start
(
decoder
);
Jpeg
*
jpeg
=
new
Jpeg
(
QByteArray
::
fromRawData
((
const
char
*
)
buffer
,
length
),
dispatcher
->
uploader
()
->
gotJpeg
(
x
,
y
,
w
,
h
));
dispatcher
->
queue
()
->
enqueue
(
jpeg
);
return
TRUE
;
}
void
Dispatcher
::
FinishedFrameBufferUpdate
(
rfbClient
*
client
)
{
Dispatcher
*
dispatcher
=
(
Dispatcher
*
)
rfbClientGetClientData
(
client
,
0
);
dispatcher
->
setFinished
(
true
);
if
(
dispatcher
->
decoderCount
()
==
0
)
{
dispatcher
->
uploader
().
finishedUpdate
();
emit
dispatcher
->
updateFramebuffer
();
}
dispatcher
->
uploader
()
->
finishedUpdate
();
}
void
Dispatcher
::
setMouse
(
int
x
,
int
y
,
bool
left
,
bool
middle
,
bool
right
)
bool
Dispatcher
::
mouseEvent
(
const
int
x
,
const
int
y
,
const
bool
left
,
const
bool
middle
,
const
bool
right
,
const
bool
up
,
const
bool
down
)
{
if
(
m_client
==
NULL
)
return
;
return
false
;
int
buttonMask
=
0
;
if
(
left
)
buttonMask
|=
rfbButton1Mask
;
if
(
middle
)
buttonMask
|=
rfbButton2Mask
;
if
(
right
)
buttonMask
|=
rfbButton3Mask
;
if
(
right
)
buttonMask
|=
rfbButton2Mask
;
if
(
middle
)
buttonMask
|=
rfbButton3Mask
;
if
(
up
)
buttonMask
|=
rfbButton4Mask
;
if
(
down
)
buttonMask
|=
rfbButton5Mask
;
SendPointerEvent
(
m_client
,
x
,
y
,
buttonMask
);
}
unsigned
int
Dispatcher
::
decoderCount
()
const
{
return
m_decoderCount
;
}
unsigned
int
Dispatcher
::
incrementDecoderCount
()
{
return
++
m_decoderCount
;
}
unsigned
int
Dispatcher
::
decrementDecoderCount
()
{
return
--
m_decoderCount
;
return
true
;
}
int
Dispatcher
::
bitsPerPixel
()
{
return
m_client
->
format
.
bitsPerPixel
;
}
Uploader
&
Dispatcher
::
uploader
()
{
return
m_uploader
;
}
void
Dispatcher
::
setFinished
(
bool
finished
)
{
m_finished
=
finished
;
}
bool
Dispatcher
::
finished
()
const
{
return
m_finished
;
}
unsigned
int
Dispatcher
::
fill_count
()
{
if
(
m_finished
&&
m_decoderCount
==
0
)
return
m_uploader
.
fill_count
();
else
return
0
;
}
unsigned
int
Dispatcher
::
copy_count
()
{
if
(
m_finished
&&
m_decoderCount
==
0
)
return
m_uploader
.
copy_count
();
else
return
0
;
}
unsigned
int
Dispatcher
::
draw_count
()
{
if
(
m_finished
&&
m_decoderCount
==
0
)
return
m_uploader
.
draw_count
();
else
if
(
m_client
==
NULL
)
return
0
;
return
m_client
->
format
.
bitsPerPixel
;
}
QVector3D
Dispatcher
::
colorMax
()
const
{
if
(
m_client
==
NULL
)
return
QVector3D
();
return
QVector3D
(
m_client
->
format
.
redMax
,
m_client
->
format
.
greenMax
,
m_client
->
format
.
blueMax
);
}
void
Dispatcher
::
create_context
(
QOpenGLContext
*
context
)
ConcurrentQueue
<
Jpeg
*
,
64u
>
*
Dispatcher
::
queue
(
)
{
m_uploader
.
create_context
(
context
);
return
&
m_queue
;
}
Uploader
*
Dispatcher
::
uploader
()
const
{
return
m_uploader
;
}
void
Dispatcher
::
open
(
QString
host
,
int
port
)
...
...
@@ -174,13 +105,51 @@ void Dispatcher::open(QString host, int port)
m_client
->
FinishedFrameBufferUpdate
=
Dispatcher
::
FinishedFrameBufferUpdate
;
m_client
->
appData
.
useRemoteCursor
=
TRUE
;
// Set the format requested by the user
m_client
->
width
=
1024
;
m_client
->
height
=
768
;
m_client
->
appData
.
compressLevel
=
0
;
m_client
->
appData
.
qualityLevel
=
0
;
#ifdef __BIG_ENDIAN__
m_client
->
format
.
bigEndian
=
TRUE
;
#else
m_client
->
format
.
bigEndian
=
FALSE
;
#endif
// The Raspberry Pi supports 8 bit paletted images and RGB422 too but only through extensions
m_client
->
format
.
trueColour
=
TRUE
;
m_client
->
format
.
bitsPerPixel
=
32
;
rfbClientSetClientData
(
m_client
,
0
,
this
);
if
(
!
rfbInitClient
(
m_client
,
NULL
,
NULL
))
{
emit
error
();
return
;
}
emit
colorMaxChanged
(
colorMax
());
// Stick to the format sent by the server if we can render it easily, set a new one otherwise
//
// Formats OpenGL ES 2.0 can (should be able to) handle:
// Internal Format External Format Type Bytes per Pixel
// --------------- --------------- ---- ---------------
// RGBA RGBA UNSIGNED_BYTE 4
// RGB RGB UNSIGNED_BYTE 3
// RGBA RGBA UNSIGNED_SHORT_4_4_4_4 2
// RGBA RGBA UNSIGNED_SHORT_5_5_5_1 2
// RGB RGB UNSIGNED_SHORT_5_6_5 2
// The Raspberry Pi supports BGRA too but only through extensions
//
// JPEG is RGB UNSIGNED_BYTE
// Supported raw formats:
// 32 bit: RGB888
// 16 bit: RGB444, RGB555, RGB565
/*int message = WaitForMessage(m_client, 1000);
if(message < 0) {
terminate();
emit error();
return;
}*/
refresh
();
}
void
Dispatcher
::
refresh
()
...
...
@@ -188,25 +157,27 @@ void Dispatcher::refresh()
if
(
m_client
==
NULL
)
return
;
setFinished
(
false
);
m_uploader
.
startedUpdate
();
m_uploader
->
cleanup
(
);
int
message
=
0
;
if
(
!
HandleRFBServerMessage
(
m_client
))
{
terminate
();
emit
error
();
return
;
}
// Don't block uploading!
// Wait until we get something
while
(
message
==
0
)
{
message
=
WaitForMessage
(
m_client
,
10000
);
QCoreApplication
::
processEvents
();
message
=
WaitForMessage
(
m_client
,
1000
);
if
(
message
<
0
)
{
terminate
();
emit
error
();
return
;
}
if
(
message
)
{
if
(
!
HandleRFBServerMessage
(
m_client
))
{
terminate
();
emit
error
();
return
;
}
}
}
}
...
...
@@ -217,12 +188,3 @@ void Dispatcher::terminate()
rfbClientCleanup
(
m_client
);
}
void
Dispatcher
::
decodingFinished
(
const
QImage
&
bitmap
,
const
int
x
,
const
int
y
,
const
int
w
,
const
int
h
)
{
m_uploader
.
gotBitmap
(
bitmap
,
x
,
y
,
w
,
h
);
if
(
m_finished
&&
decrementDecoderCount
()
==
0
)
{
m_uploader
.
finishedUpdate
();
emit
updateFramebuffer
();
}
}
dispatcher.h
View file @
36bd0aa2
...
...
@@ -21,7 +21,7 @@ class Dispatcher : public QObject
Q_OBJECT
public
:
Dispatcher
(
QObject
*
parent
=
0
);
Dispatcher
(
Uploader
*
uploader
,
QObject
*
parent
=
Q_NULLPTR
);
// libvnc hooks
static
rfbBool
MallocFrameBuffer
(
rfbClient
*
client
);
...
...
@@ -31,37 +31,34 @@ public:
static
rfbBool
GotJpeg
(
rfbClient
*
client
,
const
uint8_t
*
buffer
,
int
length
,
int
x
,
int
y
,
int
w
,
int
h
);
static
void
FinishedFrameBufferUpdate
(
rfbClient
*
client
);
void
setMouse
(
int
x
,
int
y
,
bool
left
,
bool
middle
,
bool
right
);
// input events
bool
mouseEvent
(
const
int
x
,
const
int
y
,
const
bool
left
,
const
bool
middle
,
const
bool
right
,
const
bool
up
,
const
bool
down
);
unsigned
int
decoderCount
()
const
;
unsigned
int
incrementDecoderCount
();
unsigned
int
decrementDecoderCount
();
// parameters of the VNC connection
int
bitsPerPixel
();
Uploader
&
uploader
();
void
setFinished
(
bool
finished
);
bool
finished
()
const
;
unsigned
int
fill_count
();
unsigned
int
copy_count
();
unsigned
int
draw_count
();
QVector3D
colorMax
()
const
;
// getters
ConcurrentQueue
<
Jpeg
*
,
64
>*
queue
();
Uploader
*
uploader
()
const
;
private
:
rfbClient
*
m_client
;
unsigned
int
m_decoderCount
;
bool
m_finished
;
// TODO: move this to QVnc
Uploader
m_uploader
;
Uploader
*
m_uploader
;
ConcurrentQueue
<
Jpeg
*
,
64
>
m_queue
;
signals
:
// libvnc events
void
gotCopy
(
const
int
src_x
,
const
int
src_y
,
const
int
width
,
const
int
height
,
const
int
dest_x
,
const
int
dest_y
);
void
gotFill
(
const
int
x
,
const
int
y
,
const
int
width
,
const
int
height
,
const
float
red
,
const
float
green
,
const
float
blue
);
void
gotBitmap
(
const
QImage
&
image
,
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
);
void
finishedUpdate
();
void
resizeFramebuffer
(
const
QSize
&
size
);
void
updateFramebuffer
(
);
void
colorMaxChanged
(
const
QVector3D
&
colorMax
);
void
error
();
public
slots
:
void
create_context
(
QOpenGLContext
*
context
);
// manage VNC connection
void
open
(
QString
host
,
int
port
);
void
refresh
();
void
terminate
();
void
decodingFinished
(
const
QImage
&
bitmap
,
const
int
x
,
const
int
y
,
const
int
w
,
const
int
h
);
};
#endif // RFBDISPATCH_H
draw_shader.fsh
View file @
36bd0aa2
uniform sampler2D texture;
varying
low
p vec2 vartexcoord;
varying
low
p vec3 varcolor;
varying
high
p vec2 vartexcoord;
varying
high
p vec3 varcolor;
void main(void)
{
gl_FragColor = vec4(texture2D(texture, vartexcoord).
rgb
+ varcolor, 1.0);
gl_FragColor = vec4(texture2D(texture, vartexcoord).
bgr
+ varcolor, 1.0);
}
draw_shader.vsh
View file @
36bd0aa2
uniform highp mat4 ortho;
uniform lowp vec3 colormax;
attribute highp vec2 position;
attribute
low
p vec3 color;
attribute
low
p vec2 texcoord;
varying
low
p vec3 varcolor;
varying
low
p vec2 vartexcoord;
attribute
high
p vec3 color;
attribute
high
p vec2 texcoord;
varying
high
p vec3 varcolor;
varying
high
p vec2 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color / colormax;
// varcolor = vec3(1.0, 1.0, 0.0);
vartexcoord = texcoord;
}
fill_shader.fsh
deleted
100644 → 0
View file @
14d916c7
varying highp vec3 varcolor;
void main(void)
{
gl_FragColor = vec4(varcolor, 1.0);
}
fill_shader.vsh
deleted
100644 → 0
View file @
14d916c7
uniform highp mat4 ortho;
uniform highp vec3 colormax;
attribute highp vec2 position;
attribute highp vec3 color;
varying highp vec3 varcolor;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color / colormax;
}
jpegdecoder.cpp
View file @
36bd0aa2
#include "jpegdecoder.h"
JpegDecoder
::
JpegDecoder
(
const
QByteArray
&
jpeg
,
const
int
x
,
const
int
y
,
const
int
w
,
const
int
h
,
QObject
*
parent
)
:
QObject
(
parent
),
QRunnable
(),
m_jpeg
(
jpeg
),
m_x
(
x
),
m_y
(
y
),
m_w
(
w
),
m_h
(
h
)
JpegDecoder
::
JpegDecoder
(
ConcurrentQueue
<
Jpeg
*
,
64u
>
*
queue
,
QObject
*
parent
)
:
QObject
(
parent
),
m_queue
(
queue
)
{
}
void
JpegDecoder
::
run
()
void
JpegDecoder
::
operate
()
{
m_image
.
loadFromData
(
m_jpeg
,
"JPG"
);
emit
finished
(
m_image
,
m_x
,
m_y
,
m_w
,
m_h
);
Jpeg
*
jpeg
;
forever
{
jpeg
=
m_queue
->
dequeue
();
QImage
image
;
image
.
loadFromData
(
jpeg
->
data
,
"JPEG"
);
emit
finished
(
image
,
image
.
width
(),
image
.
height
(),
jpeg
->
index
);
delete
jpeg
;
}
}
jpegdecoder.h
View file @
36bd0aa2
...
...
@@ -3,30 +3,45 @@
#include <QObject>
#include <QByteArray>
#include <QRunnable>
#include <QPoint>
#include <QSize>
#include <QImage>
#include <QDebug>
#include "concurrentqueue.h"
struct
Jpeg
{
Jpeg
(
const
QByteArray
&
d
,
const
int
i
)
:
data
(
d
),
index
(
i
)
{
}
~
Jpeg
()
{
// QByteArray::fromRawData: " QByteArray does not take ownership of data,
// so the QByteArray destructor will never delete the raw data,
// even when the last QByteArray referring to data is destroyed."
delete
[]
data
.
constData
();
}
QByteArray
data
;
int
index
;
};
/*!
* \brief Loads JPEG files on a separate thread
* \brief Loads JPEG images
*
* Consumes
*/
class
JpegDecoder
:
public
QObject
,
public
QRunnable
class
JpegDecoder
:
public
QObject
{
Q_OBJECT
public
:
JpegDecoder
(
const
QByteArray
&
jpeg
,
const
int
x
,
const
int
y
,
const
int
w
,
const
int
h
,
QObject
*
parent
=
0
);
void
run
()
;
JpegDecoder
(
ConcurrentQueue
<
Jpeg
*
,
64u
>
*
queue
,
QObject
*
parent
=
0
);
ConcurrentQueue
<
Jpeg
*
,
64u
>
*
m_queue
;
signals
:
void
finished
(
const
QImage
&
image
,
const
int
x
,
const
int
y
,
const
int
w
,
const
int
h
);
private
:
QByteArray
m_jpeg
;
QImage
m_image
;
int
m_x
;
int
m_y
;
int
m_w
;
int
m_h
;
void
finished
(
const
QImage
&
image
,
const
int
width
,
const
int
height
,
const
int
index
);
public
slots
:
void
operate
();
};
#endif // JPEGDECODER_H
main.qml
View file @
36bd0aa2
...
...
@@ -29,31 +29,5 @@ ApplicationWindow {
port
:
10495
width
:
1024
height
:
768
/* Keys {
onPressed:
}*/
MouseArea
{
anchors.fill
:
parent
// cursorShape: Qt.BlankCursor
hoverEnabled
:
true
acceptedButtons
:
Qt
.
LeftButton
|
Qt
.
MiddleButton
|
Qt
.
RightButton
onPositionChanged
:
vnc
.
setMouse
(
mouse
.
x
,
mouse
.
y
,
mouse
.
buttons
&
Qt
.
LeftButton
,
mouse
.
buttons
&
Qt
.
MiddleButton
,
mouse
.
buttons
&
Qt
.
RightButton
)
onPressed
:
vnc
.
setMouse
(
mouse
.
x
,
mouse
.
y
,
mouse
.
buttons
&
Qt
.
LeftButton
,
mouse
.
buttons
&
Qt
.
MiddleButton
,
mouse
.
buttons
&
Qt
.
RightButton
)
onReleased
:
vnc
.
setMouse
(
mouse
.
x
,
mouse
.
y
,
mouse
.
buttons
&
Qt
.
LeftButton
,
mouse
.
buttons
&
Qt
.
MiddleButton
,
mouse
.
buttons
&
Qt
.
RightButton
)
}
}
}
qvnc.cpp
View file @
36bd0aa2
#include "qvnc.h"
QVnc
::
QVnc
()
QVnc
::
QVnc
(
QQuickItem
*
parent
)
:
QQuickFramebufferObject
(
parent
),
m_decoders
(
DECODER_COUNT
),
m_threads
(
DECODER_COUNT
+
1
)
{
setAcceptedMouseButtons
(
Qt
::
AllButtons
);
setAcceptHoverEvents
(
true
);
setTextureFollowsItemSize
(
false
);
for
(
int
i
=
0
;
i
<
m_threads
.
length
();
i
++
)
m_threads
[
i
]
=
new
QThread
(
this
);
connect
(
this
,
&
QVnc
::
windowChanged
,
this
,
&
QVnc
::
winChanged
);
// Don't let Qt change the size of the OpenGL framebuffer
setTextureFollowsItemSize
(
false
);
m_uploader
=
new
Uploader
;
m_uploader
->
moveToThread
(
m_threads
[
0
]
);
m_dispatcher
=
new
Dispatcher
;
m_dispatcher
->
moveToThread
(
&
m_dispatcher_thread
);
connect
(
m_threads
[
0
],
&
QThread
::
finished
,
m_uploader
,
&
QObject
::
deleteLater
)
;
connect
(
m_uploader
,
&
Uploader
::
uploadFinished
,
this
,
&
QVnc
::
update
);
connect
(
&
m_dispatcher_thread
,
&
QThread
::
finished
,
m_dispatcher
,
&
QObject
::
deleteLater
);
m_dispatcher
=
new
Dispatcher
(
m_uploader
);
m_dispatcher
->
moveToThread
(
m_threads
[
0
]);
connect
(
m_threads
[
0
],
&
QThread
::
finished
,
m_dispatcher
,
&
QObject
::
deleteLater
);
connect
(
this
,
&
QVnc
::
open_connection
,
m_dispatcher
,
&
Dispatcher
::
open
);
connect
(
this
,
&
QVnc
::
terminate_connection
,
m_dispatcher
,
&
Dispatcher
::
terminate
);
connect
(
m_dispatcher
,
&
Dispatcher
::
updateFramebuffer
,
this
,
&
QVnc
::
update
);
connect
(
m_dispatcher
,
&
Dispatcher
::
error
,
this
,
&
QVnc
::
dispatch_error
);
// QThreadPool::globalInstance()->reserveThread();
qDebug
()
<<
QThreadPool
::
globalInstance
()
->
maxThreadCount
();
m_dispatcher_thread
.
start
();
int
i
=
1
;
foreach
(
JpegDecoder
*
d
,
m_decoders
)
{
d
=
new
JpegDecoder
(
m_dispatcher
->
queue
());
d
->
moveToThread
(
m_threads
[
i
]);
connect
(
m_threads
[
i
],
&
QThread
::
finished
,
d
,
&
QObject
::
deleteLater
);
connect
(
d
,
&
JpegDecoder
::
finished
,
m_uploader
,
&
Uploader
::
finishedJpeg
);
connect
(
this
,
&
QVnc
::
operate
,
d
,
&
JpegDecoder
::
operate
);
i
++
;
}
for
(
int
i
=
0
;
i
<
m_threads
.
length
();
i
++
)
m_threads
.
at
(
i
)
->
start
();
emit
operate
();
}
QVnc
::~
QVnc
()
{
m_dispatcher_thread
.
quit
();
m_dispatcher_thread
.
wait
();
foreach
(
QThread
*
t
,
m_threads
)
{
t
->
quit
();
t
->
wait
();
}
}
void
QVnc
::
open
()
...
...
@@ -57,11 +78,6 @@ void QVnc::setPort(int port)
emit
portChanged
(
port
);
}
void
QVnc
::
setMouse
(
int
x
,
int
y
,
bool
left
,
bool
middle
,
bool
right
)
{
m_dispatcher
->
setMouse
(
x
,
y
,
left
,
middle
,
right
);
}
void
QVnc
::
dispatch_error
()
{
qDebug
()
<<
"error"
;
...
...
@@ -70,22 +86,17 @@ void QVnc::dispatch_error()
void
QVnc
::
winChanged
(
QQuickWindow
*
window
)
{
if
(
window
!=
NULL
)
connect
(
window
,
&
QQuickWindow
::
openglContextCreated
,
m_dispatcher
,
&
Dispatcher
::
create_context
,
Qt
::
BlockingQueuedConnection
);
}
Dispatcher
*
QVnc
::
dispatcher
()
const
{
return
m_dispatcher
;
connect
(
window
,
&
QQuickWindow
::
openglContextCreated
,
m_uploader
,
&
Uploader
::
createContext
,
Qt
::
BlockingQueuedConnection
);
}
QQuickFramebufferObject
::
Renderer
*
QVnc
::
createRenderer
()
const
{
VncRenderer
*
renderer
=
new
VncRenderer
(
window
(),
m_
dispatcher
->
uploader
().
vertices
(),
m_
dispatcher
->
uploader
().
copy_textures
(),
m_dispatcher
->
uploader
().
draw_textures
()
);
m_
uploader
->
vertices
(),
m_
uploader
->
textures
());
connect
(
m_dispatcher
,
&
Dispatcher
::
colorMaxChanged
,
renderer
,
&
VncRenderer
::
setColorMax
);
connect
(
renderer
,
&
VncRenderer
::
finishedRendering
,
m_dispatcher
,
&
Dispatcher
::
refresh
);
connect
(
renderer
,
&
VncRenderer
::
FBOTextureChanged
,
&
(
m_dispatcher
->
uploader
())
,
&
Uploader
::
changeFBOTexture
);
connect
(
renderer
,
&
VncRenderer
::
FBOTextureChanged
,
m_uploader
,
&
Uploader
::
changeFBOTexture
);
return
renderer
;
}
...
...
@@ -98,3 +109,97 @@ int QVnc::port() const
{
return
m_port
;
}
void
QVnc
::
mousePressEvent
(
QMouseEvent
*
event
)
{
Qt
::
MouseButtons
buttons
=
event
->
buttons
();
m_lastMouseEvent
=
event
->
timestamp
();
if
(
m_dispatcher
->
mouseEvent
(
event
->
x
(),
event
->
y
(),
buttons
&
Qt
::
LeftButton
,
buttons
&
Qt
::
MiddleButton
,
buttons
&
Qt
::
RightButton
,
false
,
false
))
event
->
accept
();
else
event
->
ignore
();
}
void
QVnc
::
mouseReleaseEvent
(
QMouseEvent
*
event
)
{
Qt
::
MouseButtons
buttons
=
event
->
buttons
();
m_lastMouseEvent
=
event
->
timestamp
();
if
(
m_dispatcher
->
mouseEvent
(
event
->
x
(),
event
->
y
(),
buttons
&
Qt
::
LeftButton
,
buttons
&
Qt
::
MiddleButton
,
buttons
&
Qt
::
RightButton
,
false
,
false
))
event
->
accept
();
else
event
->
ignore
();
}
void
QVnc
::
wheelEvent
(
QWheelEvent
*
event
)
{
Qt
::
MouseButtons
buttons
=
event
->
buttons
();
QPoint
rotated
=
event
->
angleDelta
();
m_lastMouseEvent
=
event
->
timestamp
();
if
(
m_dispatcher
->
mouseEvent
(
event
->
x
(),
event
->
y
(),
buttons
&
Qt
::
LeftButton
,
buttons
&
Qt
::
MiddleButton
,
buttons
&
Qt
::
RightButton
,
rotated
.
x
()
>
0
,
rotated
.
x
()
<
0
))
event
->
accept
();
else
event
->
ignore
();
}
void
QVnc
::
mouseMoveEvent
(
QMouseEvent
*
event
)
{
// Filter mouse move events, we don't need 100+ of them in a second
if
((
event
->
timestamp
()
-
m_lastMouseEvent
)
>
33
)
{
Qt
::
MouseButtons
buttons
=
event
->
buttons
();
m_lastMouseEvent
=
event
->
timestamp
();
if
(
m_dispatcher
->
mouseEvent
(
event
->
x
(),
event
->
y
(),
buttons
&
Qt
::
LeftButton
,
buttons
&
Qt
::
MiddleButton
,
buttons
&
Qt
::
RightButton
,
false
,
false
))
event
->
accept
();
else
event
->
ignore
();
}
}
void
QVnc
::
hoverMoveEvent
(
QHoverEvent
*
event
)
{
// Qt bug: timestamp is zero for QHoverEvent
// if((event->timestamp() - m_lastMouseEvent) > 33) {
// m_lastMouseEvent = event->timestamp();
QPoint
position
=
event
->
pos
();
if
(
m_dispatcher
->
mouseEvent
(
position
.
x
(),
position
.
y
(),
false
,
false
,
false
,
false
,
false
))
event
->
accept
();
else
event
->
ignore
();
// }
}
void
QVnc
::
keyPressEvent
(
QKeyEvent
*
event
)
{
}
void
QVnc
::
keyReleaseEvent
(
QKeyEvent
*
event
)
{
}
qvnc.h
View file @
36bd0aa2
#ifndef VNC_H
#define VNC_H
#define DECODER_COUNT 2
#include <QQuickWindow>
#include <QObject>
#include <QQuickFramebufferObject>
...
...
@@ -22,35 +24,47 @@ class QVnc : public QQuickFramebufferObject
Q_PROPERTY
(
int
port
READ
port
WRITE
setPort
NOTIFY
portChanged
)
public
:
explicit
QVnc
();
explicit
QVnc
(
QQuickItem
*
parent
=
Q_NULLPTR
);
~
QVnc
();
Renderer
*
createRenderer
()
const
;
QString
host
()
const
;
int
port
()
const
;
Dispatcher
*
dispatcher
()
const
;
protected
:
void
mousePressEvent
(
QMouseEvent
*
event
);
void
mouseReleaseEvent
(
QMouseEvent
*
event
);
void
mouseMoveEvent
(
QMouseEvent
*
event
);
void
keyPressEvent
(
QKeyEvent
*
event
);
void
keyReleaseEvent
(
QKeyEvent
*
event
);
void
wheelEvent
(
QWheelEvent
*
event
);
void
hoverMoveEvent
(
QHoverEvent
*
event
);
private
:
Dispatcher
*
m_dispatcher
;
Uploader
*
m_uploader
;
QVector
<
JpegDecoder
*>
m_decoders
;
VncRenderer
*
m_renderer
;
QVector
<
QThread
*>
m_threads
;
QString
m_host
;
int
m_port
;
ulong
m_lastMouseEvent
;
signals
:
void
open_connection
(
QString
host
,
int
port
);
void
terminate_connection
();
void
hostChanged
(
QString
host
);
void
portChanged
(
int
port
);
void
operate
();
public
slots
:
void
open
();
void
terminate
();
void
setHost
(
QString
host
);
void
setPort
(
int
port
);
void
setMouse
(
int
x
,
int
y
,
bool
left
,
bool
middle
,
bool
right
);
void
dispatch_error
();
private
:
Dispatcher
*
m_dispatcher
;
QThread
m_dispatcher_thread
;
QString
m_host
;
int
m_port
;
private
slots
:
void
winChanged
(
QQuickWindow
*
window
);
};
...
...
uploader.cpp
View file @
36bd0aa2
#include "uploader.h"
#include <cstring>
Uploader
::
Uploader
(
QObject
*
parent
)
:
QObject
(
parent
),
m_
uploader_context
(
this
),
m_copyProgram
(
this
)
Uploader
::
Uploader
(
QObject
*
parent
)
:
QObject
(
parent
),
m_
context
(
this
),
m_allocated
(
0
),
m_program
(
this
),
m_jpegs
(
0
)
{
// "applications must ensure that create() is only called on the main (GUI) thread"
m_surface
.
create
();
m_copy_textures
=
QSharedPointer
<
QVector
<
GLuint
>>
(
new
QVector
<
GLuint
>
);
m_draw_textures
=
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
(
new
QVector
<
QOpenGLTexture
*>
);
m_textures
=
QSharedPointer
<
QVector
<
GLuint
>>
(
new
QVector
<
GLuint
>
);
// A single rectangle takes 20 float values to describe (4 vertices * (2 coordinate + 3 color))
m_fill_data
.
reserve
(
100
);
m_draw_data
.
reserve
(
100
);
m_copy_data
.
reserve
(
5
);
m_copy_textures
->
reserve
(
5
);
m_draw_textures
->
reserve
(
5
);
m_vertices
=
QSharedPointer
<
QOpenGLBuffer
>
(
new
QOpenGLBuffer
);
// reserve space for 10 rectangles
m_data
.
reserve
(
280
);
m_textures
->
reserve
(
10
);
}
Uploader
::~
Uploader
()
{
m_
copyP
rogram
.
release
();
m_
p
rogram
.
release
();
}
void
Uploader
::
create
_c
ontext
(
QOpenGLContext
*
context
)
void
Uploader
::
create
C
ontext
(
QOpenGLContext
*
context
)
{
static
const
float
position
[]
=
{
-
1.0
f
,
-
1.0
f
,
-
1.0
f
,
1.0
f
,
1.0
f
,
-
1.0
f
,
1.0
f
,
1.0
f
};
m_
uploader_
context
.
setShareContext
(
context
);
m_
uploader_
context
.
create
();
m_
uploader_
context
.
makeCurrent
(
&
m_surface
);
m_functions
=
m_
uploader_
context
.
functions
();
m_
copyP
rogram
.
addShaderFromSourceFile
(
QOpenGLShader
::
Vertex
,
"copy_shader.vsh"
);
m_
copyP
rogram
.
addShaderFromSourceFile
(
QOpenGLShader
::
Fragment
,
"copy_shader.fsh"
);
m_
copyP
rogram
.
bind
();
m_context
.
setShareContext
(
context
);
m_context
.
create
();
m_context
.
makeCurrent
(
&
m_surface
);
m_functions
=
m_context
.
functions
();
m_
p
rogram
.
addShaderFromSourceFile
(
QOpenGLShader
::
Vertex
,
"copy_shader.vsh"
);
m_
p
rogram
.
addShaderFromSourceFile
(
QOpenGLShader
::
Fragment
,
"copy_shader.fsh"
);
m_
p
rogram
.
bind
();
m_functions
->
glActiveTexture
(
GL_TEXTURE0
);
m_
copyP
rogram
.
setUniformValue
(
"texture"
,
0
);
m_
copyP
rogram
.
enableAttributeArray
(
"position"
);
m_
copyP
rogram
.
enableAttributeArray
(
"texcoord"
);
m_
copyP
rogram
.
setAttributeArray
(
"position"
,
GL_FLOAT
,
position
,
2
);
m_
p
rogram
.
setUniformValue
(
"texture"
,
0
);
m_
p
rogram
.
enableAttributeArray
(
"position"
);
m_
p
rogram
.
enableAttributeArray
(
"texcoord"
);
m_
p
rogram
.
setAttributeArray
(
"position"
,
GL_FLOAT
,
position
,
2
);
m_vertices
->
create
();
m_vertices
->
setUsagePattern
(
QOpenGLBuffer
::
DynamicDraw
);
m_vertices
.
create
();
m_vertices
.
setUsagePattern
(
QOpenGLBuffer
::
DynamicDraw
);
}
void
Uploader
::
startedUpdate
()
void
Uploader
::
cleanup
()
{
// Clean up the data from the previous round
m_fill_data
.
clear
();
m_fill_count
=
0
;
m_functions
->
glDeleteTextures
(
m_copy_count
,
m_copy_textures
->
constData
());
m_copy_textures
->
clear
();
m_copy_data
.
clear
();
m_copy_count
=
0
;
for
(
unsigned
int
i
=
0
;
i
<
m_draw_count
;
i
++
)
{
m_draw_textures
->
at
(
i
)
->
destroy
();
delete
m_draw_textures
->
at
(
i
);
}
m_draw_textures
->
clear
();
m_draw_data
.
clear
();
m_draw_count
=
0
;
m_data
.
clear
();
m_functions
->
glDeleteTextures
(
m_textures
->
size
(),
m_textures
->
constData
());
m_textures
->
clear
();
m_finished
=
false
;
}
void
Uploader
::
gotFill
(
const
int
x
,
const
int
y
,
const
int
width
,
const
int
height
,
const
float
red
,
const
float
green
,
const
float
blue
)
{
m_textures
->
append
(
0
);
// NOTE: -coordinates are transformed to normalized device coordinates in the vertex shader
// -coordinates and colors are extended to vec4 in the vertex shader
// -OpenGL ES 2.0 does not support integer values as input,
// thus we need to cast to float on the CPU side :(
// bottom left
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
(
y
+
height
));
m_data
.
append
(
red
);
m_data
.
append
(
green
);
m_data
.
append
(
blue
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// top left
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
y
);
m_data
.
append
(
red
);
m_data
.
append
(
green
);
m_data
.
append
(
blue
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// bottom right
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
(
y
+
height
));
m_data
.
append
(
red
);
m_data
.
append
(
green
);
m_data
.
append
(
blue
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// top right
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
y
);
m_data
.
append
(
red
);
m_data
.
append
(
green
);
m_data
.
append
(
blue
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
}
void
Uploader
::
gotCopy
Rect
(
const
int
src_x
,
const
int
src_y
,
const
int
width
,
const
int
height
,
const
int
dest_x
,
const
int
dest_y
)
void
Uploader
::
gotCopy
(
const
int
src_x
,
const
int
src_y
,
const
int
width
,
const
int
height
,
const
int
dest_x
,
const
int
dest_y
)
{
float
texcoord
[]
=
{(
float
)
src_x
,
(
float
)
(
src_y
+
height
),
(
float
)
src_x
,
(
float
)
src_y
,
...
...
@@ -79,229 +102,227 @@ void Uploader::gotCopyRect(const int src_x, const int src_y, const int width, co
QOpenGLFramebufferObject
fbo
(
width
,
height
);
fbo
.
bind
();
m_functions
->
glViewport
(
0
,
0
,
width
,
height
);
m_
copyP
rogram
.
setAttributeArray
(
"texcoord"
,
GL_FLOAT
,
texcoord
,
2
);
m_
p
rogram
.
setAttributeArray
(
"texcoord"
,
GL_FLOAT
,
texcoord
,
2
);
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
->
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
m_copy_textures
->
append
(
fbo
.
takeTexture
());
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
0
);
m_textures
->
append
(
fbo
.
takeTexture
());
// bottom left
m_
copy_
data
.
append
((
float
)
dest_x
);
m_
copy_
data
.
append
((
float
)
(
dest_y
+
height
));
m_data
.
append
((
float
)
dest_x
);
m_data
.
append
((
float
)
(
dest_y
+
height
));
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// top left
m_
copy_
data
.
append
((
float
)
dest_x
);
m_
copy_
data
.
append
((
float
)
dest_y
);
m_data
.
append
((
float
)
dest_x
);
m_data
.
append
((
float
)
dest_y
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
1.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
1.0
f
);
// bottom right
m_
copy_
data
.
append
((
float
)
(
dest_x
+
width
));
m_
copy_
data
.
append
((
float
)
(
dest_y
+
height
));
m_data
.
append
((
float
)
(
dest_x
+
width
));
m_data
.
append
((
float
)
(
dest_y
+
height
));
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_
copy_
data
.
append
(
1.0
f
);
m_
copy_
data
.
append
(
0.0
f
);
m_data
.
append
(
1.0
f
);
m_data
.
append
(
0.0
f
);
// top right
m_copy_data
.
append
((
float
)
(
dest_x
+
width
));
m_copy_data
.
append
((
float
)
dest_y
);
m_copy_data
.
append
(
0.0
f
);
m_copy_data
.
append
(
0.0
f
);
m_copy_data
.
append
(
0.0
f
);
m_data
.
append
((
float
)
(
dest_x
+
width
));
m_data
.
append
((
float
)
dest_y
);
m_copy_data
.
append
(
1.0
f
);
m_copy_data
.
append
(
1.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_copy_count
++
;
m_data
.
append
(
1.0
f
);
m_data
.
append
(
1.0
f
);
}
void
Uploader
::
gotFillRect
(
const
int
x
,
const
int
y
,
const
int
width
,
const
int
height
,
const
float
red
,
const
float
green
,
const
float
blue
)
void
Uploader
::
gotBitmap
(
const
QByteArray
&
bitmap
,
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
,
const
GLenum
format
,
const
GLenum
type
)
{
// |---|---|---|---|---|
// | X | Y | R | G | B |
// |---|---|---|---|---|
// NOTE: -coordinates are transformed to normalized device coordinates in the vertex shader
// -coordinates and colors are extended to vec4 in the vertex shader
// -OpenGL ES 2.0 does not support integer values as input,
// thus we need to cast to float on the CPU side :(
quint32
real_width
=
qNextPowerOfTwo
(
width
-
1
);
quint32
real_height
=
qNextPowerOfTwo
(
height
-
1
);
GLuint
id
;
m_functions
->
glGenTextures
(
1
,
&
id
);
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
id
);
m_functions
->
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
real_width
,
real_height
,
0
,
format
,
type
,
NULL
);
m_functions
->
glTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
0
,
0
,
width
,
height
,
format
,
type
,
bitmap
.
constData
());
m_textures
->
append
(
id
);
float
bottom
=
(
float
)
height
/
(
float
)
real_height
;
float
right
=
(
float
)
width
/
(
float
)
real_width
;
// bottom left
m_fill_data
.
append
((
float
)
x
);
m_fill_data
.
append
((
float
)
(
y
+
height
));
m_fill_data
.
append
(
red
);
m_fill_data
.
append
(
green
);
m_fill_data
.
append
(
blue
);
m_fill_data
.
append
(
0.0
f
);
m_fill_data
.
append
(
0.0
f
);
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
(
y
+
height
));
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
bottom
);
// top left
m_fill_data
.
append
((
float
)
x
);
m_fill_data
.
append
((
float
)
y
);
m_fill_data
.
append
(
red
);
m_fill_data
.
append
(
green
);
m_fill_data
.
append
(
blue
);
m_fill_data
.
append
(
0.0
f
);
m_fill_data
.
append
(
0.0
f
);
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
y
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// bottom right
m_fill_data
.
append
((
float
)
(
x
+
width
));
m_fill_data
.
append
((
float
)
(
y
+
height
));
m_fill_data
.
append
(
red
);
m_fill_data
.
append
(
green
);
m_fill_data
.
append
(
blue
);
m_fill_data
.
append
(
0.0
f
);
m_fill_data
.
append
(
0.0
f
);
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
(
y
+
height
));
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
right
);
m_data
.
append
(
bottom
);
// top right
m_
fill_
data
.
append
((
float
)
(
x
+
width
));
m_
fill_
data
.
append
((
float
)
y
);
m_fill_data
.
append
(
red
);
m_
fill_data
.
append
(
green
);
m_
fill_data
.
append
(
blue
);
m_
fill_
data
.
append
(
0.0
f
);
m_fill_data
.
append
(
0.0
f
);
m_
fill_count
++
;
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
y
);
m_
data
.
append
(
0.0
f
);
m_
data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
right
);
m_
data
.
append
(
0.0
f
)
;
}
void
Uploader
::
gotBitmap
(
const
QImage
&
image
,
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
)
// Allocate storage for the image
int
Uploader
::
gotJpeg
(
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
)
{
QImage
img
=
image
.
convertToFormat
(
QImage
::
Format_RGBA8888
)
;
m_jpegs
++
;
// "This function returns the nearest power of two greater than value."
// We need greater than or equal
quint32
real_width
=
qNextPowerOfTwo
(
width
-
1
);
quint32
real_height
=
qNextPowerOfTwo
(
height
-
1
);
GLuint
id
;
m_functions
->
glGenTextures
(
1
,
&
id
);
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
id
);
m_functions
->
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
real_width
,
real_height
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
NULL
);
m_textures
->
append
(
id
);
float
bottom
=
(
float
)
height
/
(
float
)
real_height
;
float
right
=
(
float
)
width
/
(
float
)
real_width
;
m_functions
->
glPixelStorei
(
GL_UNPACK_ALIGNMENT
,
1
);
QOpenGLTexture
*
tex
=
new
QOpenGLTexture
(
QOpenGLTexture
::
Target2D
);
tex
->
setSize
(
real_width
,
real_height
);
tex
->
setMipLevels
(
1
);
tex
->
setFormat
(
QOpenGLTexture
::
RGBAFormat
);
tex
->
setMinMagFilters
(
QOpenGLTexture
::
Nearest
,
QOpenGLTexture
::
Nearest
);
tex
->
setWrapMode
(
QOpenGLTexture
::
ClampToEdge
);
tex
->
allocateStorage
(
QOpenGLTexture
::
RGBA
,
QOpenGLTexture
::
UInt8
);
tex
->
bind
();
m_functions
->
glTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
0
,
0
,
width
,
height
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
img
.
constBits
());
tex
->
release
();
// TODO: use a single texture
m_draw_textures
->
append
(
tex
);
// bottom left
m_d
raw_d
ata
.
append
((
float
)
x
);
m_d
raw_d
ata
.
append
((
float
)
(
y
+
height
));
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
(
y
+
height
));
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
bottom
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
bottom
);
// top left
m_d
raw_d
ata
.
append
((
float
)
x
);
m_d
raw_d
ata
.
append
((
float
)
y
);
m_data
.
append
((
float
)
x
);
m_data
.
append
((
float
)
y
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
// bottom right
m_d
raw_d
ata
.
append
((
float
)
(
x
+
width
));
m_d
raw_d
ata
.
append
((
float
)
(
y
+
height
));
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
(
y
+
height
));
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_d
raw_d
ata
.
append
(
right
);
m_d
raw_d
ata
.
append
(
bottom
);
m_data
.
append
(
right
);
m_data
.
append
(
bottom
);
// top right
m_draw_data
.
append
((
float
)
(
x
+
width
));
m_draw_data
.
append
((
float
)
y
);
m_data
.
append
((
float
)
(
x
+
width
));
m_data
.
append
((
float
)
y
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_data
.
append
(
0.0
f
);
m_draw_data
.
append
(
0.0
f
);
m_draw_data
.
append
(
0.0
f
);
m_draw_data
.
append
(
0.0
f
);
m_data
.
append
(
right
);
m_data
.
append
(
0.0
f
);
m_draw_data
.
append
(
right
)
;
m_draw_data
.
append
(
0.0
f
);
return
m_textures
->
size
()
-
1
;
}
m_draw_count
++
;
void
Uploader
::
finishedJpeg
(
const
QImage
&
image
,
const
quint32
width
,
const
quint32
height
,
const
int
index
)
{
m_jpegs
--
;
m_functions
->
glPixelStorei
(
GL_UNPACK_ALIGNMENT
,
1
);
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
m_textures
->
at
(
index
));
m_functions
->
glTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
0
,
0
,
width
,
height
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
image
.
constBits
());
if
(
m_jpegs
==
0
&&
m_finished
)
{
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
0
);
m_functions
->
glFinish
();
emit
uploadFinished
();
}
}
void
Uploader
::
finishedUpdate
()
{
unsigned
int
fillSize
=
m_fill_data
.
size
()
*
sizeof
(
float
);
unsigned
int
copySize
=
m_copy_data
.
size
()
*
sizeof
(
float
);
unsigned
int
drawSize
=
m_draw_data
.
size
()
*
sizeof
(
float
);
unsigned
int
sumSize
=
fillSize
+
copySize
+
drawSize
;
unsigned
int
size
=
m_data
.
size
()
*
sizeof
(
float
);
unsigned
int
nextPowerOfTwo
=
qNextPowerOfTwo
(
size
);
m_vertices
->
bind
();
m_vertices
.
bind
();
if
(
sumSize
>
m_allocated
)
{
m_vertices
->
allocate
(
sumSize
);
m_allocated
=
sumSize
;
if
(
nextPowerOfTwo
>
m_allocated
)
{
m_vertices
.
allocate
(
nextPowerOfTwo
);
m_allocated
=
nextPowerOfTwo
;
}
if
(
fillSize
>
0
)
m_vertices
->
write
(
0
,
m_fill_data
.
constData
(),
fillSize
);
if
(
copySize
>
0
)
m_vertices
->
write
(
fillSize
,
m_copy_data
.
constData
(),
copySize
);
if
(
drawSize
>
0
)
m_vertices
->
write
(
fillSize
+
copySize
,
m_draw_data
.
constData
(),
drawSize
);
m_functions
->
glGetError
();
m_vertices
.
write
(
0
,
m_data
.
constData
(),
size
);
m_vertices
->
release
();
m_functions
->
glFinish
();
}
unsigned
int
Uploader
::
fill_count
()
const
{
return
m_fill_count
;
}
m_vertices
.
release
();
unsigned
int
Uploader
::
copy_count
()
const
{
return
m_copy_count
;
}
unsigned
int
Uploader
::
draw_count
()
const
{
return
m_draw_count
;
if
(
m_jpegs
==
0
)
{
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
0
);
emit
uploadFinished
();
}
else
{
m_finished
=
true
;
}
}
QSharedPointer
<
QVector
<
GLuint
>>
Uploader
::
copy_texture
s
()
void
Uploader
::
swapBuffer
s
()
{
return
m_copy_textures
;
// This thread should finish uploading
// The other thread should finish rendering from the other thread
m_functions
->
glFinish
();
}
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
Uploader
::
draw_textures
()
QSharedPointer
<
QVector
<
GLuint
>>
Uploader
::
textures
()
const
{
return
m_
draw_
textures
;
return
m_textures
;
}
Q
SharedPointer
<
QOpenGLBuffer
>
Uploader
::
vertices
()
const
Q
OpenGLBuffer
Uploader
::
vertices
()
const
{
return
m_vertices
;
}
...
...
@@ -309,5 +330,5 @@ QSharedPointer<QOpenGLBuffer> Uploader::vertices() const
void
Uploader
::
changeFBOTexture
(
const
unsigned
int
FBOTexture
,
const
QMatrix4x4
&
ortho
)
{
m_FBOTexture
=
FBOTexture
;
m_
copyP
rogram
.
setUniformValue
(
"ortho"
,
ortho
);
m_
p
rogram
.
setUniformValue
(
"ortho"
,
ortho
);
}
uploader.h
View file @
36bd0aa2
...
...
@@ -17,7 +17,15 @@
#include <QtAlgorithms>
#include <QSharedPointer>
#include <QtMath>
// #include <GLES/gl2ext.h>
class
Bitmap
{
public
:
QByteArray
data
;
int
x
;
int
y
;
int
width
;
int
height
;
};
class
Uploader
:
public
QObject
{
...
...
@@ -25,51 +33,43 @@ class Uploader : public QObject
public
:
Uploader
(
QObject
*
parent
=
Q_NULLPTR
);
~
Uploader
();
void
create_context
(
QOpenGLContext
*
context
);
void
startedUpdate
();
void
gotCopyRect
(
const
int
src_x
,
const
int
src_y
,
const
int
width
,
const
int
height
,
const
int
dest_x
,
const
int
dest_y
);
void
gotFillRect
(
const
int
x
,
const
int
y
,
const
int
width
,
const
int
height
,
const
float
red
,
const
float
green
,
const
float
blue
);
void
gotBitmap
(
const
QImage
&
image
,
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
);
void
finishedUpdate
();
void
setFramebufferHeight
(
int
framebufferHeight
);
unsigned
int
fill_count
()
const
;
unsigned
int
copy_count
()
const
;
unsigned
int
draw_count
()
const
;
Q
SharedPointer
<
QVector
<
GLuint
>>
copy_textures
()
;
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
draw_textures
()
;
Q
OpenGLBuffer
vertices
()
const
;
QSharedPointer
<
QVector
<
GLuint
>>
textures
()
const
;
QSharedPointer
<
QOpenGLBuffer
>
vertices
()
const
;
// VNC events
void
gotCopy
(
const
int
src_x
,
const
int
src_y
,
const
int
width
,
const
int
height
,
const
int
dest_x
,
const
int
dest_y
);
void
gotFill
(
const
int
x
,
const
int
y
,
const
int
width
,
const
int
height
,
const
float
red
,
const
float
green
,
const
float
blue
);
int
gotJpeg
(
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
);
void
gotBitmap
(
const
QByteArray
&
bitmap
,
const
quint32
x
,
const
quint32
y
,
const
quint32
width
,
const
quint32
height
,
const
GLenum
format
,
const
GLenum
type
);
void
finishedUpdate
();
private
:
int
m_framebufferHeight
;
QOffscreenSurface
m_surface
;
QOpenGLContext
m_
uploader_
context
;
QOpenGLContext
m_context
;
QOpenGLFunctions
*
m_functions
;
Q
SharedPointer
<
QOpenGLBuffer
>
m_vertices
;
Q
OpenGLBuffer
m_vertices
;
unsigned
int
m_allocated
;
QSharedPointer
<
QVector
<
GLuint
>>
m_textures
;
QOpenGLShaderProgram
m_
copyP
rogram
;
QOpenGLShaderProgram
m_
p
rogram
;
GLuint
m_FBOTexture
;
unsigned
int
m_fill_count
;
QVector
<
float
>
m_fill_data
;
unsigned
int
m_copy_count
;
QVector
<
float
>
m_copy_data
;
QSharedPointer
<
QVector
<
GLuint
>>
m_copy_textures
;
unsigned
int
m_draw_count
;
QVector
<
float
>
m_draw_data
;
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
m_draw_textures
;
uchar
m_decoders_running
;
QVector
<
float
>
m_data
;
QVector
<
Bitmap
*>
m_bitmaps
;
int
m_jpegs
;
bool
m_finished
;
void
swapBuffers
();
signals
:
void
uploadFinished
();
public
slots
:
void
changeFBOTexture
(
const
unsigned
int
FBOTexture
,
const
QMatrix4x4
&
ortho
);
void
createContext
(
QOpenGLContext
*
context
);
void
cleanup
();
void
finishedJpeg
(
const
QImage
&
image
,
const
quint32
width
,
const
quint32
height
,
int
index
);
};
#endif // UPLOADER_H
vncrenderer.cpp
View file @
36bd0aa2
...
...
@@ -2,12 +2,12 @@
#include <cstring>
VncRenderer
::
VncRenderer
(
QQuickWindow
*
window
,
QSharedPointer
<
QOpenGLBuffer
>
vertices
,
QSharedPointer
<
QVector
<
GLuint
>>
copy_textures
,
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
draw_textures
,
QOpenGLBuffer
vertices
,
QSharedPointer
<
QVector
<
GLuint
>>
textures
,
QObject
*
parent
)
:
QObject
(
parent
),
m_
clear
(
true
),
m_window
(
window
),
m_vertices
(
vertices
),
m_copy_textures
(
copy_textures
),
m_draw_textures
(
draw_textures
)
QObject
(
parent
),
m_
window
(
window
),
m_vertices
(
vertices
),
m_textures
(
textures
),
m_rendered
(
false
)
{
connect
(
m_window
,
&
QQuickWindow
::
frameSwapped
,
this
,
&
VncRenderer
::
frameSwapped
);
m_program
.
addShaderFromSourceFile
(
QOpenGLShader
::
Vertex
,
"draw_shader.vsh"
);
m_program
.
addShaderFromSourceFile
(
QOpenGLShader
::
Fragment
,
"draw_shader.fsh"
);
m_program
.
bind
();
...
...
@@ -20,19 +20,13 @@ VncRenderer::VncRenderer(QQuickWindow *window,
void
VncRenderer
::
render
()
{
/*if(m_frameCount == 0)
m_time.start();
else
qDebug() << (float(m_frameCount) / (float(m_time.elapsed()) / 1000.0f));
m_frameCount++;*/
if
(
m_clear
)
{
m_functions
->
glClearColor
(
0.0
f
,
0.0
f
,
0.0
f
,
1.0
f
);
m_functions
->
glClear
(
GL_COLOR_BUFFER_BIT
);
m_clear
=
false
;
}
static
QTime
frameTime
;
qDebug
()
<<
qRound
(
1000.0
/
frameTime
.
elapsed
());
frameTime
.
restart
();
m_program
.
bind
();
m_vertices
->
bind
();
m_vertices
.
bind
();
m_program
.
setAttributeBuffer
(
"position"
,
GL_FLOAT
,
0
*
sizeof
(
float
),
2
,
7
*
sizeof
(
float
));
m_program
.
setAttributeBuffer
(
"color"
,
GL_FLOAT
,
2
*
sizeof
(
float
),
3
,
7
*
sizeof
(
float
));
m_program
.
setAttributeBuffer
(
"texcoord"
,
GL_FLOAT
,
5
*
sizeof
(
float
),
2
,
7
*
sizeof
(
float
));
...
...
@@ -40,28 +34,18 @@ void VncRenderer::render()
m_program
.
enableAttributeArray
(
"color"
);
m_program
.
enableAttributeArray
(
"texcoord"
);
for
(
unsigned
int
i
=
0
;
i
<
m_fill_count
;
i
++
)
for
(
int
i
=
0
;
i
<
m_textures
->
length
();
i
++
)
{
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
m_textures
->
at
(
i
));
if
(
m_textures
->
at
(
i
)
!=
0
)
{
m_functions
->
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
m_functions
->
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
m_functions
->
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_S
,
GL_CLAMP_TO_EDGE
);
m_functions
->
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_T
,
GL_CLAMP_TO_EDGE
);
}
m_functions
->
glDrawArrays
(
GL_TRIANGLE_STRIP
,
i
*
4
,
4
);
for
(
unsigned
int
i
=
0
;
i
<
m_copy_count
;
i
++
)
{
m_functions
->
glBindTexture
(
GL_TEXTURE_2D
,
m_copy_textures
->
at
(
i
));
m_functions
->
glDrawArrays
(
GL_TRIANGLE_STRIP
,
(
m_fill_count
+
i
)
*
4
,
4
);
}
for
(
unsigned
int
i
=
0
;
i
<
m_draw_count
;
i
++
)
{
m_draw_textures
->
at
(
i
)
->
bind
();
m_functions
->
glDrawArrays
(
GL_TRIANGLE_STRIP
,
(
m_fill_count
+
m_copy_count
+
i
)
*
4
,
4
);
m_draw_textures
->
at
(
i
)
->
release
();
}
m_vertices
->
release
();
m_program
.
release
();
m_functions
->
glFlush
();
m_window
->
resetOpenGLState
();
emit
finishedRendering
();
m_rendered
=
true
;
}
QOpenGLFramebufferObject
*
VncRenderer
::
createFramebufferObject
(
const
QSize
&
size
)
...
...
@@ -72,20 +56,33 @@ QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size
m_program
.
setUniformValue
(
"ortho"
,
ortho
);
m_program
.
release
();
QOpenGLFramebufferObject
*
framebufferObject
=
new
QOpenGLFramebufferObject
(
size
);
QOpenGLFramebufferObjectFormat
format
;
/* format.setTextureTarget(GL_TEXTURE_2D);
#ifdef GL_RGB8
format.setInternalTextureFormat(GL_RGB8);
#ifdef GL_RGB8_OES
format.setInternalTextureFormat(GL_RGB8_OES);
#else
format.setInternalTextureFormat(GL_RGBA);
#endif*/
QOpenGLFramebufferObject
*
framebufferObject
=
new
QOpenGLFramebufferObject
(
size
,
format
);
emit
FBOTextureChanged
(
framebufferObject
->
texture
(),
ortho
);
return
framebufferObject
;
}
void
VncRenderer
::
s
ynchronize
(
QQuickFramebufferObject
*
object
)
void
VncRenderer
::
s
etColorMax
(
const
QVector3D
&
colorMax
)
{
QVnc
*
vnc
=
static_cast
<
QVnc
*>
(
object
);
Dispatcher
*
dispatcher
=
vnc
->
dispatcher
(
);
m_fill_count
=
dispatcher
->
fill_count
();
m_copy_count
=
dispatcher
->
copy_count
();
m_draw_count
=
dispatcher
->
draw_count
();
if
(
m_program
.
bind
())
{
m_program
.
setUniformValue
(
"colormax"
,
colorMax
);
m_program
.
release
();
}
}
m_program
.
bind
();
m_program
.
setUniformValue
(
"colormax"
,
dispatcher
->
colorMax
());
m_program
.
release
();
void
VncRenderer
::
frameSwapped
()
{
if
(
m_rendered
)
{
m_rendered
=
false
;
emit
finishedRendering
();
}
}
vncrenderer.h
View file @
36bd0aa2
...
...
@@ -9,40 +9,32 @@
#include <QMatrix4x4>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QSharedPointer>
#include <QTime>
#include "qvnc.h"
class
VncRenderer
:
public
QObject
,
public
QQuickFramebufferObject
::
Renderer
{
Q_OBJECT
public
:
VncRenderer
(
QQuickWindow
*
window
,
QSharedPointer
<
QOpenGLBuffer
>
vertices
,
QSharedPointer
<
QVector
<
GLuint
>>
copy_textures
,
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
draw_textures
,
QOpenGLBuffer
vertices
,
QSharedPointer
<
QVector
<
GLuint
>>
textures
,
QObject
*
parent
=
0
);
protected
:
void
render
()
override
;
QOpenGLFramebufferObject
*
createFramebufferObject
(
const
QSize
&
size
)
override
;
void
synchronize
(
QQuickFramebufferObject
*
)
override
;
private
:
QSharedPointer
<
QOpenGLBuffer
>
m_vertices
;
QOpenGLShaderProgram
m_program
;
QQuickWindow
*
m_window
;
QOpenGLBuffer
m_vertices
;
QSharedPointer
<
QVector
<
GLuint
>>
m_textures
;
QVector3D
m_colorMax
;
QOpenGLShaderProgram
m_program
;
QOpenGLFunctions
*
m_functions
;
bool
m_clear
;
int
m_frameCount
;
QTime
m_time
;
unsigned
int
m_fill_count
;
unsigned
int
m_copy_count
;
unsigned
int
m_draw_count
;
QSharedPointer
<
QVector
<
GLuint
>>
m_copy_textures
;
QSharedPointer
<
QVector
<
QOpenGLTexture
*>>
m_draw_textures
;
bool
m_rendered
;
public
slots
:
void
setColorMax
(
const
QVector3D
&
colorMax
);
private
slots
:
void
frameSwapped
();
signals
:
void
FBOTextureChanged
(
const
unsigned
int
FBOTexture
,
const
QMatrix4x4
&
ortho
);
void
finishedRendering
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment