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

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