You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EncodeManager.cxx 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
  3. * Copyright 2014-2018 Pierre Ossman for Cendio AB
  4. * Copyright 2018 Peter Astrand for Cendio AB
  5. *
  6. * This is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This software is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this software; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  19. * USA.
  20. */
  21. #include <stdlib.h>
  22. #include <rfb/EncodeManager.h>
  23. #include <rfb/Encoder.h>
  24. #include <rfb/Palette.h>
  25. #include <rfb/SConnection.h>
  26. #include <rfb/SMsgWriter.h>
  27. #include <rfb/UpdateTracker.h>
  28. #include <rfb/LogWriter.h>
  29. #include <rfb/Exception.h>
  30. #include <rfb/RawEncoder.h>
  31. #include <rfb/RREEncoder.h>
  32. #include <rfb/HextileEncoder.h>
  33. #include <rfb/ZRLEEncoder.h>
  34. #include <rfb/TightEncoder.h>
  35. #include <rfb/TightJPEGEncoder.h>
  36. using namespace rfb;
  37. static LogWriter vlog("EncodeManager");
  38. // Split each rectangle into smaller ones no larger than this area,
  39. // and no wider than this width.
  40. static const int SubRectMaxArea = 65536;
  41. static const int SubRectMaxWidth = 2048;
  42. // The size in pixels of either side of each block tested when looking
  43. // for solid blocks.
  44. static const int SolidSearchBlock = 16;
  45. // Don't bother with blocks smaller than this
  46. static const int SolidBlockMinArea = 2048;
  47. // How long we consider a region recently changed (in ms)
  48. static const int RecentChangeTimeout = 50;
  49. namespace rfb {
  50. enum EncoderClass {
  51. encoderRaw,
  52. encoderRRE,
  53. encoderHextile,
  54. encoderTight,
  55. encoderTightJPEG,
  56. encoderZRLE,
  57. encoderClassMax,
  58. };
  59. enum EncoderType {
  60. encoderSolid,
  61. encoderBitmap,
  62. encoderBitmapRLE,
  63. encoderIndexed,
  64. encoderIndexedRLE,
  65. encoderFullColour,
  66. encoderTypeMax,
  67. };
  68. struct RectInfo {
  69. int rleRuns;
  70. Palette palette;
  71. };
  72. };
  73. static const char *encoderClassName(EncoderClass klass)
  74. {
  75. switch (klass) {
  76. case encoderRaw:
  77. return "Raw";
  78. case encoderRRE:
  79. return "RRE";
  80. case encoderHextile:
  81. return "Hextile";
  82. case encoderTight:
  83. return "Tight";
  84. case encoderTightJPEG:
  85. return "Tight (JPEG)";
  86. case encoderZRLE:
  87. return "ZRLE";
  88. case encoderClassMax:
  89. break;
  90. }
  91. return "Unknown Encoder Class";
  92. }
  93. static const char *encoderTypeName(EncoderType type)
  94. {
  95. switch (type) {
  96. case encoderSolid:
  97. return "Solid";
  98. case encoderBitmap:
  99. return "Bitmap";
  100. case encoderBitmapRLE:
  101. return "Bitmap RLE";
  102. case encoderIndexed:
  103. return "Indexed";
  104. case encoderIndexedRLE:
  105. return "Indexed RLE";
  106. case encoderFullColour:
  107. return "Full Colour";
  108. case encoderTypeMax:
  109. break;
  110. }
  111. return "Unknown Encoder Type";
  112. }
  113. EncodeManager::EncodeManager(SConnection* conn_)
  114. : conn(conn_), recentChangeTimer(this)
  115. {
  116. StatsVector::iterator iter;
  117. encoders.resize(encoderClassMax, NULL);
  118. activeEncoders.resize(encoderTypeMax, encoderRaw);
  119. encoders[encoderRaw] = new RawEncoder(conn);
  120. encoders[encoderRRE] = new RREEncoder(conn);
  121. encoders[encoderHextile] = new HextileEncoder(conn);
  122. encoders[encoderTight] = new TightEncoder(conn);
  123. encoders[encoderTightJPEG] = new TightJPEGEncoder(conn);
  124. encoders[encoderZRLE] = new ZRLEEncoder(conn);
  125. updates = 0;
  126. memset(&copyStats, 0, sizeof(copyStats));
  127. stats.resize(encoderClassMax);
  128. for (iter = stats.begin();iter != stats.end();++iter) {
  129. StatsVector::value_type::iterator iter2;
  130. iter->resize(encoderTypeMax);
  131. for (iter2 = iter->begin();iter2 != iter->end();++iter2)
  132. memset(&*iter2, 0, sizeof(EncoderStats));
  133. }
  134. }
  135. EncodeManager::~EncodeManager()
  136. {
  137. std::vector<Encoder*>::iterator iter;
  138. logStats();
  139. for (iter = encoders.begin();iter != encoders.end();iter++)
  140. delete *iter;
  141. }
  142. void EncodeManager::logStats()
  143. {
  144. size_t i, j;
  145. unsigned rects;
  146. unsigned long long pixels, bytes, equivalent;
  147. double ratio;
  148. char a[1024], b[1024];
  149. rects = 0;
  150. pixels = bytes = equivalent = 0;
  151. vlog.info("Framebuffer updates: %u", updates);
  152. if (copyStats.rects != 0) {
  153. vlog.info(" %s:", "CopyRect");
  154. rects += copyStats.rects;
  155. pixels += copyStats.pixels;
  156. bytes += copyStats.bytes;
  157. equivalent += copyStats.equivalent;
  158. ratio = (double)copyStats.equivalent / copyStats.bytes;
  159. siPrefix(copyStats.rects, "rects", a, sizeof(a));
  160. siPrefix(copyStats.pixels, "pixels", b, sizeof(b));
  161. vlog.info(" %s: %s, %s", "Copies", a, b);
  162. iecPrefix(copyStats.bytes, "B", a, sizeof(a));
  163. vlog.info(" %*s %s (1:%g ratio)",
  164. (int)strlen("Copies"), "",
  165. a, ratio);
  166. }
  167. for (i = 0;i < stats.size();i++) {
  168. // Did this class do anything at all?
  169. for (j = 0;j < stats[i].size();j++) {
  170. if (stats[i][j].rects != 0)
  171. break;
  172. }
  173. if (j == stats[i].size())
  174. continue;
  175. vlog.info(" %s:", encoderClassName((EncoderClass)i));
  176. for (j = 0;j < stats[i].size();j++) {
  177. if (stats[i][j].rects == 0)
  178. continue;
  179. rects += stats[i][j].rects;
  180. pixels += stats[i][j].pixels;
  181. bytes += stats[i][j].bytes;
  182. equivalent += stats[i][j].equivalent;
  183. ratio = (double)stats[i][j].equivalent / stats[i][j].bytes;
  184. siPrefix(stats[i][j].rects, "rects", a, sizeof(a));
  185. siPrefix(stats[i][j].pixels, "pixels", b, sizeof(b));
  186. vlog.info(" %s: %s, %s", encoderTypeName((EncoderType)j), a, b);
  187. iecPrefix(stats[i][j].bytes, "B", a, sizeof(a));
  188. vlog.info(" %*s %s (1:%g ratio)",
  189. (int)strlen(encoderTypeName((EncoderType)j)), "",
  190. a, ratio);
  191. }
  192. }
  193. ratio = (double)equivalent / bytes;
  194. siPrefix(rects, "rects", a, sizeof(a));
  195. siPrefix(pixels, "pixels", b, sizeof(b));
  196. vlog.info(" Total: %s, %s", a, b);
  197. iecPrefix(bytes, "B", a, sizeof(a));
  198. vlog.info(" %s (1:%g ratio)", a, ratio);
  199. }
  200. bool EncodeManager::supported(int encoding)
  201. {
  202. switch (encoding) {
  203. case encodingRaw:
  204. case encodingRRE:
  205. case encodingHextile:
  206. case encodingZRLE:
  207. case encodingTight:
  208. return true;
  209. default:
  210. return false;
  211. }
  212. }
  213. bool EncodeManager::needsLosslessRefresh(const Region& req)
  214. {
  215. return !lossyRegion.intersect(req).is_empty();
  216. }
  217. int EncodeManager::getNextLosslessRefresh(const Region& req)
  218. {
  219. // Do we have something we can send right away?
  220. if (!pendingRefreshRegion.intersect(req).is_empty())
  221. return 0;
  222. assert(needsLosslessRefresh(req));
  223. assert(recentChangeTimer.isStarted());
  224. return recentChangeTimer.getNextTimeout();
  225. }
  226. void EncodeManager::pruneLosslessRefresh(const Region& limits)
  227. {
  228. lossyRegion.assign_intersect(limits);
  229. pendingRefreshRegion.assign_intersect(limits);
  230. }
  231. void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
  232. const RenderedCursor* renderedCursor)
  233. {
  234. doUpdate(true, ui.changed, ui.copied, ui.copy_delta, pb, renderedCursor);
  235. recentlyChangedRegion.assign_union(ui.changed);
  236. recentlyChangedRegion.assign_union(ui.copied);
  237. if (!recentChangeTimer.isStarted())
  238. recentChangeTimer.start(RecentChangeTimeout);
  239. }
  240. void EncodeManager::writeLosslessRefresh(const Region& req, const PixelBuffer* pb,
  241. const RenderedCursor* renderedCursor,
  242. size_t maxUpdateSize)
  243. {
  244. doUpdate(false, getLosslessRefresh(req, maxUpdateSize),
  245. Region(), Point(), pb, renderedCursor);
  246. }
  247. bool EncodeManager::handleTimeout(Timer* t)
  248. {
  249. if (t == &recentChangeTimer) {
  250. // Any lossy region that wasn't recently updated can
  251. // now be scheduled for a refresh
  252. pendingRefreshRegion.assign_union(lossyRegion.subtract(recentlyChangedRegion));
  253. recentlyChangedRegion.clear();
  254. // Will there be more to do? (i.e. do we need another round)
  255. if (!lossyRegion.subtract(pendingRefreshRegion).is_empty())
  256. return true;
  257. }
  258. return false;
  259. }
  260. void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
  261. const Region& copied, const Point& copyDelta,
  262. const PixelBuffer* pb,
  263. const RenderedCursor* renderedCursor)
  264. {
  265. int nRects;
  266. Region changed, cursorRegion;
  267. updates++;
  268. prepareEncoders(allowLossy);
  269. changed = changed_;
  270. if (!conn->client.supportsEncoding(encodingCopyRect))
  271. changed.assign_union(copied);
  272. /*
  273. * We need to render the cursor seperately as it has its own
  274. * magical pixel buffer, so split it out from the changed region.
  275. */
  276. if (renderedCursor != NULL) {
  277. cursorRegion = changed.intersect(renderedCursor->getEffectiveRect());
  278. changed.assign_subtract(renderedCursor->getEffectiveRect());
  279. }
  280. if (conn->client.supportsEncoding(pseudoEncodingLastRect))
  281. nRects = 0xFFFF;
  282. else {
  283. nRects = 0;
  284. if (conn->client.supportsEncoding(encodingCopyRect))
  285. nRects += copied.numRects();
  286. nRects += computeNumRects(changed);
  287. nRects += computeNumRects(cursorRegion);
  288. }
  289. conn->writer()->writeFramebufferUpdateStart(nRects);
  290. if (conn->client.supportsEncoding(encodingCopyRect))
  291. writeCopyRects(copied, copyDelta);
  292. /*
  293. * We start by searching for solid rects, which are then removed
  294. * from the changed region.
  295. */
  296. if (conn->client.supportsEncoding(pseudoEncodingLastRect))
  297. writeSolidRects(&changed, pb);
  298. writeRects(changed, pb);
  299. writeRects(cursorRegion, renderedCursor);
  300. conn->writer()->writeFramebufferUpdateEnd();
  301. }
  302. void EncodeManager::prepareEncoders(bool allowLossy)
  303. {
  304. enum EncoderClass solid, bitmap, bitmapRLE;
  305. enum EncoderClass indexed, indexedRLE, fullColour;
  306. bool allowJPEG;
  307. rdr::S32 preferred;
  308. std::vector<int>::iterator iter;
  309. solid = bitmap = bitmapRLE = encoderRaw;
  310. indexed = indexedRLE = fullColour = encoderRaw;
  311. allowJPEG = conn->client.pf().bpp >= 16;
  312. if (!allowLossy) {
  313. if (encoders[encoderTightJPEG]->losslessQuality == -1)
  314. allowJPEG = false;
  315. }
  316. // Try to respect the client's wishes
  317. preferred = conn->getPreferredEncoding();
  318. switch (preferred) {
  319. case encodingRRE:
  320. // Horrible for anything high frequency and/or lots of colours
  321. bitmapRLE = indexedRLE = encoderRRE;
  322. break;
  323. case encodingHextile:
  324. // Slightly less horrible
  325. bitmapRLE = indexedRLE = fullColour = encoderHextile;
  326. break;
  327. case encodingTight:
  328. if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
  329. fullColour = encoderTightJPEG;
  330. else
  331. fullColour = encoderTight;
  332. indexed = indexedRLE = encoderTight;
  333. bitmap = bitmapRLE = encoderTight;
  334. break;
  335. case encodingZRLE:
  336. fullColour = encoderZRLE;
  337. bitmapRLE = indexedRLE = encoderZRLE;
  338. bitmap = indexed = encoderZRLE;
  339. break;
  340. }
  341. // Any encoders still unassigned?
  342. if (fullColour == encoderRaw) {
  343. if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
  344. fullColour = encoderTightJPEG;
  345. else if (encoders[encoderZRLE]->isSupported())
  346. fullColour = encoderZRLE;
  347. else if (encoders[encoderTight]->isSupported())
  348. fullColour = encoderTight;
  349. else if (encoders[encoderHextile]->isSupported())
  350. fullColour = encoderHextile;
  351. }
  352. if (indexed == encoderRaw) {
  353. if (encoders[encoderZRLE]->isSupported())
  354. indexed = encoderZRLE;
  355. else if (encoders[encoderTight]->isSupported())
  356. indexed = encoderTight;
  357. else if (encoders[encoderHextile]->isSupported())
  358. indexed = encoderHextile;
  359. }
  360. if (indexedRLE == encoderRaw)
  361. indexedRLE = indexed;
  362. if (bitmap == encoderRaw)
  363. bitmap = indexed;
  364. if (bitmapRLE == encoderRaw)
  365. bitmapRLE = bitmap;
  366. if (solid == encoderRaw) {
  367. if (encoders[encoderTight]->isSupported())
  368. solid = encoderTight;
  369. else if (encoders[encoderRRE]->isSupported())
  370. solid = encoderRRE;
  371. else if (encoders[encoderZRLE]->isSupported())
  372. solid = encoderZRLE;
  373. else if (encoders[encoderHextile]->isSupported())
  374. solid = encoderHextile;
  375. }
  376. // JPEG is the only encoder that can reduce things to grayscale
  377. if ((conn->client.subsampling == subsampleGray) &&
  378. encoders[encoderTightJPEG]->isSupported() && allowLossy) {
  379. solid = bitmap = bitmapRLE = encoderTightJPEG;
  380. indexed = indexedRLE = fullColour = encoderTightJPEG;
  381. }
  382. activeEncoders[encoderSolid] = solid;
  383. activeEncoders[encoderBitmap] = bitmap;
  384. activeEncoders[encoderBitmapRLE] = bitmapRLE;
  385. activeEncoders[encoderIndexed] = indexed;
  386. activeEncoders[encoderIndexedRLE] = indexedRLE;
  387. activeEncoders[encoderFullColour] = fullColour;
  388. for (iter = activeEncoders.begin(); iter != activeEncoders.end(); ++iter) {
  389. Encoder *encoder;
  390. encoder = encoders[*iter];
  391. encoder->setCompressLevel(conn->client.compressLevel);
  392. if (allowLossy) {
  393. encoder->setQualityLevel(conn->client.qualityLevel);
  394. encoder->setFineQualityLevel(conn->client.fineQualityLevel,
  395. conn->client.subsampling);
  396. } else {
  397. int level = __rfbmax(conn->client.qualityLevel,
  398. encoder->losslessQuality);
  399. encoder->setQualityLevel(level);
  400. encoder->setFineQualityLevel(-1, subsampleUndefined);
  401. }
  402. }
  403. }
  404. Region EncodeManager::getLosslessRefresh(const Region& req,
  405. size_t maxUpdateSize)
  406. {
  407. std::vector<Rect> rects;
  408. Region refresh;
  409. size_t area;
  410. // We make a conservative guess at the compression ratio at 2:1
  411. maxUpdateSize *= 2;
  412. // We will measure pixels, not bytes (assume 32 bpp)
  413. maxUpdateSize /= 4;
  414. area = 0;
  415. pendingRefreshRegion.intersect(req).get_rects(&rects);
  416. while (!rects.empty()) {
  417. size_t idx;
  418. Rect rect;
  419. // Grab a random rect so we don't keep damaging and restoring the
  420. // same rect over and over
  421. idx = rand() % rects.size();
  422. rect = rects[idx];
  423. // Add rects until we exceed the threshold, then include as much as
  424. // possible of the final rect
  425. if ((area + rect.area()) > maxUpdateSize) {
  426. // Use the narrowest axis to avoid getting to thin rects
  427. if (rect.width() > rect.height()) {
  428. int width = (maxUpdateSize - area) / rect.height();
  429. rect.br.x = rect.tl.x + __rfbmax(1, width);
  430. } else {
  431. int height = (maxUpdateSize - area) / rect.width();
  432. rect.br.y = rect.tl.y + __rfbmax(1, height);
  433. }
  434. refresh.assign_union(Region(rect));
  435. break;
  436. }
  437. area += rect.area();
  438. refresh.assign_union(Region(rect));
  439. rects.erase(rects.begin() + idx);
  440. }
  441. return refresh;
  442. }
  443. int EncodeManager::computeNumRects(const Region& changed)
  444. {
  445. int numRects;
  446. std::vector<Rect> rects;
  447. std::vector<Rect>::const_iterator rect;
  448. numRects = 0;
  449. changed.get_rects(&rects);
  450. for (rect = rects.begin(); rect != rects.end(); ++rect) {
  451. int w, h, sw, sh;
  452. w = rect->width();
  453. h = rect->height();
  454. // No split necessary?
  455. if (((w*h) < SubRectMaxArea) && (w < SubRectMaxWidth)) {
  456. numRects += 1;
  457. continue;
  458. }
  459. if (w <= SubRectMaxWidth)
  460. sw = w;
  461. else
  462. sw = SubRectMaxWidth;
  463. sh = SubRectMaxArea / sw;
  464. // ceil(w/sw) * ceil(h/sh)
  465. numRects += (((w - 1)/sw) + 1) * (((h - 1)/sh) + 1);
  466. }
  467. return numRects;
  468. }
  469. Encoder *EncodeManager::startRect(const Rect& rect, int type)
  470. {
  471. Encoder *encoder;
  472. int klass, equiv;
  473. activeType = type;
  474. klass = activeEncoders[activeType];
  475. beforeLength = conn->getOutStream()->length();
  476. stats[klass][activeType].rects++;
  477. stats[klass][activeType].pixels += rect.area();
  478. equiv = 12 + rect.area() * (conn->client.pf().bpp/8);
  479. stats[klass][activeType].equivalent += equiv;
  480. encoder = encoders[klass];
  481. conn->writer()->startRect(rect, encoder->encoding);
  482. if ((encoder->flags & EncoderLossy) &&
  483. ((encoder->losslessQuality == -1) ||
  484. (encoder->getQualityLevel() < encoder->losslessQuality)))
  485. lossyRegion.assign_union(Region(rect));
  486. else
  487. lossyRegion.assign_subtract(Region(rect));
  488. // This was either a rect getting refreshed, or a rect that just got
  489. // new content. Either way we should not try to refresh it anymore.
  490. pendingRefreshRegion.assign_subtract(Region(rect));
  491. return encoder;
  492. }
  493. void EncodeManager::endRect()
  494. {
  495. int klass;
  496. int length;
  497. conn->writer()->endRect();
  498. length = conn->getOutStream()->length() - beforeLength;
  499. klass = activeEncoders[activeType];
  500. stats[klass][activeType].bytes += length;
  501. }
  502. void EncodeManager::writeCopyRects(const Region& copied, const Point& delta)
  503. {
  504. std::vector<Rect> rects;
  505. std::vector<Rect>::const_iterator rect;
  506. Region lossyCopy;
  507. beforeLength = conn->getOutStream()->length();
  508. copied.get_rects(&rects, delta.x <= 0, delta.y <= 0);
  509. for (rect = rects.begin(); rect != rects.end(); ++rect) {
  510. int equiv;
  511. copyStats.rects++;
  512. copyStats.pixels += rect->area();
  513. equiv = 12 + rect->area() * (conn->client.pf().bpp/8);
  514. copyStats.equivalent += equiv;
  515. conn->writer()->writeCopyRect(*rect, rect->tl.x - delta.x,
  516. rect->tl.y - delta.y);
  517. }
  518. copyStats.bytes += conn->getOutStream()->length() - beforeLength;
  519. lossyCopy = lossyRegion;
  520. lossyCopy.translate(delta);
  521. lossyCopy.assign_intersect(copied);
  522. lossyRegion.assign_union(lossyCopy);
  523. // Stop any pending refresh as a copy is enough that we consider
  524. // this region to be recently changed
  525. pendingRefreshRegion.assign_subtract(copied);
  526. }
  527. void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
  528. {
  529. std::vector<Rect> rects;
  530. std::vector<Rect>::const_iterator rect;
  531. changed->get_rects(&rects);
  532. for (rect = rects.begin(); rect != rects.end(); ++rect)
  533. findSolidRect(*rect, changed, pb);
  534. }
  535. void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
  536. const PixelBuffer* pb)
  537. {
  538. Rect sr;
  539. int dx, dy, dw, dh;
  540. // We start by finding a solid 16x16 block
  541. for (dy = rect.tl.y; dy < rect.br.y; dy += SolidSearchBlock) {
  542. dh = SolidSearchBlock;
  543. if (dy + dh > rect.br.y)
  544. dh = rect.br.y - dy;
  545. for (dx = rect.tl.x; dx < rect.br.x; dx += SolidSearchBlock) {
  546. // We define it like this to guarantee alignment
  547. rdr::U32 _buffer;
  548. rdr::U8* colourValue = (rdr::U8*)&_buffer;
  549. dw = SolidSearchBlock;
  550. if (dx + dw > rect.br.x)
  551. dw = rect.br.x - dx;
  552. pb->getImage(colourValue, Rect(dx, dy, dx+1, dy+1));
  553. sr.setXYWH(dx, dy, dw, dh);
  554. if (checkSolidTile(sr, colourValue, pb)) {
  555. Rect erb, erp;
  556. Encoder *encoder;
  557. // We then try extending the area by adding more blocks
  558. // in both directions and pick the combination that gives
  559. // the largest area.
  560. sr.setXYWH(dx, dy, rect.br.x - dx, rect.br.y - dy);
  561. extendSolidAreaByBlock(sr, colourValue, pb, &erb);
  562. // Did we end up getting the entire rectangle?
  563. if (erb.equals(rect))
  564. erp = erb;
  565. else {
  566. // Don't bother with sending tiny rectangles
  567. if (erb.area() < SolidBlockMinArea)
  568. continue;
  569. // Extend the area again, but this time one pixel
  570. // row/column at a time.
  571. extendSolidAreaByPixel(rect, erb, colourValue, pb, &erp);
  572. }
  573. // Send solid-color rectangle.
  574. encoder = startRect(erp, encoderSolid);
  575. if (encoder->flags & EncoderUseNativePF) {
  576. encoder->writeSolidRect(erp.width(), erp.height(),
  577. pb->getPF(), colourValue);
  578. } else {
  579. rdr::U32 _buffer2;
  580. rdr::U8* converted = (rdr::U8*)&_buffer2;
  581. conn->client.pf().bufferFromBuffer(converted, pb->getPF(),
  582. colourValue, 1);
  583. encoder->writeSolidRect(erp.width(), erp.height(),
  584. conn->client.pf(), converted);
  585. }
  586. endRect();
  587. changed->assign_subtract(Region(erp));
  588. // Search remaining areas by recursion
  589. // FIXME: Is this the best way to divide things up?
  590. // Left? (Note that we've already searched a SolidSearchBlock
  591. // pixels high strip here)
  592. if ((erp.tl.x != rect.tl.x) && (erp.height() > SolidSearchBlock)) {
  593. sr.setXYWH(rect.tl.x, erp.tl.y + SolidSearchBlock,
  594. erp.tl.x - rect.tl.x, erp.height() - SolidSearchBlock);
  595. findSolidRect(sr, changed, pb);
  596. }
  597. // Right?
  598. if (erp.br.x != rect.br.x) {
  599. sr.setXYWH(erp.br.x, erp.tl.y, rect.br.x - erp.br.x, erp.height());
  600. findSolidRect(sr, changed, pb);
  601. }
  602. // Below?
  603. if (erp.br.y != rect.br.y) {
  604. sr.setXYWH(rect.tl.x, erp.br.y, rect.width(), rect.br.y - erp.br.y);
  605. findSolidRect(sr, changed, pb);
  606. }
  607. return;
  608. }
  609. }
  610. }
  611. }
  612. void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb)
  613. {
  614. std::vector<Rect> rects;
  615. std::vector<Rect>::const_iterator rect;
  616. changed.get_rects(&rects);
  617. for (rect = rects.begin(); rect != rects.end(); ++rect) {
  618. int w, h, sw, sh;
  619. Rect sr;
  620. w = rect->width();
  621. h = rect->height();
  622. // No split necessary?
  623. if (((w*h) < SubRectMaxArea) && (w < SubRectMaxWidth)) {
  624. writeSubRect(*rect, pb);
  625. continue;
  626. }
  627. if (w <= SubRectMaxWidth)
  628. sw = w;
  629. else
  630. sw = SubRectMaxWidth;
  631. sh = SubRectMaxArea / sw;
  632. for (sr.tl.y = rect->tl.y; sr.tl.y < rect->br.y; sr.tl.y += sh) {
  633. sr.br.y = sr.tl.y + sh;
  634. if (sr.br.y > rect->br.y)
  635. sr.br.y = rect->br.y;
  636. for (sr.tl.x = rect->tl.x; sr.tl.x < rect->br.x; sr.tl.x += sw) {
  637. sr.br.x = sr.tl.x + sw;
  638. if (sr.br.x > rect->br.x)
  639. sr.br.x = rect->br.x;
  640. writeSubRect(sr, pb);
  641. }
  642. }
  643. }
  644. }
  645. void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)
  646. {
  647. PixelBuffer *ppb;
  648. Encoder *encoder;
  649. struct RectInfo info;
  650. unsigned int divisor, maxColours;
  651. bool useRLE;
  652. EncoderType type;
  653. // FIXME: This is roughly the algorithm previously used by the Tight
  654. // encoder. It seems a bit backwards though, that higher
  655. // compression setting means spending less effort in building
  656. // a palette. It might be that they figured the increase in
  657. // zlib setting compensated for the loss.
  658. if (conn->client.compressLevel == -1)
  659. divisor = 2 * 8;
  660. else
  661. divisor = conn->client.compressLevel * 8;
  662. if (divisor < 4)
  663. divisor = 4;
  664. maxColours = rect.area()/divisor;
  665. // Special exception inherited from the Tight encoder
  666. if (activeEncoders[encoderFullColour] == encoderTightJPEG) {
  667. if ((conn->client.compressLevel != -1) && (conn->client.compressLevel < 2))
  668. maxColours = 24;
  669. else
  670. maxColours = 96;
  671. }
  672. if (maxColours < 2)
  673. maxColours = 2;
  674. encoder = encoders[activeEncoders[encoderIndexedRLE]];
  675. if (maxColours > encoder->maxPaletteSize)
  676. maxColours = encoder->maxPaletteSize;
  677. encoder = encoders[activeEncoders[encoderIndexed]];
  678. if (maxColours > encoder->maxPaletteSize)
  679. maxColours = encoder->maxPaletteSize;
  680. ppb = preparePixelBuffer(rect, pb, true);
  681. if (!analyseRect(ppb, &info, maxColours))
  682. info.palette.clear();
  683. // Different encoders might have different RLE overhead, but
  684. // here we do a guess at RLE being the better choice if reduces
  685. // the pixel count by 50%.
  686. useRLE = info.rleRuns <= (rect.area() * 2);
  687. switch (info.palette.size()) {
  688. case 0:
  689. type = encoderFullColour;
  690. break;
  691. case 1:
  692. type = encoderSolid;
  693. break;
  694. case 2:
  695. if (useRLE)
  696. type = encoderBitmapRLE;
  697. else
  698. type = encoderBitmap;
  699. break;
  700. default:
  701. if (useRLE)
  702. type = encoderIndexedRLE;
  703. else
  704. type = encoderIndexed;
  705. }
  706. encoder = startRect(rect, type);
  707. if (encoder->flags & EncoderUseNativePF)
  708. ppb = preparePixelBuffer(rect, pb, false);
  709. encoder->writeRect(ppb, info.palette);
  710. endRect();
  711. }
  712. bool EncodeManager::checkSolidTile(const Rect& r, const rdr::U8* colourValue,
  713. const PixelBuffer *pb)
  714. {
  715. switch (pb->getPF().bpp) {
  716. case 32:
  717. return checkSolidTile(r, *(const rdr::U32*)colourValue, pb);
  718. case 16:
  719. return checkSolidTile(r, *(const rdr::U16*)colourValue, pb);
  720. default:
  721. return checkSolidTile(r, *(const rdr::U8*)colourValue, pb);
  722. }
  723. }
  724. void EncodeManager::extendSolidAreaByBlock(const Rect& r,
  725. const rdr::U8* colourValue,
  726. const PixelBuffer *pb, Rect* er)
  727. {
  728. int dx, dy, dw, dh;
  729. int w_prev;
  730. Rect sr;
  731. int w_best = 0, h_best = 0;
  732. w_prev = r.width();
  733. // We search width first, back off when we hit a different colour,
  734. // and restart with a larger height. We keep track of the
  735. // width/height combination that gives us the largest area.
  736. for (dy = r.tl.y; dy < r.br.y; dy += SolidSearchBlock) {
  737. dh = SolidSearchBlock;
  738. if (dy + dh > r.br.y)
  739. dh = r.br.y - dy;
  740. // We test one block here outside the x loop in order to break
  741. // the y loop right away.
  742. dw = SolidSearchBlock;
  743. if (dw > w_prev)
  744. dw = w_prev;
  745. sr.setXYWH(r.tl.x, dy, dw, dh);
  746. if (!checkSolidTile(sr, colourValue, pb))
  747. break;
  748. for (dx = r.tl.x + dw; dx < r.tl.x + w_prev;) {
  749. dw = SolidSearchBlock;
  750. if (dx + dw > r.tl.x + w_prev)
  751. dw = r.tl.x + w_prev - dx;
  752. sr.setXYWH(dx, dy, dw, dh);
  753. if (!checkSolidTile(sr, colourValue, pb))
  754. break;
  755. dx += dw;
  756. }
  757. w_prev = dx - r.tl.x;
  758. if (w_prev * (dy + dh - r.tl.y) > w_best * h_best) {
  759. w_best = w_prev;
  760. h_best = dy + dh - r.tl.y;
  761. }
  762. }
  763. er->tl.x = r.tl.x;
  764. er->tl.y = r.tl.y;
  765. er->br.x = er->tl.x + w_best;
  766. er->br.y = er->tl.y + h_best;
  767. }
  768. void EncodeManager::extendSolidAreaByPixel(const Rect& r, const Rect& sr,
  769. const rdr::U8* colourValue,
  770. const PixelBuffer *pb, Rect* er)
  771. {
  772. int cx, cy;
  773. Rect tr;
  774. // Try to extend the area upwards.
  775. for (cy = sr.tl.y - 1; cy >= r.tl.y; cy--) {
  776. tr.setXYWH(sr.tl.x, cy, sr.width(), 1);
  777. if (!checkSolidTile(tr, colourValue, pb))
  778. break;
  779. }
  780. er->tl.y = cy + 1;
  781. // ... downwards.
  782. for (cy = sr.br.y; cy < r.br.y; cy++) {
  783. tr.setXYWH(sr.tl.x, cy, sr.width(), 1);
  784. if (!checkSolidTile(tr, colourValue, pb))
  785. break;
  786. }
  787. er->br.y = cy;
  788. // ... to the left.
  789. for (cx = sr.tl.x - 1; cx >= r.tl.x; cx--) {
  790. tr.setXYWH(cx, er->tl.y, 1, er->height());
  791. if (!checkSolidTile(tr, colourValue, pb))
  792. break;
  793. }
  794. er->tl.x = cx + 1;
  795. // ... to the right.
  796. for (cx = sr.br.x; cx < r.br.x; cx++) {
  797. tr.setXYWH(cx, er->tl.y, 1, er->height());
  798. if (!checkSolidTile(tr, colourValue, pb))
  799. break;
  800. }
  801. er->br.x = cx;
  802. }
  803. PixelBuffer* EncodeManager::preparePixelBuffer(const Rect& rect,
  804. const PixelBuffer *pb,
  805. bool convert)
  806. {
  807. const rdr::U8* buffer;
  808. int stride;
  809. // Do wo need to convert the data?
  810. if (convert && !conn->client.pf().equal(pb->getPF())) {
  811. convertedPixelBuffer.setPF(conn->client.pf());
  812. convertedPixelBuffer.setSize(rect.width(), rect.height());
  813. buffer = pb->getBuffer(rect, &stride);
  814. convertedPixelBuffer.imageRect(pb->getPF(),
  815. convertedPixelBuffer.getRect(),
  816. buffer, stride);
  817. return &convertedPixelBuffer;
  818. }
  819. // Otherwise we still need to shift the coordinates. We have our own
  820. // abusive subclass of FullFramePixelBuffer for this.
  821. buffer = pb->getBuffer(rect, &stride);
  822. offsetPixelBuffer.update(pb->getPF(), rect.width(), rect.height(),
  823. buffer, stride);
  824. return &offsetPixelBuffer;
  825. }
  826. bool EncodeManager::analyseRect(const PixelBuffer *pb,
  827. struct RectInfo *info, int maxColours)
  828. {
  829. const rdr::U8* buffer;
  830. int stride;
  831. buffer = pb->getBuffer(pb->getRect(), &stride);
  832. switch (pb->getPF().bpp) {
  833. case 32:
  834. return analyseRect(pb->width(), pb->height(),
  835. (const rdr::U32*)buffer, stride,
  836. info, maxColours);
  837. case 16:
  838. return analyseRect(pb->width(), pb->height(),
  839. (const rdr::U16*)buffer, stride,
  840. info, maxColours);
  841. default:
  842. return analyseRect(pb->width(), pb->height(),
  843. (const rdr::U8*)buffer, stride,
  844. info, maxColours);
  845. }
  846. }
  847. void EncodeManager::OffsetPixelBuffer::update(const PixelFormat& pf,
  848. int width, int height,
  849. const rdr::U8* data_,
  850. int stride_)
  851. {
  852. format = pf;
  853. // Forced cast. We never write anything though, so it should be safe.
  854. setBuffer(width, height, (rdr::U8*)data_, stride_);
  855. }
  856. rdr::U8* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& r, int* stride)
  857. {
  858. throw rfb::Exception("Invalid write attempt to OffsetPixelBuffer");
  859. }
  860. // Preprocessor generated, optimised methods
  861. #define BPP 8
  862. #include "EncodeManagerBPP.cxx"
  863. #undef BPP
  864. #define BPP 16
  865. #include "EncodeManagerBPP.cxx"
  866. #undef BPP
  867. #define BPP 32
  868. #include "EncodeManagerBPP.cxx"
  869. #undef BPP