Commit 1eb3ee74 by Balázs Ludmány

Commit Arnoldnak!

parent cb68f729
......@@ -18,11 +18,10 @@ QML_IMPORT_PATH =
# Default rules for deployment.
include(deployment.pri)
LIBS += -L$$PWD/../libvnc/libvncclient/.libs/ -lvncclient -lEGL -ljpeg -L$$PWD/../build-texload-Desktop_Qt_5_9_0_GCC_64bit-Release -ltexload
unix|win32: LIBS += -L$$PWD/../libvnc/libvncclient/.libs/ -lvncclient -lEGL -ljpeg
INCLUDEPATH += $$PWD/../libvnc
DEPENDPATH += $$PWD/../libvnc
INCLUDEPATH += $$PWD/../libvnc $$PWD/../texload
DEPENDPATH += $$PWD/../libvnc $$PWD/../texload
HEADERS += \
vncrenderer.h \
......@@ -33,11 +32,12 @@ HEADERS += \
concurrentqueue.h
DISTFILES += \
draw_shader.fsh \
draw_shader.vsh \
copy_shader.vsh \
copy_shader.fsh \
fill_shader.vsh \
fill_shader.fsh \
bitmap_shader.vsh \
bitmap_shader.fsh
bitmap_shader.fsh \
ycbcr_shader.fsh
#QMAKE_CXXFLAGS_RELEASE -= -O2
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2016-08-01T17:47:15. -->
<!-- Written by QtCreator 4.3.1, 2017-07-03T16:01:35. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{922a144e-00be-428d-a407-33848eeec705}</value>
<value type="QByteArray">{221989f1-8db7-4676-b888-f4ceb403e265}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
......@@ -40,6 +40,7 @@
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
......@@ -53,19 +54,21 @@
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangStaticAnalyzer.SuppressedDiagnostics"/>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<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="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.9.0 GCC 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.9.0 GCC 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.59.gcc_64_kit</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">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/ldmnyblzs/files/Projects/build-ThinClient-Desktop-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ldmnyblzs/Projects/build-ThinClient-Desktop_Qt_5_9_0_GCC_64bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
......@@ -73,7 +76,6 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
......@@ -118,7 +120,9 @@
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges">
<value type="QString">QT_QPA_VERBOSE=opengl:1</value>
</valuelist>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
......@@ -126,7 +130,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/ldmnyblzs/files/Projects/build-ThinClient-Desktop-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ldmnyblzs/Projects/build-ThinClient-Desktop_Qt_5_9_0_GCC_64bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
......@@ -134,7 +138,6 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
......@@ -186,7 +189,67 @@
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ldmnyblzs/Projects/build-ThinClient-Desktop_Qt_5_9_0_GCC_64bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
......@@ -202,6 +265,11 @@
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
......@@ -237,23 +305,22 @@
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes">
<value type="QString">QML_RENDER_TIMING=1</value>
</valuelist>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<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>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/ldmnyblzs/Projects/ThinClient/ThinClient.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">ThinClient.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">/home/ldmnyblzs/Projects/build-ThinClient-Desktop_Qt_5_9_0_GCC_64bit-Release</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.2.1, 2017-06-03T23:07:15. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{922a144e-00be-428d-a407-33848eeec705}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<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.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/ldmnyblzs/files/Projects/build-ThinClient-Desktop-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/ldmnyblzs/files/Projects/build-ThinClient-Desktop-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">ThinClient</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">ThinClient2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/ldmnyblzs/Projects/ThinClient/ThinClient.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">ThinClient.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">/media/ldmnyblzs/files/Projects/build-ThinClient-Desktop-Release</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>
uniform sampler2D texture;
varying highp vec4 vartexcoord;
varying highp vec2 vartexcoord;
void main(void)
{
gl_FragColor = texture2D(texture, vartexcoord.st);
//gl_FragColor = vec4(vartexcoord.st, 0.0, 1.0);
gl_FragColor = vec4(texture2D(texture, vartexcoord).rgb, 1.0);
}
uniform highp mat4 ortho;
uniform highp mat4 texortho;
uniform highp mat4 ortho; // transforms screen coordinates to [-1, 1]
uniform highp mat4 texortho; // transforms screen coordinates to [0, 1]
attribute highp vec2 position;
attribute highp vec2 texcoord;
varying highp vec4 vartexcoord;
varying highp vec2 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
vartexcoord = texortho * vec4(texcoord, 0.0, 1.0);
vartexcoord = vec4(texortho * vec4(position, 0.0, 1.0)).xy;
}
......@@ -3,6 +3,7 @@
#include <QSemaphore>
#include <QMutex>
#include <QTime>
template <class T, const unsigned short S>
class ConcurrentQueue
......@@ -14,6 +15,7 @@ public:
bool isEmpty() const;
private:
T m_buffer[S];
QTime m_time[S];
unsigned short m_next;
unsigned short m_first;
QSemaphore m_free;
......
uniform sampler2D texture;
varying mediump vec2 vartexcoord;
varying highp vec2 vartarget;
void main(void)
{
gl_FragColor = texture2D(texture, vartexcoord);
gl_FragColor = texture2D(texture, vartarget);
}
uniform mediump mat4 ortho;
uniform mediump mat4 texortho;
attribute mediump vec2 position;
attribute mediump vec2 texcoord;
varying mediump vec2 vartexcoord;
uniform highp mat4 srcortho;
uniform highp mat4 trgortho;
attribute highp vec2 source;
attribute highp vec2 target;
varying highp vec2 vartarget;
void main(void)
{
gl_Position = vec4((position.x - 1024.0) / 1024.0, (position.y - 1024.0) / 1024.0, 0.0, 1.0);
vartexcoord = vec2(texcoord.x / 1920.0, texcoord.y / 1080.0);
gl_Position = trgortho * vec4(target, 0.0, 1.0);
vartarget = vec4(srcortho * vec4(source, 0.0, 1.0)).xy;
}
#include "dispatcher.h"
#include "uploader.h"
Dispatcher::Dispatcher(Uploader *uploader, QObject *parent) :
QObject(parent), m_client(NULL), m_uploader(uploader)
QObject(parent)
{
m_client = rfbGetClient(8, 3, 4);
m_client->canHandleNewFBSize = FALSE;
m_client->MallocFrameBuffer = Dispatcher::MallocFrameBuffer;
m_client->GotCopyRect = Dispatcher::GotCopyRect;
m_client->GotFillRect = Dispatcher::GotFillRect;
m_client->GotBitmap = Dispatcher::GotBitmap;
m_client->GotJpeg = Dispatcher::GotJpeg;
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
m_client->GetPassword = Dispatcher::GetPassword;
rfbClientSetClientData(m_client, const_cast<char*>("dispatcher"), this);
// the pointer to the Uploader is stored in the rfbClient instead of a member of the class to avoid duplication
rfbClientSetClientData(m_client, const_cast<char*>("uploader"), uploader);
}
Dispatcher::~Dispatcher()
{
rfbClientCleanup(m_client);
}
rfbBool Dispatcher::MallocFrameBuffer(rfbClient *client)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
auto dispatcher = static_cast<Dispatcher *>(rfbClientGetClientData(client, const_cast<char*>("dispatcher")));
emit dispatcher->resizeFramebuffer(QSize(client->width, client->height));
return TRUE;
}
void Dispatcher::GotCopyRect(rfbClient *client, const int src_x, const int src_y, const int w, const int h, const int dest_x, const int dest_y)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->uploader()->gotCopy(src_x, src_y, w, h, dest_x, dest_y);
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(client, const_cast<char*>("uploader")));
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)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(client, const_cast<char*>("uploader")));
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()->gotFill(x, y, w, h, red, green, blue);
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)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
// We have to make a deep copy because libvnc might free the buffer as soon as this function returns
dispatcher->uploader()->gotBitmap(buffer, x, y, w, h);
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(client, const_cast<char*>("uploader")));
uploader->gotBitmap(buffer, x, y, w, h);
}
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));
dispatcher->uploader()->gotJpeg();
Jpeg *jpeg = new Jpeg({(unsigned char*)buffer, length, x, y, w, h});
dispatcher->queue()->enqueue(jpeg);
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(client, const_cast<char*>("uploader")));
uploader->gotJpeg(buffer, length, x, y, w, h);
return TRUE;
}
void Dispatcher::FinishedFrameBufferUpdate(rfbClient *client)
{
Dispatcher *dispatcher = (Dispatcher *) rfbClientGetClientData(client, 0);
dispatcher->uploader()->finishedUpdate();
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(client, const_cast<char*>("uploader")));
uploader->finishedUpdate();
}
char *Dispatcher::GetPassword(rfbClient *client)
{
char* password = new char[9];
char* password = (char*) std::malloc(sizeof(char) * 9);
strcpy(password, "asdfasdf");
return password;
}
......@@ -78,39 +96,18 @@ int Dispatcher::bitsPerPixel()
return m_client->format.bitsPerPixel;
}
ConcurrentQueue<Jpeg *, 256u> *Dispatcher::queue()
{
return &m_queue;
}
Uploader *Dispatcher::uploader() const
{
return m_uploader;
}
void Dispatcher::open(const QString host, const int port, const int width, const int height)
{
QByteArray tmp = host.toLocal8Bit();
m_client = rfbGetClient(8, 3, 4);
m_client->canHandleNewFBSize = FALSE;
m_client->serverHost = new char[tmp.size() + 1];
strcpy(m_client->serverHost, tmp.constData());
m_client->serverPort = port;
m_client->MallocFrameBuffer = Dispatcher::MallocFrameBuffer;
m_client->GotCopyRect = Dispatcher::GotCopyRect;
m_client->GotFillRect = Dispatcher::GotFillRect;
m_client->GotBitmap = Dispatcher::GotBitmap;
m_client->GotJpeg = Dispatcher::GotJpeg;
m_client->FinishedFrameBufferUpdate = Dispatcher::FinishedFrameBufferUpdate;
m_client->GetPassword = Dispatcher::GetPassword;
// Set the format requested by the user
m_client->appData.useRemoteCursor = TRUE;
//m_client->appData.useRemoteCursor = TRUE;
m_client->width = width;
m_client->height = height;
m_client->appData.compressLevel = 9;
m_client->appData.qualityLevel = 0;
//m_client->appData.compressLevel = 0;
//m_client->appData.qualityLevel = 9;
#ifdef __BIG_ENDIAN__
m_client->format.bigEndian = TRUE;
#else
......@@ -120,30 +117,11 @@ void Dispatcher::open(const QString host, const int port, const int width, const
m_client->format.trueColour = TRUE;
m_client->format.bitsPerPixel = 32;
rfbClientSetClientData(m_client, 0, this);
if(!rfbInitClient(m_client, NULL, NULL)) {
emit error();
return;
}
// 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
refresh();
decode();
}
......@@ -166,10 +144,9 @@ void Dispatcher::refresh()
}
void Dispatcher::decode()
{
if(m_client == NULL)
return;
m_uploader->startDecoding();
auto uploader = static_cast<Uploader *>(rfbClientGetClientData(m_client, const_cast<char*>("uploader")));
uploader->startDecoding();
if(!HandleRFBServerMessage(m_client)) {
terminate();
......
#ifndef RFBDISPATCH_H
#define RFBDISPATCH_H
#include <QOpenGLContext>
#include <QCoreApplication>
#include <QImage>
#include <QThreadPool>
#include <QObject>
#include <QPoint>
#include <QSize>
#include <QColor>
#include <QMouseEvent>
#include <QVector3D>
#include <QTime>
#include <rfb/rfbclient.h>
#include "uploader.h"
#include "jpegdecoder.h"
extern QTime elapsed;
class Uploader;
class Dispatcher : public QObject
{
Q_OBJECT
public:
Dispatcher(Uploader *uploader, QObject *parent = Q_NULLPTR);
explicit Dispatcher(Uploader *uploader, QObject *parent = Q_NULLPTR);
~Dispatcher();
// libvnc hooks
static rfbBool MallocFrameBuffer(rfbClient* client);
......@@ -40,14 +28,8 @@ public:
// parameters of the VNC connection
int bitsPerPixel();
// getters
ConcurrentQueue<Jpeg *, 256u>* queue();
Uploader *uploader() const;
private:
rfbClient *m_client;
Uploader *m_uploader;
ConcurrentQueue<Jpeg*, 256u> 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);
......
uniform sampler2D texture;
varying mediump vec2 vartexcoord;
varying lowp vec4 varcolor;
void main(void)
{
gl_FragColor = vec4(texture2D(texture, vartexcoord).rgb + varcolor.rgb, 1.0);
}
uniform mediump mat4 ortho;
attribute mediump vec2 position;
attribute lowp vec4 color;
attribute mediump vec2 texcoord;
varying lowp vec4 varcolor;
varying mediump vec2 vartexcoord;
void main(void)
{
gl_Position = ortho * vec4(position, 0.0, 1.0);
varcolor = color;
vartexcoord = vec2(texcoord.x / 2048.0, texcoord.y / 2048.0);
}
......@@ -2,5 +2,5 @@ varying highp vec4 varcolor;
void main(void)
{
gl_FragColor = varcolor;
gl_FragColor = vec4(varcolor.rgb, 1.0);
}
#include "jpegdecoder.h"
int Jpeg::y_width = 0;
int Jpeg::cb_width = 0;
int Jpeg::cr_width = 0;
unsigned char *Jpeg::y_pointer = 0;
unsigned char *Jpeg::cb_pointer = 0;
unsigned char *Jpeg::cr_pointer = 0;
struct error_mgr
{
struct jpeg_error_mgr mgr;
jmp_buf setjmp_buffer;
};
typedef struct error_mgr* error_ptr;
METHODDEF(void)
error_exit (j_common_ptr cinfo)
{
error_ptr myerr = (error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
JpegDecoder::JpegDecoder(ConcurrentQueue<Jpeg *, 256u> *queue, QObject *parent) :
JpegDecoder::JpegDecoder(ConcurrentQueue<Jpeg *, 1024u> *queue, QObject *parent) :
QObject(parent), m_queue(queue)
{
}
void JpegDecoder::operate()
{
//QTime time;
//time.start();
struct jpeg_decompress_struct cinfo;
struct error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.mgr);
jerr.mgr.error_exit = error_exit;
jerr.mgr.error_exit = &error_exit;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
}
jpeg_create_decompress(&cinfo);
Jpeg *jpeg;
JSAMPLE *samples;
JSAMPROW *rows;
//int dequeue, decompress;
forever {
//time.restart();
jpeg = m_queue->dequeue();
//dequeue = time.elapsed();
jpeg_mem_src(&cinfo, jpeg->data, jpeg->length);
(void) jpeg_read_header(&cinfo, TRUE);
cinfo.dct_method = JDCT_FASTEST;
cinfo.do_fancy_upsampling = FALSE;
cinfo.two_pass_quantize = FALSE;
cinfo.dither_mode = JDITHER_ORDERED;
//cinfo.scale_num = 1;
//cinfo.scale_denom = 8;
cinfo.out_color_space = JCS_EXT_RGBX;
(void) jpeg_start_decompress(&cinfo);
samples = new JSAMPLE[cinfo.output_width * cinfo.output_height * cinfo.output_components];
rows = new JSAMPROW[cinfo.output_height * cinfo.output_components];
for(size_t i = 0; i < cinfo.output_height; i++) {
rows[i] = samples + (i * cinfo.output_width * cinfo.output_components);
auto jpeg = m_queue->dequeue();
jpeg->output = new JSAMPARRAY[3];
int paddingHeight = (16 - (jpeg->height % 16));
int paddingWidth = jpeg->width + (16 - jpeg->width % 16);
jpeg->padding = new JSAMPLE[3 * paddingHeight * paddingWidth];
jpeg->rows = new JSAMPROW[3 * (jpeg->height + paddingHeight)];
for (unsigned char component = 0; component < 3; ++component)
jpeg->output[component] = &jpeg->rows[component * (jpeg->height + paddingHeight)];
for (int row = 0; row < jpeg->height; ++row)
{
jpeg->output[0][row] = &Jpeg::y_pointer[jpeg->x + (jpeg->y + row) * Jpeg::y_width];
jpeg->output[1][row] = &Jpeg::cb_pointer[jpeg->x + (jpeg->y + row) * Jpeg::cb_width];
jpeg->output[2][row] = &Jpeg::cr_pointer[jpeg->x + (jpeg->y + row) * Jpeg::cr_width];
}
for (int row = 0; row < paddingHeight; ++row)
{
jpeg->output[0][jpeg->height + row] = &jpeg->padding[row * paddingWidth];
jpeg->output[1][jpeg->height + row] = &jpeg->padding[(paddingHeight + row) * paddingWidth];
jpeg->output[2][jpeg->height + row] = &jpeg->padding[(2 * paddingHeight + row) * paddingWidth];
}
jpeg_mem_src(&cinfo, jpeg->input, jpeg->length);
jpeg_read_header(&cinfo, TRUE);
cinfo.dct_method = JDCT_FASTEST;
cinfo.raw_data_out = TRUE;
jpeg_start_decompress(&cinfo);
JSAMPARRAY rowzero[3];
for(int component = 0; component < cinfo.output_components; component++)
rowzero[component] = &jpeg->output[component][0];
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, rows + cinfo.output_scanline, 1);
for(int component = 0; component < cinfo.output_components; component++)
jpeg->output[component] = &rowzero[component][cinfo.output_scanline / (cinfo.max_v_samp_factor * cinfo.comp_info[component].v_samp_factor)];
jpeg_read_raw_data(&cinfo, jpeg->output, qMax(static_cast<int>(cinfo.output_height - cinfo.output_scanline), cinfo.max_v_samp_factor * DCTSIZE));
}
(void) jpeg_finish_decompress(&cinfo);
//decompress = time.elapsed();
//qDebug() << "dequeue" << dequeue << "decompress" << decompress;
emit finished(samples, jpeg->x, jpeg->y, jpeg->width, jpeg->height);
delete[] jpeg->data;
jpeg_finish_decompress(&cinfo);
emit finishedJpeg();
delete jpeg;
delete[] rows;
}
jpeg_destroy_decompress(&cinfo);
}
......@@ -15,12 +15,39 @@
struct Jpeg
{
uint8_t *data;
int length;
int x;
int y;
uint8_t *input;
std::size_t length;
JSAMPIMAGE output;
JSAMPROW *rows;
JSAMPLE *padding;
int width;
int height;
int x;
int y;
static int y_width;
static int cb_width;
static int cr_width;
static unsigned char *y_pointer;
static unsigned char *cb_pointer;
static unsigned char *cr_pointer;
Jpeg(uint8_t *input,
const std::size_t length,
const int width,
const int height,
const int x,
const int y) : input(input), length(length), width(width), height(height), x(x), y(y)
{
}
~Jpeg()
{
std::free(input);
delete[] output;
delete[] rows;
delete[] padding;
}
};
/*!
......@@ -32,28 +59,12 @@ class JpegDecoder : public QObject
{
Q_OBJECT
public:
JpegDecoder(ConcurrentQueue<Jpeg*, 256u> *queue, QObject *parent = 0);
ConcurrentQueue<Jpeg*, 256u> *m_queue;
JpegDecoder(ConcurrentQueue<Jpeg*, 1024u> *queue, QObject *parent = 0);
ConcurrentQueue<Jpeg*, 1024u> *m_queue;
signals:
void finished(const unsigned char *image, const quint32 x, const quint32 y, const quint32 width, const quint32 height);
void finishedJpeg();
public slots:
void operate();
};
struct error_mgr
{
struct jpeg_error_mgr mgr;
jmp_buf setjmp_buffer;
};
typedef struct error_mgr* error_ptr;
METHODDEF(void)
error_exit (j_common_ptr cinfo)
{
error_ptr myerr = (error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
#endif // JPEGDECODER_H
......@@ -2,8 +2,6 @@
#include <QtQml>
#include <QQmlApplicationEngine>
QTime elapsed;
#include "qvnc.h"
int main(int argc, char *argv[])
......@@ -18,8 +16,8 @@ int main(int argc, char *argv[])
format.setMajorVersion(2);
format.setMinorVersion(0);
format.setRenderableType(QSurfaceFormat::OpenGLES);
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setSwapInterval(1);
format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
format.setSwapInterval(0);
#ifdef OGL_DEBUG
format.setOption(QSurfaceFormat::DebugContext, true);
#endif
......@@ -27,7 +25,7 @@ int main(int argc, char *argv[])
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES, true);
QGuiApplication app(argc, argv);
qmlRegisterType<QVnc>("thinclient", 1, 3, "QVnc");
qmlRegisterType<QVnc>("thinclient", 1, 4, "QVnc");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
......
import QtQuick 2.6
import QtQuick.Controls 2.0
import thinclient 1.3
import QtQuick 2.5
import QtQuick.Controls 2.1
import thinclient 1.4
ApplicationWindow {
visible: true
......@@ -27,9 +27,9 @@ ApplicationWindow {
QVnc {
id: vnc
host: "vm.ik.bme.hu"
port: 10495
port: 13070
width: 1920
height: 1080
transform: Scale {xScale: window.width / vnc.width; yScale: (window.height - tab.height) / vnc.height}
//transform: Scale {xScale: window.width / vnc.width; yScale: (window.height - tab.height) / vnc.height}
}
}
#include "qvnc.h"
QVnc::QVnc(QQuickItem *parent) :
QQuickFramebufferObject(parent), m_decoders(DECODER_COUNT), m_threads(DECODER_COUNT + 1)
QQuickFramebufferObject(parent), m_host(""), m_port(0)
{
setAcceptedMouseButtons(Qt::AllButtons);
setAcceptHoverEvents(true);
// this makes sure the rendering is called only when we explicitly ask for it
setTextureFollowsItemSize(false);
for(int i = 0; i < m_threads.length(); i++)
m_threads[i] = new QThread(this);
connect(this, &QVnc::windowChanged, this, &QVnc::winChanged);
m_uploader = new Uploader;
m_uploader->moveToThread(m_threads[0]);
connect(m_threads[0], &QThread::finished, m_uploader, &QObject::deleteLater);
connect(m_uploader, &Uploader::uploadFinished, this, &QVnc::update);
connect(&m_worker, &QThread::finished, m_uploader, &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::error, this, &QVnc::dispatch_error);
connect(&m_worker, &QThread::finished, m_dispatcher, &QObject::deleteLater);
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) {
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++;
}
m_uploader->moveToThread(&m_worker);
m_dispatcher->moveToThread(&m_worker);
for(int i = 0; i < m_threads.length(); i++)
m_threads.at(i)->start();
m_worker.start();
emit operate();
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);
}
QVnc::~QVnc()
{
foreach(QThread* t, m_threads) {
t->quit();
t->wait();
}
}
void QVnc::open()
......@@ -88,25 +67,19 @@ void QVnc::dispatch_error()
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::swapBuffers, Qt::BlockingQueuedConnection);
}
if(window != NULL)
connect(window, &QQuickWindow::openglContextCreated, m_uploader, &Uploader::createContext);
}
QQuickFramebufferObject::Renderer *QVnc::createRenderer() const
{
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());
auto renderer = new VncRenderer(window(),
m_uploader->fillBuffer(),
m_uploader->copyBuffer(),
m_uploader->bitmapBuffer(),
m_uploader->ycbcrBuffer());
connect(renderer, &VncRenderer::rendered, m_dispatcher, &Dispatcher::decode);
return renderer;
}
QString QVnc::host() const
......@@ -170,9 +143,9 @@ void QVnc::wheelEvent(QWheelEvent *event)
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) {
//if((event->timestamp() - m_lastMouseEvent) > 33) {
Qt::MouseButtons buttons = event->buttons();
m_lastMouseEvent = event->timestamp();
// m_lastMouseEvent = event->timestamp();
if(m_dispatcher->mouseEvent(event->x(),
event->y(),
buttons & Qt::LeftButton,
......@@ -183,13 +156,13 @@ void QVnc::mouseMoveEvent(QMouseEvent *event)
event->accept();
else
event->ignore();
}
//}
}
void QVnc::hoverMoveEvent(QHoverEvent *event)
{
// Qt bug: timestamp is zero for QHoverEvent
// if((event->timestamp() - m_lastMouseEvent) > 33) {
//if((event->timestamp() - m_lastMouseEvent) > 33) {
// m_lastMouseEvent = event->timestamp();
QPoint position = event->pos();
if(m_dispatcher->mouseEvent(position.x(),
......@@ -202,7 +175,7 @@ void QVnc::hoverMoveEvent(QHoverEvent *event)
event->accept();
else
event->ignore();
// }
//}
}
Uploader *QVnc::uploader() const
......
#ifndef VNC_H
#define VNC_H
#define DECODER_COUNT 5
// #define OGL_DEBUG
#define TEXTURE_WIDTH 1920
#define TEXTURE_HEIGHT 1080
#define VERTEX_BUFFER 16384
//#define OGL_DEBUG
#include <QQuickWindow>
#include <QObject>
......@@ -32,7 +33,7 @@ public:
explicit QVnc(QQuickItem *parent = Q_NULLPTR);
~QVnc();
Renderer *createRenderer() const;
Renderer *createRenderer() const override;
QString host() const;
int port() const;
Uploader *uploader() const;
......@@ -47,9 +48,7 @@ protected:
private:
Dispatcher *m_dispatcher;
Uploader *m_uploader;
QVector<JpegDecoder*> m_decoders;
VncRenderer *m_renderer;
QVector<QThread*> m_threads;
QThread m_worker;
QString m_host;
int m_port;
......@@ -64,10 +63,6 @@ signals:
void hostChanged(QString host);
void portChanged(int port);
void operate();
void refresh();
public slots:
void open();
void terminate();
......
#include "uploader.h"
#include <cstring>
#include <texturefactory.h>
#include "jpegdecoder.h"
#include <QElapsedTimer>
//QElapsedTimer timer;
Uploader::Uploader(QObject *parent) :
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)
QObject(parent), m_context(this), m_fillIndex(0), m_copyIndex(0), m_bitmapIndex(0), m_ycbcrIndex(0), m_jpegs(0), m_finished(false), m_first(true)
{
// "applications must ensure that create() is only called on the main (GUI) thread"
QSurfaceFormat format;
......@@ -24,9 +29,17 @@ Uploader::Uploader(QObject *parent) :
m_surface.setFormat(format);
m_surface.create();
m_fillCount = new unsigned int(0);
m_copyCount = new unsigned int(0);
m_bitmapCount = new unsigned int(0);
for(std::size_t i = 0; i < m_workers.size(); ++i)
{
m_decoders[i] = new JpegDecoder(&m_queue);
m_decoders[i]->moveToThread(&m_workers[i]);
connect(&m_workers[i], &QThread::finished, m_decoders[i], &QObject::deleteLater);
connect(m_decoders[i], &JpegDecoder::finishedJpeg, this, &Uploader::finishedJpeg);
connect(this, &Uploader::operate, m_decoders[i], &JpegDecoder::operate);
m_workers[i].start();
}
emit operate();
}
Uploader::~Uploader()
......@@ -53,53 +66,37 @@ void Uploader::createContext(QOpenGLContext *context)
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_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_renderTexture = &m_texId[0];
*m_uploadTexture = &m_texId[1];
m_gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
m_fillBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_fillBuffer.create();
m_fillBuffer.bind();
m_fillBuffer.allocate(VERTEX_BUFFER * sizeof(Fill));
m_copyBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_copyBuffer.create();
m_copyBuffer.bind();
m_copyBuffer.allocate(VERTEX_BUFFER * sizeof(Copy));
m_bitmapBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_bitmapBuffer.create();
m_bitmapBuffer.bind();
m_bitmapBuffer.allocate(VERTEX_BUFFER * sizeof(Bitmap));
m_ycbcrBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_ycbcrBuffer.create();
m_ycbcrBuffer.bind();
m_ycbcrBuffer.allocate(VERTEX_BUFFER * sizeof(Bitmap));
auto textureFactory = TextureFactory::create();
m_rgbTexture = textureFactory->createTexture(QSize(TEXTURE_WIDTH, TEXTURE_HEIGHT));
m_yTexture = textureFactory->createTexture(QSize(TEXTURE_WIDTH / 4, TEXTURE_HEIGHT));
m_cbTexture = textureFactory->createTexture(QSize(TEXTURE_WIDTH / 8, TEXTURE_HEIGHT));
m_crTexture = textureFactory->createTexture(QSize(TEXTURE_WIDTH / 8, TEXTURE_HEIGHT));
Jpeg::y_width = m_yTexture->allocated.width() * 4;
Jpeg::cb_width = m_cbTexture->allocated.width() * 4;
Jpeg::cr_width = m_crTexture->allocated.width() * 4;
m_gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
void Uploader::gotFill(const GLushort x, const GLushort y,
......@@ -107,10 +104,10 @@ void Uploader::gotFill(const GLushort x, const GLushort y,
const GLubyte red, const GLubyte green, const GLubyte blue)
{
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({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});
m_fillPointer[m_fillIndex++] = Fill({(GLushort) (x + width), y, red, green, blue, 0xFF});
} else {
qDebug() << "Out of memory";
}
......@@ -120,23 +117,20 @@ void Uploader::gotCopy(const GLushort src_x, const GLushort src_y,
const GLushort width, const GLushort height,
const GLushort dest_x, const GLushort dest_y)
{
if(!refreshAtlas(width, height))
return;
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});
m_copyPointer[m_copyIndex++] = Copy({src_x, (GLushort) (src_y + height), dest_x, (GLushort) (dest_y + height)});
m_copyPointer[m_copyIndex++] = Copy({src_x, src_y, dest_x, dest_y});
m_copyPointer[m_copyIndex++] = Copy({(GLushort) (src_x + width), (GLushort) (src_y + height), (GLushort) (dest_x + width), (GLushort) (dest_y + height)});
m_copyPointer[m_copyIndex++] = Copy({(GLushort) (src_x + width), src_y, (GLushort) (dest_x + width), dest_y});
} else {
qDebug() << "Out of memory";
}
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});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, (GLushort) (dest_y + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({dest_x, dest_y});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), (GLushort) (dest_y + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (dest_x + width), dest_y});
} else {
qDebug() << "Out of memory";
}
......@@ -146,50 +140,40 @@ void Uploader::gotBitmap(const unsigned char *image,
const GLushort x, const GLushort y,
const GLushort width, const GLushort height)
{
if(!refreshAtlas(width, height))
return;
m_gl->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
for (std::size_t row = 0; row < height; ++row)
std::memcpy(&m_rgbPointer[(x + (y + row) * m_rgbTexture->allocated.width()) * 4], &image[row * width * 4], width * 4);
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});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, (GLushort) (y + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({x, y});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), (GLushort) (y + height)});
m_bitmapPointer[m_bitmapIndex++] = Bitmap({(GLushort) (x + width), y});
} else {
qDebug() << "Out of memory";
}
}
void Uploader::gotJpeg()
void Uploader::gotJpeg(const uint8_t *buffer, int length, int x, int y, int width, int height)
{
m_jpegs++;
}
void Uploader::finishedJpeg(const unsigned char *image,
const GLushort x, const GLushort y,
const GLushort width, const GLushort height)
{
if(!refreshAtlas(width, height))
return;
m_jpegs--;
m_gl->glTexSubImage2D(GL_TEXTURE_2D, 0, m_atlasX, m_atlasY, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
delete[] 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});
Jpeg *jpeg = new Jpeg((unsigned char*)buffer, length, width, height, x, y);
m_queue.enqueue(jpeg);
if(m_ycbcrIndex + 4 < VERTEX_BUFFER) {
m_ycbcrPointer[m_ycbcrIndex++] = Bitmap({static_cast<GLushort>(x), static_cast<GLushort>(y + height)});
m_ycbcrPointer[m_ycbcrIndex++] = Bitmap({static_cast<GLushort>(x), static_cast<GLushort>(y)});
m_ycbcrPointer[m_ycbcrIndex++] = Bitmap({static_cast<GLushort>(x + width), static_cast<GLushort>(y + height)});
m_ycbcrPointer[m_ycbcrIndex++] = Bitmap({static_cast<GLushort>(x + width), static_cast<GLushort>(y)});
} else {
qDebug() << "Out of memory";
}
if(m_jpegs == 0)
qDebug() << "jpeg" << elapsed.elapsed();
m_jpegs++;
}
void Uploader::finishedJpeg()
{
//qDebug() << "jpeg" << timer.elapsed();
m_jpegs--;
if(m_jpegs == 0 && m_finished) {
startRendering();
}
......@@ -197,129 +181,77 @@ void Uploader::finishedJpeg(const unsigned char *image,
void Uploader::finishedUpdate()
{
//qDebug() << "finished" << timer.elapsed();
m_finished = true;
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() << "Atlas out of memory" << m_atlasX << m_atlasY << width << height;
return false;
}
m_atlasX += m_atlasLastWidth;
m_atlasLastWidth = width;
if(height > m_atlasRowHeight)
m_atlasRowHeight = height;
} else {
if(m_atlasY + m_atlasRowHeight + height > TEXTURE_HEIGHT) {
qDebug() << "Atlas out of memory" << m_atlasX << m_atlasY << width << height;
return false;
}
m_atlasX = 0;
m_atlasY += m_atlasRowHeight;
m_atlasRowHeight = height;
m_atlasLastWidth = width;
}
return true;
}
void Uploader::startDecoding()
{
(*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);
//timer.start();
if (m_fillIndex > 0 || m_first)
{
m_fillBuffer.bind();
m_fillPointer = (Fill*) m_fillBuffer.map(QOpenGLBuffer::WriteOnly);
}
if (m_copyIndex > 0 || m_first)
{
m_copyBuffer.bind();
m_copyPointer = (Copy*) m_copyBuffer.map(QOpenGLBuffer::WriteOnly);
}
if (m_bitmapIndex > 0 || m_first)
{
m_bitmapBuffer.bind();
m_bitmapPointer = (Bitmap*) m_bitmapBuffer.map(QOpenGLBuffer::WriteOnly);
m_rgbPointer = static_cast<unsigned char*>(m_rgbTexture->map());
}
if (m_ycbcrIndex > 0 || m_first)
{
m_ycbcrBuffer.bind();
m_ycbcrPointer = (Bitmap*) m_ycbcrBuffer.map(QOpenGLBuffer::WriteOnly);
Jpeg::y_pointer = static_cast<unsigned char*>(m_yTexture->map());
Jpeg::cb_pointer = static_cast<unsigned char*>(m_cbTexture->map());
Jpeg::cr_pointer = static_cast<unsigned char*>(m_crTexture->map());
}
m_fillIndex = 0;
m_copyIndex = 0;
m_bitmapIndex = 0;
m_ycbcrIndex = 0;
m_atlasX = 1;
m_atlasY = 1;
m_atlasRowHeight = 0;
m_atlasLastWidth = 0;
elapsed.restart();
}
void Uploader::startRendering()
{
(*m_uploadFill)->bind();
(*m_uploadFill)->unmap();
(*m_uploadCopy)->bind();
(*m_uploadCopy)->unmap();
(*m_uploadBitmap)->bind();
(*m_uploadBitmap)->unmap();
qDebug() << "rendering" << elapsed.elapsed();
m_gl->glFlush();
m_first = false;
m_finished = false;
m_swap = true;
qDebug() << "flush" << elapsed.elapsed();
emit uploadFinished();
m_jpegs = 0;
}
void Uploader::swapBuffers()
void Uploader::startRendering()
{
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();
if (m_fillIndex > 0)
{
m_fillBuffer.bind();
m_fillBuffer.unmap();
}
}
GLuint **Uploader::texture() const
{
return m_renderTexture;
}
QOpenGLBuffer **Uploader::fillBuffer() const
{
return m_renderFill;
}
QOpenGLBuffer **Uploader::copyBuffer() const
{
return m_renderCopy;
}
QOpenGLBuffer **Uploader::bitmapBuffer() const
{
return m_renderBitmap;
}
unsigned int *Uploader::fillCount() const
{
return m_fillCount;
}
unsigned int *Uploader::copyCount() const
{
return m_copyCount;
}
if (m_copyIndex > 0)
{
m_copyBuffer.bind();
m_copyBuffer.unmap();
}
if (m_bitmapIndex > 0)
{
m_bitmapBuffer.bind();
m_bitmapBuffer.unmap();
m_rgbTexture->unmap();
}
if (m_ycbcrIndex > 0)
{
m_ycbcrBuffer.bind();
m_ycbcrBuffer.unmap();
m_yTexture->unmap();
m_cbTexture->unmap();
m_crTexture->unmap();
}
//qDebug() << "uploaded" << timer.elapsed();
unsigned int *Uploader::bitmapCount() const
{
return m_bitmapCount;
emit uploadFinished();
}
......@@ -16,12 +16,13 @@
#ifndef UPLOADER_H
#define UPLOADER_H
#define TEXTURE_WIDTH 4096
#define TEXTURE_HEIGHT 4096
#define VERTEX_BUFFER 1024
// #define OGL_DEBUG
#define TEXTURE_WIDTH 1920
#define TEXTURE_HEIGHT 1080
#define VERTEX_BUFFER 16384
//#define OGL_DEBUG
#include <utility>
#include <memory>
#include <QObject>
#include <QDebug>
......@@ -33,15 +34,26 @@
#include <QtMath>
#include <QTime>
#include <QOpenGLDebugLogger>
#include <QThread>
extern QTime elapsed;
#include <texture.h>
#include "concurrentqueue.h"
#define DECODER_COUNT 5
struct Bitmap
{
GLushort x;
GLushort y;
GLushort texX;
GLushort texY;
};
struct Copy
{
GLushort src_x;
GLushort src_y;
GLushort dest_x;
GLushort dest_y;
};
struct Fill
......@@ -54,6 +66,9 @@ struct Fill
GLubyte alpha;
};
class JpegDecoder;
class Jpeg;
/*!
* \brief The Uploader class
*
......@@ -63,17 +78,22 @@ class Uploader : public QObject
{
Q_OBJECT
public:
Uploader(QObject *parent = Q_NULLPTR);
explicit Uploader(QObject *parent = Q_NULLPTR);
~Uploader();
GLuint **texture() const;
QOpenGLBuffer **fillBuffer() const;
QOpenGLBuffer **copyBuffer() const;
QOpenGLBuffer **bitmapBuffer() const;
unsigned int *fillCount() const;
unsigned int *copyCount() const;
unsigned int *bitmapCount() const;
void swapBuffers();
// might as well make these public, they are shared with the renderer
std::shared_ptr<Texture> rgbTexture() const {return m_rgbTexture;}
std::shared_ptr<Texture> yTexture() const {return m_yTexture;}
std::shared_ptr<Texture> cbTexture() const {return m_cbTexture;}
std::shared_ptr<Texture> crTexture() const {return m_crTexture;}
QOpenGLBuffer fillBuffer() const {return m_fillBuffer;}
QOpenGLBuffer copyBuffer() const {return m_copyBuffer;}
QOpenGLBuffer bitmapBuffer() const {return m_bitmapBuffer;}
QOpenGLBuffer ycbcrBuffer() const {return m_ycbcrBuffer;}
std::size_t fillCount() const {return m_fillIndex;}
std::size_t copyCount() const {return m_copyIndex;}
std::size_t bitmapCount() const {return m_bitmapIndex;}
std::size_t ycbcrCount() const {return m_ycbcrIndex;}
// VNC events
void gotFill(const GLushort x, const GLushort y,
......@@ -85,56 +105,55 @@ public:
void gotBitmap(const unsigned char *image,
const GLushort x, const GLushort y,
const GLushort width, const GLushort height);
void gotJpeg();
void gotJpeg(const uint8_t *buffer, int length, int x, int y, int width, int height);
void finishedUpdate();
void startDecoding();
private:
QOffscreenSurface m_surface;
QOpenGLContext m_context;
QOpenGLFunctions *m_gl;
QOpenGLBuffer **m_uploadFill;
QOpenGLBuffer **m_renderFill;
QOpenGLBuffer m_fillBuffer;
Fill *m_fillPointer;
size_t m_fillIndex;
unsigned int *m_fillCount;
std::size_t m_fillIndex;
QOpenGLBuffer **m_uploadCopy;
QOpenGLBuffer **m_renderCopy;
Bitmap *m_copyPointer;
size_t m_copyIndex;
unsigned int *m_copyCount;
QOpenGLBuffer m_copyBuffer;
Copy *m_copyPointer;
std::size_t m_copyIndex;
QOpenGLBuffer **m_uploadBitmap;
QOpenGLBuffer **m_renderBitmap;
QOpenGLBuffer m_bitmapBuffer;
Bitmap *m_bitmapPointer;
size_t m_bitmapIndex;
unsigned int *m_bitmapCount;
std::size_t m_bitmapIndex;
std::shared_ptr<Texture> m_rgbTexture;
unsigned char *m_rgbPointer;
QOpenGLBuffer m_ycbcrBuffer;
Bitmap *m_ycbcrPointer;
std::size_t m_ycbcrIndex;
GLuint m_texId[2];
GLuint **m_uploadTexture;
GLuint **m_renderTexture;
std::shared_ptr<Texture> m_yTexture;
std::shared_ptr<Texture> m_cbTexture;
std::shared_ptr<Texture> m_crTexture;
std::array<QThread, DECODER_COUNT> m_workers;
std::array<JpegDecoder*, DECODER_COUNT> m_decoders;
ConcurrentQueue<Jpeg*, 1024u> m_queue;
int m_jpegs;
bool m_finished;
bool m_swap;
unsigned short m_atlasX;
unsigned short m_atlasY;
unsigned short m_atlasRowHeight;
unsigned short m_atlasLastWidth;
bool refreshAtlas(const int width, const int height);
bool m_first;
void startRendering();
signals:
void uploadFinished();
void buffersSwapped();
void operate();
public slots:
void createContext(QOpenGLContext *context);
void finishedJpeg(const unsigned char *image,
const GLushort x, const GLushort y,
const GLushort width, const GLushort height);
void finishedJpeg();
private slots:
void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
};
......
......@@ -3,20 +3,14 @@
#include "uploader.h"
VncRenderer::VncRenderer(QQuickWindow *window,
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) :
QOpenGLBuffer fillBuffer,
QOpenGLBuffer copyBuffer,
QOpenGLBuffer bitmapBuffer,
QOpenGLBuffer ycbcrBuffer,
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_fillBuffer(fillBuffer), m_copyBuffer(copyBuffer), m_bitmapBuffer(bitmapBuffer), m_ycbcrBuffer(ycbcrBuffer),
m_fillCount(0), m_copyCount(0), m_bitmapCount(0), m_ycbcrCount(0),
m_indices(QOpenGLBuffer::IndexBuffer)
{
#ifdef OGL_DEBUG
......@@ -26,33 +20,49 @@ VncRenderer::VncRenderer(QQuickWindow *window,
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_toTexture.ortho(QRect(QPoint(0, TEXTURE_HEIGHT), QSize(TEXTURE_WIDTH, -1 * TEXTURE_HEIGHT)));
m_fromTexture.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_copyProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "/home/ldmnyblzs/Projects/ThinClient/copy_shader.vsh");
m_copyProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "/home/ldmnyblzs/Projects/ThinClient/copy_shader.fsh");
m_copyProgram.bind();
m_copyProgram.setUniformValue("trgortho", m_toTexture);
m_copyProgram.setUniformValue("texture", 0);
m_copyProgram.release();
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_bitmapProgram.bind();
m_bitmapProgram.setUniformValue("texture", 1);
m_bitmapProgram.setUniformValue("texortho", m_fromTexture);
m_bitmapProgram.release();
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_ycbcrProgram.setUniformValue("cr_texture", 4);
m_ycbcrProgram.setUniformValue("texortho", m_fromTexture);
m_ycbcrProgram.release();
m_indices.create();
m_indices.bind();
m_indices.allocate(ind.i, (VERTEX_BUFFER / 4) * 6 - 2);
m_indices.release();
m_gl = QOpenGLContext::currentContext()->functions();
m_gl->glGenFramebuffers(0, &m_textureTarget);
m_gl->glGenFramebuffers(1, &m_textureTarget);
m_clear = true;
frameCount = 0;
frameTime.start();
}
......@@ -63,12 +73,25 @@ void VncRenderer::handleDebugMessage(const QOpenGLDebugMessage &debugMessage)
void VncRenderer::render()
{
frameCount++;
if(frameTime.elapsed() > 1000) {
// qDebug() << frameCount;
if (m_clear)
{
m_gl->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
m_gl->glClear(GL_COLOR_BUFFER_BIT);
m_clear = false;
}
if(m_fillCount > 0 || m_bitmapCount > 0 || m_ycbcrCount > 0)
{
//frameCount++;
}
else
return;
/*if(frameTime.elapsed() > 1000) {
qDebug() << frameCount;
frameCount = 0;
frameTime.restart();
}
}*/
/* Rendering:
* 1. Draw filled rectangles
......@@ -77,136 +100,170 @@ void VncRenderer::render()
* 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) {
if(m_fillCount > 0) {
m_fillProgram.bind();
m_fillBuffer.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);
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Fill),
NULL);
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);
}
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
sizeof(Fill),
reinterpret_cast<void*>(2 * sizeof(GLushort)));
if(*m_bitmapCount > 0) {
m_bitmapProgram.bind();
m_bitmapProgram.enableAttributeArray("position");
m_bitmapProgram.enableAttributeArray("texcoord");
m_gl->glDrawElements(GL_TRIANGLE_STRIP, m_fillCount, GL_UNSIGNED_SHORT, NULL);
m_fillBuffer.release();
m_fillProgram.release();
}
if(*m_copyCount > 0) {
(*m_copyBuffer)->bind();
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("position"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Bitmap),
(void*) 0);
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("texcoord"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Bitmap),
(void*) (2 * sizeof(GLushort)));
// copy to the texture
if(m_copyCount > 0) {
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_copyProgram.bind();
m_copyBuffer.bind();
m_copyProgram.enableAttributeArray("source");
m_copyProgram.enableAttributeArray("target");
m_gl->glVertexAttribPointer(m_copyProgram.attributeLocation("source"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Copy),
NULL);
m_gl->glVertexAttribPointer(m_copyProgram.attributeLocation("target"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
sizeof(Copy),
reinterpret_cast<void*>(2 * sizeof(GLushort)));
m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_textureTarget);
m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, **m_rgbTexture, 0);
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_gl->glDrawElements(GL_TRIANGLE_STRIP, m_copyCount, GL_UNSIGNED_SHORT, NULL);
m_framebufferObject->bind();
m_gl->glViewport(0, 0, 1920, 1080);
m_copyBuffer.release();
m_copyProgram.release();
}
if(*m_bitmapCount > 0) {
// rgb
(*m_bitmapBuffer)->bind();
if(m_bitmapCount > 0) {
m_rgbTexture->bind(GL_TEXTURE1);
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_bitmapProgram.bind();
m_bitmapBuffer.bind();
m_bitmapProgram.enableAttributeArray("position");
m_gl->glVertexAttribPointer(m_bitmapProgram.attributeLocation("position"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
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);
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
0,
NULL);
m_gl->glDrawElements(GL_TRIANGLE_STRIP, m_bitmapCount, GL_UNSIGNED_SHORT, NULL);
m_bitmapBuffer.release();
m_bitmapProgram.release();
}
*m_fillCount = 0;
*m_copyCount = 0;
*m_bitmapCount = 0;
if(m_ycbcrCount > 0) {
m_yTexture->bind(GL_TEXTURE2);
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);
update();
m_crTexture->bind(GL_TEXTURE3);
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_cbTexture->bind(GL_TEXTURE4);
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_ycbcrProgram.bind();
m_ycbcrBuffer.bind();
m_ycbcrProgram.enableAttributeArray("position");
m_gl->glVertexAttribPointer(m_ycbcrProgram.attributeLocation("position"),
2,
GL_UNSIGNED_SHORT,
GL_FALSE,
0,
NULL);
m_gl->glDrawElements(GL_TRIANGLE_STRIP, m_ycbcrCount, GL_UNSIGNED_SHORT, NULL);
m_ycbcrBuffer.release();
m_ycbcrProgram.release();
}
m_indices.release();
m_window->resetOpenGLState();
emit rendered();
}
void VncRenderer::synchronize(QQuickFramebufferObject *fbo)
{
auto qvnc = static_cast<QVnc*>(fbo);
auto uploader = qvnc->uploader();
m_fillCount = std::max(uploader->fillCount() / 4 * 6, 2uL) - 2;
m_copyCount = std::max(uploader->copyCount() / 4 * 6, 2uL) - 2;
m_bitmapCount = std::max(uploader->bitmapCount() / 4 * 6, 2uL) - 2;
m_ycbcrCount = std::max(uploader->ycbcrCount() / 4 * 6, 2uL) - 2;
// query until it is finally set
if (m_rgbTexture.get() == nullptr)
{
m_rgbTexture = uploader->rgbTexture();
m_yTexture = uploader->yTexture();
m_cbTexture = uploader->cbTexture();
m_crTexture = uploader->crTexture();
}
}
QOpenGLFramebufferObject *VncRenderer::createFramebufferObject(const QSize &size)
{
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())));
m_toFramebuffer.ortho(QRect(QPoint(0, size.height()), QSize(size.width(), -1 * size.height())));
m_fromFramebuffer.ortho(QRect(QPoint(-1 * size.width(), size.height()), QSize(2 * size.width(), -2 * size.height())));
m_fillProgram.bind();
m_fillProgram.setUniformValue("ortho", m_toFramebuffer);
m_fillProgram.release();
m_copyProgram.bind();
m_copyProgram.setUniformValue("srcortho", m_fromFramebuffer);
m_copyProgram.release();
m_bitmapProgram.bind();
m_bitmapProgram.setUniformValue("ortho", m_toFramebuffer);
m_bitmapProgram.release();
m_ycbcrProgram.bind();
m_ycbcrProgram.setUniformValue("ortho", m_toFramebuffer);
m_ycbcrProgram.release();
m_framebufferObject = new QOpenGLFramebufferObject(size);
return m_framebufferObject;
return (m_framebufferObject = new QOpenGLFramebufferObject(size));
}
#ifndef VNCRENDERER_H
#define VNCRENDERER_H
#include <memory>
#include <QQuickWindow>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
......@@ -11,6 +12,8 @@
#include <QOpenGLBuffer>
#include <QTime>
#include <texture.h>
#include "qvnc.h"
struct Indices
......@@ -35,54 +38,56 @@ class VncRenderer : public QObject, public QQuickFramebufferObject::Renderer
Q_OBJECT
public:
VncRenderer(QQuickWindow *window,
QOpenGLBuffer **fillBuffer,
QOpenGLBuffer **copyBuffer,
QOpenGLBuffer **bitmapBuffer,
GLuint **rgbTexture,
GLuint **yTexture,
GLuint **cbTexture,
GLuint **crTexture,
unsigned int *fillCount,
unsigned int *copyCount,
unsigned int *bitmapCount,
QOpenGLBuffer fillBuffer,
QOpenGLBuffer copyBuffer,
QOpenGLBuffer bitmapBuffer,
QOpenGLBuffer ycbcrBuffer,
QObject *parent = nullptr);
protected:
void render() override;
void synchronize(QQuickFramebufferObject *fbo) override;
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
private:
QQuickWindow *m_window;
QMatrix4x4 m_copyOrtho;
QMatrix4x4 m_copyTexortho;
QMatrix4x4 m_bitmapOrtho;
QMatrix4x4 m_bitmapTexortho;
QMatrix4x4 m_fromTexture;
QMatrix4x4 m_toFramebuffer;
QMatrix4x4 m_fromFramebuffer;
QMatrix4x4 m_toTexture;
QOpenGLBuffer **m_fillBuffer;
QOpenGLBuffer **m_copyBuffer;
QOpenGLBuffer **m_bitmapBuffer;
QOpenGLBuffer m_fillBuffer;
QOpenGLBuffer m_copyBuffer;
QOpenGLBuffer m_bitmapBuffer;
QOpenGLBuffer m_ycbcrBuffer;
GLuint **m_rgbTexture;
GLuint **m_yTexture;
GLuint **m_cbTexture;
GLuint **m_crTexture;
std::shared_ptr<Texture> m_rgbTexture;
std::shared_ptr<Texture> m_yTexture;
std::shared_ptr<Texture> m_cbTexture;
std::shared_ptr<Texture> m_crTexture;
unsigned int *m_fillCount;
unsigned int *m_copyCount;
unsigned int *m_bitmapCount;
unsigned int m_fillCount;
unsigned int m_copyCount;
unsigned int m_bitmapCount;
unsigned int m_ycbcrCount;
QOpenGLBuffer m_indices;
QOpenGLShaderProgram m_fillProgram;
QOpenGLShaderProgram m_bitmapProgram;
QOpenGLShaderProgram m_ycbcrProgram;
QOpenGLShaderProgram m_copyProgram;
GLuint m_textureTarget;
QOpenGLFunctions *m_gl;
QOpenGLFramebufferObject *m_framebufferObject;
bool m_clear;
int frameCount;
QTime frameTime;
private slots:
void handleDebugMessage(const QOpenGLDebugMessage &debugMessage);
signals:
void rendered();
};
#endif // VNCRENDERER_H
uniform sampler2D y_texture;
uniform sampler2D cb_texture;
uniform sampler2D cr_texture;
varying highp vec2 vartexcoord;
varying highp float vartexindex;
void main(void)
{
highp float Y;
highp float Cb;
highp float Cr;
highp float pos = mod((gl_FragCoord.x - 0.5), 4.0);
if(pos < 1.0) {
Y = texture2D(y_texture, vartexcoord).r;
Cb = texture2D(cb_texture, vartexcoord).r;
Cr = texture2D(cr_texture, vartexcoord).r;
} else if(pos < 2.0) {
Y = texture2D(y_texture, vartexcoord).g;
Cb = texture2D(cb_texture, vartexcoord).g;
Cr = texture2D(cr_texture, vartexcoord).g;
} else if(pos < 3.0) {
Y = texture2D(y_texture, vartexcoord).b;
Cb = texture2D(cb_texture, vartexcoord).b;
Cr = texture2D(cr_texture, vartexcoord).b;
} else {
Y = texture2D(y_texture, vartexcoord).a;
Cb = texture2D(cb_texture, vartexcoord).a;
Cr = texture2D(cr_texture, vartexcoord).a;
}
highp float R = Y + 1.402 * (Cr - 0.5);
highp float G = Y - 0.34414 * (Cb - 0.5) - 0.71414 * (Cr - 0.5);
highp float B = Y + 1.772 * (Cb - 0.5);
gl_FragColor = vec4(B, G, R, 1.0);
}
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