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

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