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.

PixelBuffer.cxx 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2014 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. // -=- PixelBuffer.cxx
  20. //
  21. // The PixelBuffer class encapsulates the PixelFormat and dimensions
  22. // of a block of pixel data.
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26. #include <string.h>
  27. #include <rfb/Exception.h>
  28. #include <rfb/LogWriter.h>
  29. #include <rfb/PixelBuffer.h>
  30. using namespace rfb;
  31. using namespace rdr;
  32. static LogWriter vlog("PixelBuffer");
  33. // We do a lot of byte offset calculations that assume the result fits
  34. // inside a signed 32 bit integer. Limit the maximum size of pixel
  35. // buffers so that these calculations never overflow.
  36. const int maxPixelBufferWidth = 16384;
  37. const int maxPixelBufferHeight = 16384;
  38. const int maxPixelBufferStride = 16384;
  39. // -=- Generic pixel buffer class
  40. PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h)
  41. : format(pf), width_(0), height_(0)
  42. {
  43. setSize(w, h);
  44. }
  45. PixelBuffer::PixelBuffer() : width_(0), height_(0)
  46. {
  47. }
  48. PixelBuffer::~PixelBuffer() {}
  49. void
  50. PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const
  51. {
  52. int inStride;
  53. const uint8_t* data;
  54. int bytesPerPixel, inBytesPerRow, outBytesPerRow, bytesPerMemCpy;
  55. uint8_t* imageBufPos;
  56. const uint8_t* end;
  57. if (!r.enclosed_by(getRect()))
  58. throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  59. r.width(), r.height(),
  60. r.tl.x, r.tl.y, width(), height());
  61. data = getBuffer(r, &inStride);
  62. bytesPerPixel = format.bpp/8;
  63. inBytesPerRow = inStride * bytesPerPixel;
  64. if (!outStride)
  65. outStride = r.width();
  66. outBytesPerRow = outStride * bytesPerPixel;
  67. bytesPerMemCpy = r.width() * bytesPerPixel;
  68. imageBufPos = (uint8_t*)imageBuf;
  69. end = data + (inBytesPerRow * r.height());
  70. while (data < end) {
  71. memcpy(imageBufPos, data, bytesPerMemCpy);
  72. imageBufPos += outBytesPerRow;
  73. data += inBytesPerRow;
  74. }
  75. }
  76. void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf,
  77. const Rect& r, int stride) const
  78. {
  79. const uint8_t* srcBuffer;
  80. int srcStride;
  81. if (format == pf) {
  82. getImage(imageBuf, r, stride);
  83. return;
  84. }
  85. if (!r.enclosed_by(getRect()))
  86. throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  87. r.width(), r.height(),
  88. r.tl.x, r.tl.y, width(), height());
  89. if (stride == 0)
  90. stride = r.width();
  91. srcBuffer = getBuffer(r, &srcStride);
  92. pf.bufferFromBuffer((uint8_t*)imageBuf, format, srcBuffer,
  93. r.width(), r.height(), stride, srcStride);
  94. }
  95. void PixelBuffer::setSize(int width, int height)
  96. {
  97. if ((width < 0) || (width > maxPixelBufferWidth))
  98. throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width);
  99. if ((height < 0) || (height > maxPixelBufferHeight))
  100. throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height);
  101. width_ = width;
  102. height_ = height;
  103. }
  104. // -=- Modifiable generic pixel buffer class
  105. ModifiablePixelBuffer::ModifiablePixelBuffer(const PixelFormat& pf,
  106. int w, int h)
  107. : PixelBuffer(pf, w, h)
  108. {
  109. }
  110. ModifiablePixelBuffer::ModifiablePixelBuffer()
  111. {
  112. }
  113. ModifiablePixelBuffer::~ModifiablePixelBuffer()
  114. {
  115. }
  116. void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix)
  117. {
  118. int stride;
  119. uint8_t *buf;
  120. int w, h, b;
  121. if (!r.enclosed_by(getRect()))
  122. throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  123. r.width(), r.height(), r.tl.x, r.tl.y, width(), height());
  124. w = r.width();
  125. h = r.height();
  126. b = format.bpp/8;
  127. if (h == 0)
  128. return;
  129. buf = getBufferRW(r, &stride);
  130. if (b == 1) {
  131. while (h--) {
  132. memset(buf, *(const uint8_t*)pix, w);
  133. buf += stride * b;
  134. }
  135. } else {
  136. uint8_t *start;
  137. int w1;
  138. start = buf;
  139. w1 = w;
  140. while (w1--) {
  141. memcpy(buf, pix, b);
  142. buf += b;
  143. }
  144. buf += (stride - w) * b;
  145. h--;
  146. while (h--) {
  147. memcpy(buf, start, w * b);
  148. buf += stride * b;
  149. }
  150. }
  151. commitBufferRW(r);
  152. }
  153. void ModifiablePixelBuffer::imageRect(const Rect& r,
  154. const void* pixels, int srcStride)
  155. {
  156. uint8_t* dest;
  157. int destStride;
  158. int bytesPerPixel, bytesPerDestRow, bytesPerSrcRow, bytesPerFill;
  159. const uint8_t* src;
  160. uint8_t* end;
  161. if (!r.enclosed_by(getRect()))
  162. throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  163. r.width(), r.height(),
  164. r.tl.x, r.tl.y, width(), height());
  165. bytesPerPixel = getPF().bpp/8;
  166. dest = getBufferRW(r, &destStride);
  167. bytesPerDestRow = bytesPerPixel * destStride;
  168. if (!srcStride)
  169. srcStride = r.width();
  170. bytesPerSrcRow = bytesPerPixel * srcStride;
  171. bytesPerFill = bytesPerPixel * r.width();
  172. src = (const uint8_t*)pixels;
  173. end = dest + (bytesPerDestRow * r.height());
  174. while (dest < end) {
  175. memcpy(dest, src, bytesPerFill);
  176. dest += bytesPerDestRow;
  177. src += bytesPerSrcRow;
  178. }
  179. commitBufferRW(r);
  180. }
  181. void ModifiablePixelBuffer::copyRect(const Rect &rect,
  182. const Point &move_by_delta)
  183. {
  184. int srcStride, dstStride;
  185. int bytesPerPixel;
  186. const uint8_t* srcData;
  187. uint8_t* dstData;
  188. Rect drect, srect;
  189. drect = rect;
  190. if (!drect.enclosed_by(getRect()))
  191. throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  192. drect.width(), drect.height(),
  193. drect.tl.x, drect.tl.y, width(), height());
  194. srect = drect.translate(move_by_delta.negate());
  195. if (!srect.enclosed_by(getRect()))
  196. throw rfb::Exception("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  197. srect.width(), srect.height(),
  198. srect.tl.x, srect.tl.y, width(), height());
  199. bytesPerPixel = format.bpp/8;
  200. srcData = getBuffer(srect, &srcStride);
  201. dstData = getBufferRW(drect, &dstStride);
  202. if (move_by_delta.y == 0) {
  203. // Possible overlap. Be careful and use memmove().
  204. int h = drect.height();
  205. while (h--) {
  206. memmove(dstData, srcData, drect.width() * bytesPerPixel);
  207. dstData += dstStride * bytesPerPixel;
  208. srcData += srcStride * bytesPerPixel;
  209. }
  210. } else if (move_by_delta.y < 0) {
  211. // The data shifted upwards. Copy from top to bottom.
  212. int h = drect.height();
  213. while (h--) {
  214. memcpy(dstData, srcData, drect.width() * bytesPerPixel);
  215. dstData += dstStride * bytesPerPixel;
  216. srcData += srcStride * bytesPerPixel;
  217. }
  218. } else {
  219. // The data shifted downwards. Copy from bottom to top.
  220. int h = drect.height();
  221. dstData += (h-1) * dstStride * bytesPerPixel;
  222. srcData += (h-1) * srcStride * bytesPerPixel;
  223. while (h--) {
  224. memcpy(dstData, srcData, drect.width() * bytesPerPixel);
  225. dstData -= dstStride * bytesPerPixel;
  226. srcData -= srcStride * bytesPerPixel;
  227. }
  228. }
  229. commitBufferRW(drect);
  230. }
  231. void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, const Rect &dest,
  232. const void* pix)
  233. {
  234. uint8_t buf[4];
  235. format.bufferFromBuffer(buf, pf, (const uint8_t*)pix, 1);
  236. fillRect(dest, buf);
  237. }
  238. void ModifiablePixelBuffer::imageRect(const PixelFormat& pf, const Rect &dest,
  239. const void* pixels, int stride)
  240. {
  241. uint8_t* dstBuffer;
  242. int dstStride;
  243. if (!dest.enclosed_by(getRect()))
  244. throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
  245. dest.width(), dest.height(),
  246. dest.tl.x, dest.tl.y, width(), height());
  247. if (stride == 0)
  248. stride = dest.width();
  249. dstBuffer = getBufferRW(dest, &dstStride);
  250. format.bufferFromBuffer(dstBuffer, pf, (const uint8_t*)pixels,
  251. dest.width(), dest.height(),
  252. dstStride, stride);
  253. commitBufferRW(dest);
  254. }
  255. // -=- Simple pixel buffer with a continuous block of memory
  256. FullFramePixelBuffer::FullFramePixelBuffer(const PixelFormat& pf, int w, int h,
  257. uint8_t* data_, int stride_)
  258. : ModifiablePixelBuffer(pf, w, h), data(data_), stride(stride_)
  259. {
  260. }
  261. FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {}
  262. FullFramePixelBuffer::~FullFramePixelBuffer() {}
  263. uint8_t* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride_)
  264. {
  265. if (!r.enclosed_by(getRect()))
  266. throw rfb::Exception("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
  267. r.width(), r.height(),
  268. r.tl.x, r.tl.y, width(), height());
  269. *stride_ = stride;
  270. return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)];
  271. }
  272. void FullFramePixelBuffer::commitBufferRW(const Rect& /*r*/)
  273. {
  274. }
  275. const uint8_t* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) const
  276. {
  277. if (!r.enclosed_by(getRect()))
  278. throw rfb::Exception("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
  279. r.width(), r.height(),
  280. r.tl.x, r.tl.y, width(), height());
  281. *stride_ = stride;
  282. return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)];
  283. }
  284. void FullFramePixelBuffer::setBuffer(int width, int height,
  285. uint8_t* data_, int stride_)
  286. {
  287. if ((width < 0) || (width > maxPixelBufferWidth))
  288. throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width);
  289. if ((height < 0) || (height > maxPixelBufferHeight))
  290. throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height);
  291. if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width))
  292. throw rfb::Exception("Invalid PixelBuffer stride of %d pixels requested", stride_);
  293. if ((width != 0) && (height != 0) && (data_ == NULL))
  294. throw rfb::Exception("PixelBuffer requested without a valid memory area");
  295. ModifiablePixelBuffer::setSize(width, height);
  296. stride = stride_;
  297. data = data_;
  298. }
  299. void FullFramePixelBuffer::setSize(int /*w*/, int /*h*/)
  300. {
  301. // setBuffer() should be used
  302. throw rfb::Exception("Invalid call to FullFramePixelBuffer::setSize()");
  303. }
  304. // -=- Managed pixel buffer class
  305. // Automatically allocates enough space for the specified format & area
  306. ManagedPixelBuffer::ManagedPixelBuffer()
  307. : data_(NULL), datasize(0)
  308. {
  309. }
  310. ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h)
  311. : FullFramePixelBuffer(pf, 0, 0, NULL, 0), data_(NULL), datasize(0)
  312. {
  313. setSize(w, h);
  314. }
  315. ManagedPixelBuffer::~ManagedPixelBuffer()
  316. {
  317. if (data_)
  318. delete [] data_;
  319. }
  320. void ManagedPixelBuffer::setPF(const PixelFormat &pf)
  321. {
  322. format = pf;
  323. setSize(width(), height());
  324. }
  325. void ManagedPixelBuffer::setSize(int w, int h)
  326. {
  327. unsigned long new_datasize = w * h * (format.bpp/8);
  328. new_datasize = w * h * (format.bpp/8);
  329. if (datasize < new_datasize) {
  330. if (data_) {
  331. delete [] data_;
  332. data_ = NULL;
  333. datasize = 0;
  334. }
  335. if (new_datasize) {
  336. data_ = new uint8_t[new_datasize];
  337. datasize = new_datasize;
  338. }
  339. }
  340. setBuffer(w, h, data_, w);
  341. }