The Pedigree Project 0.1
Framebuffer.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/machine/Framebuffer.h"
22#include "pedigree/kernel/processor/MemoryRegion.h"
23#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24#include "pedigree/kernel/processor/VirtualAddressSpace.h"
25#include "pedigree/kernel/utilities/utility.h"
26
27Framebuffer::Framebuffer() : m_pParent(0), m_FramebufferBase(0), m_bActive(true) {
28 m_Palette = new uint32_t[256];
29
30 size_t i = 0;
31 for (size_t g = 0; g <= 255; g += 0x33)
32 for (size_t b = 0; b <= 255; b += 0x33)
33 for (size_t r = 0; r <= 255; r += 0x33)
34 m_Palette[i++] = Graphics::createRgb(r, g, b);
35
36 NOTICE("Framebuffer: created " << Dec << i << Hex << " entries in the default palette");
37}
38
39Framebuffer::~Framebuffer() {}
40
41size_t Framebuffer::getWidth() const {
42 return m_nWidth;
43}
44
45size_t Framebuffer::getHeight() const {
46 return m_nHeight;
47}
48
49Graphics::PixelFormat Framebuffer::getFormat() const {
50 return m_PixelFormat;
51}
52
53bool Framebuffer::getActive() const {
54 return m_bActive;
55}
56
57void Framebuffer::setActive(bool b) {
58 m_bActive = b;
59}
60
61void Framebuffer::setPalette(uint32_t* palette, size_t nEntries) {
62 delete[] m_Palette;
63 m_Palette = new uint32_t[nEntries];
64 MemoryCopy(m_Palette, palette, nEntries * sizeof(uint32_t));
65
66 NOTICE("Framebuffer: new palette set with " << Dec << nEntries << Hex << " entries");
67}
68
69uint32_t* Framebuffer::getPalette() const {
70 return m_Palette;
71}
72
74 if (m_pParent)
75 return m_pParent->getRawBuffer();
76 return reinterpret_cast<void*>(m_FramebufferBase);
77}
78
79physical_uintptr_t Framebuffer::getPhysicalPage(size_t) const {
80 return ~physical_uintptr_t(0);
81}
82
83Graphics::Buffer* Framebuffer::createBuffer(const void* srcData, Graphics::PixelFormat srcFormat,
84 size_t width, size_t height, uint32_t* pPalette) {
85 if (m_pParent)
86 return m_pParent->createBuffer(srcData, srcFormat, width, height, pPalette);
87 return swCreateBuffer(srcData, srcFormat, width, height, pPalette);
88}
89
91 // if(m_pParent)
92 // m_pParent->destroyBuffer(pBuffer);
93 // else
94 swDestroyBuffer(pBuffer);
95}
96
97void Framebuffer::redraw(size_t x, size_t y, size_t w, size_t h, bool bChild) {
98 if (m_pParent) {
99 // Redraw with parent:
100 // 1. Draw our framebuffer. This will go to the top without
101 // changing intermediate framebuffers.
102 // 2. Pass a redraw up the chain. This will reach the top level
103 // (with modified x/y) and cause our screen region to be redrawn.
104
108
109 // If the redraw was not caused by a child, make sure our
110 // framebuffer has precedence over any children.
113 if (!bChild) {
114 if (m_pParent->getFormat() == m_PixelFormat) {
115 Graphics::Buffer buf = bufferFromSelf();
116 m_pParent->draw(&buf, x, y, m_XPos + x, m_YPos + y, w, h, false);
117 // m_pParent->draw(reinterpret_cast<void*>(m_FramebufferBase),
118 // x, y, m_XPos + x, m_YPos + y, w, h, m_PixelFormat,
119 // false);
120 } else {
121 ERROR(
122 "Child framebuffer has different pixel format to "
123 "parent!");
124 }
125 }
126
127 // Now we are a child requesting a redraw, so the parent will not
128 // have precedence over us.
129 m_pParent->redraw(m_XPos + x, m_YPos + y, w, h, true);
130 } else
131 hwRedraw(x, y, w, h);
132}
133
134void Framebuffer::blit(Graphics::Buffer* pBuffer, size_t srcx, size_t srcy, size_t destx,
135 size_t desty, size_t width, size_t height, bool bLowestCall) {
136 if (m_pParent)
137 m_pParent->blit(pBuffer, srcx, srcy, m_XPos + destx, m_YPos + desty, width, height, false);
138 if (bLowestCall || !m_pParent)
139 swBlit(pBuffer, srcx, srcy, destx, desty, width, height);
140}
141
142void Framebuffer::draw(void* pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty,
143 size_t width, size_t height, Graphics::PixelFormat format,
144 bool bLowestCall) {
145 // Draw is implemented as a "create buffer and blit"... so we can
146 // avoid checking for parent here as we don't want to poison the
147 // parent's buffer.
148 swDraw(pBuffer, srcx, srcy, destx, desty, width, height, format, bLowestCall);
149}
150
151void Framebuffer::rect(size_t x, size_t y, size_t width, size_t height, uint32_t colour,
152 Graphics::PixelFormat format, bool bLowestCall) {
153 if (m_pParent)
154 m_pParent->rect(m_XPos + x, m_YPos + y, width, height, colour, format, false);
155 if (bLowestCall || !m_pParent)
156 swRect(x, y, width, height, colour, format);
157}
158
159void Framebuffer::copy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h,
160 bool bLowestCall) {
161 if (m_pParent)
162 m_pParent->copy(m_XPos + srcx, m_YPos + srcy, m_XPos + destx, m_YPos + desty, w, h, false);
163 if (bLowestCall || !m_pParent)
164 swCopy(srcx, srcy, destx, desty, w, h);
165}
166
167void Framebuffer::line(size_t x1, size_t y1, size_t x2, size_t y2, uint32_t colour,
168 Graphics::PixelFormat format, bool bLowestCall) {
169 if (m_pParent)
170 m_pParent->line(m_XPos + x1, m_YPos + y1, m_XPos + x2, m_YPos + y2, colour, format, false);
171 if (bLowestCall || !m_pParent)
172 swLine(x1, y1, x2, y2, colour, format);
173}
174
175void Framebuffer::setPixel(size_t x, size_t y, uint32_t colour, Graphics::PixelFormat format,
176 bool bLowestCall) {
177 if (m_pParent)
178 m_pParent->setPixel(m_XPos + x, m_YPos + y, colour, format, false);
179 if (bLowestCall || !m_pParent)
180 swSetPixel(x, y, colour, format);
181}
182
183void Framebuffer::setXPos(size_t x) {
184 m_XPos = x;
185}
186
187void Framebuffer::setYPos(size_t y) {
188 m_YPos = y;
189}
190
191void Framebuffer::setWidth(size_t w) {
192 m_nWidth = w;
193}
194
195void Framebuffer::setHeight(size_t h) {
196 m_nHeight = h;
197}
198
199void Framebuffer::setFormat(Graphics::PixelFormat pf) {
200 m_PixelFormat = pf;
201}
202
203void Framebuffer::setBytesPerPixel(size_t b) {
205}
206
207uint32_t Framebuffer::getBytesPerPixel() const {
208 return m_nBytesPerPixel;
209}
210
211void Framebuffer::setBytesPerLine(size_t b) {
212 m_nBytesPerLine = b;
213}
214
215uint32_t Framebuffer::getBytesPerLine() const {
216 return m_nBytesPerLine;
217}
218
219void Framebuffer::setParent(Framebuffer* p) {
220 m_pParent = p;
221}
222
223Framebuffer* Framebuffer::getParent() const {
224 return m_pParent;
225}
226
227void Framebuffer::setFramebuffer(uintptr_t p) {
228 m_FramebufferBase = p;
229}
230
231Graphics::Buffer Framebuffer::bufferFromSelf() {
233 ret.base = m_FramebufferBase;
234 ret.width = m_nWidth;
235 ret.height = m_nHeight;
236 ret.format = m_PixelFormat;
238 ret.bufferId = 0;
239 ret.pBacking = 0;
240 return ret;
241}
242
243void Framebuffer::draw(Graphics::Buffer* pBuffer, size_t srcx, size_t srcy, size_t destx,
244 size_t desty, size_t width, size_t height, bool bLowestCall) {
245 swDraw(pBuffer, srcx, srcy, destx, desty, width, height, bLowestCall);
246}
247
248Graphics::Buffer* Framebuffer::swCreateBuffer(const void* srcData, Graphics::PixelFormat srcFormat,
249 size_t width, size_t height, uint32_t* pPalette) {
250 if (UNLIKELY(!m_FramebufferBase))
251 return 0;
252 if (UNLIKELY(!(width && height)))
253 return 0;
254
255 Graphics::PixelFormat destFormat = m_PixelFormat;
256
257 size_t sourceBytesPerPixel = bytesPerPixel(srcFormat);
258 size_t sourceBytesPerLine = width * sourceBytesPerPixel;
259
260 size_t destBytesPerPixel = m_nBytesPerPixel;
261 size_t destBytesPerLine = width * destBytesPerPixel;
262
263 size_t fullBufferSize = height * destBytesPerLine;
264 const size_t pageSize = PhysicalMemoryManager::getPageSize();
265
266 MemoryRegion* pRegion = new MemoryRegion("sw-framebuffer-buffer");
268 *pRegion, (fullBufferSize + pageSize - 1) / pageSize, 0, VirtualAddressSpace::Write);
269
270 if (!bSuccess) {
271 delete pRegion;
272 return 0;
273 }
274
275 // Copy the buffer in full
276 void* pAddress = pRegion->virtualAddress();
277 if (((sourceBytesPerPixel == destBytesPerPixel) && (sourceBytesPerLine == destBytesPerLine)) &&
278 (srcFormat == destFormat)) {
279 // Same pixel format and same pixel size. Safe to do a conventional
280 // memcpy. The pixel size check is to handle cases where a buffer may
281 // be, say, 24-bit RGB, and the display driver also 24-bit RGB, but
282 // the display's framebuffer reserves 32 bits for pixels (even though
283 // the actual depth is 24 bits).
284 MemoryCopy(pAddress, srcData, fullBufferSize);
285 } else {
286 // Have to convert and pack each pixel, much slower than memcpy.
287 size_t x, y;
288 for (y = 0; y < height; y++) {
289 for (x = 0; x < width; x++) {
290 size_t sourceOffset = (y * sourceBytesPerLine) + (x * sourceBytesPerPixel);
291 size_t destOffset = (y * destBytesPerLine) + (x * destBytesPerPixel);
292
293 // We'll always access the beginning of a pixel, which makes
294 // things here much simpler.
295 const uint32_t* pSource =
296 reinterpret_cast<const uint32_t*>(adjust_pointer(srcData, sourceOffset));
297
298 uint32_t transform = 0;
299 if (srcFormat == Graphics::Bits8_Idx) {
300 uint32_t source = pPalette[(*pSource) & 0xFF];
301 Graphics::convertPixel(source, Graphics::Bits24_Bgr, transform, destFormat);
302 } else {
303 Graphics::convertPixel(*pSource, srcFormat, transform, destFormat);
304 }
305
306 if (destBytesPerPixel == 4) {
307 uint32_t* pDest = reinterpret_cast<uint32_t*>(adjust_pointer(pAddress, destOffset));
308
309 if (sourceBytesPerPixel == 3)
310 transform &= 0xFFFFFF;
311 else if (sourceBytesPerPixel == 2)
312 transform &= 0xFFFF;
313
314 *pDest = transform;
315 } else if (destBytesPerPixel == 3) {
316 // Handle existing data after this byte if it exists
317 uint32_t* pDest = reinterpret_cast<uint32_t*>(adjust_pointer(pAddress, destOffset));
318 *pDest = (*pDest & 0xFF000000) | (transform & 0xFFFFFF);
319 } else if (destBytesPerPixel == 2) {
320 uint16_t* pDest = reinterpret_cast<uint16_t*>(adjust_pointer(pAddress, destOffset));
321 *pDest = transform & 0xFFFF;
322 } else if (destBytesPerPixel == 1) {
324 }
325 }
326 }
327 }
328
329 Graphics::Buffer* pBuffer = new Graphics::Buffer;
330 pBuffer->base = reinterpret_cast<uintptr_t>(pRegion->virtualAddress());
331 pBuffer->width = width;
332 pBuffer->height = height;
333 pBuffer->format = m_PixelFormat;
334 pBuffer->bytesPerPixel = destBytesPerPixel;
335 pBuffer->bufferId = 0;
336 pBuffer->pBacking = reinterpret_cast<void*>(pRegion);
337
338 return pBuffer;
339}
340
341void Framebuffer::swDestroyBuffer(Graphics::Buffer* pBuffer) {
342 if (pBuffer) {
343 if (pBuffer->base) {
344 MemoryRegion* pRegion = reinterpret_cast<MemoryRegion*>(pBuffer->pBacking);
345 delete pRegion; // Unmaps the memory as well
346 }
347 delete pBuffer;
348 }
349}
350
351void Framebuffer::swBlit(Graphics::Buffer* pBuffer, size_t srcx, size_t srcy, size_t destx,
352 size_t desty, size_t width, size_t height) {
353 if (UNLIKELY(!m_FramebufferBase))
354 return;
355 if (UNLIKELY(!(width && height)))
356 return;
357 if (UNLIKELY(!pBuffer))
358 return;
359
360 size_t bytesPerLine = m_nBytesPerLine;
361 size_t destBytesPerPixel = m_nBytesPerPixel;
362
363 size_t sourceBytesPerPixel = pBuffer->bytesPerPixel;
364 size_t sourceBytesPerLine = pBuffer->width * destBytesPerPixel;
365
366 // Sanity check and clip
367 if ((srcx > pBuffer->width) || (srcy > pBuffer->height))
368 return;
369 if ((destx > m_nWidth) || (desty > m_nHeight))
370 return;
371 if ((srcx + width) > pBuffer->width)
372 width = (srcx + width) - pBuffer->width;
373 if ((srcy + height) > pBuffer->height)
374 height = (srcy + height) - pBuffer->height;
375 if ((destx + width) > m_nWidth)
376 width = m_nWidth - destx; // (destx + width) - m_nWidth;
377 if ((desty + height) > m_nHeight)
378 height = m_nHeight - desty; // (desty + height) - m_nHeight;
379
381
382 void* pSrc = reinterpret_cast<void*>(pBuffer->base);
383
384 // A full-width source can still be tightly packed while scanout has padding.
385 // Copy rows separately unless both buffers have the same packed stride.
386 if (UNLIKELY((srcx == 0) && (destx == 0) && (width * destBytesPerPixel == bytesPerLine) &&
387 (sourceBytesPerLine == bytesPerLine))) {
388 size_t sourceBufferOffset = (srcy * sourceBytesPerLine);
389 size_t frameBufferOffset = (desty * bytesPerLine);
390
391 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffset);
392 void* src = adjust_pointer(pSrc, sourceBufferOffset);
393
394 MemoryCopy(dest, src, bytesPerLine * height);
395 } else {
396 // Line-by-line copy
397 for (size_t y1 = desty, y2 = srcy; y1 < (desty + height); y1++, y2++) {
398 size_t sourceBufferOffset = (y2 * sourceBytesPerLine) + (srcx * sourceBytesPerPixel);
399 size_t frameBufferOffset = (y1 * bytesPerLine) + (destx * destBytesPerPixel);
400
401 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffset);
402 void* src = adjust_pointer(pSrc, sourceBufferOffset);
403
404 MemoryCopy(dest, src, width * destBytesPerPixel);
405 }
406 }
407}
408
409void Framebuffer::swRect(size_t x, size_t y, size_t width, size_t height, uint32_t colour,
410 Graphics::PixelFormat format) {
411 if (UNLIKELY(!m_FramebufferBase))
412 return;
413 if (UNLIKELY(!(width && height)))
414 return;
415
416 // Sanity check and clip
417 if ((x > m_nWidth) || (y > m_nHeight))
418 return;
419 if (width > m_nWidth)
420 width = m_nWidth;
421 if (height > m_nHeight)
422 height = m_nHeight;
423 if ((x + width) > m_nWidth)
424 width = (x + width) - m_nWidth;
425 if ((y + height) > m_nHeight)
426 height = (y + height) - m_nHeight;
427
428 uint32_t transformColour = 0;
429 if (format == Graphics::Bits8_Idx) {
430 uint32_t source = m_Palette[colour & 0xFF];
431 Graphics::convertPixel(source, Graphics::Bits24_Bgr, transformColour, m_PixelFormat);
432 } else
433 Graphics::convertPixel(colour, format, transformColour, m_PixelFormat);
434
435 size_t bytesPerPixel = m_nBytesPerPixel;
436 size_t bytesPerLine = m_nBytesPerLine;
437
438 // Can we just do an easy memset?
439 if (UNLIKELY((!x) && (width == m_nWidth))) {
440 size_t frameBufferOffset = (y * bytesPerLine) + (x * bytesPerPixel);
441
442 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffset);
443
444 size_t copySize = (bytesPerLine * height);
445 if (bytesPerPixel == 4)
446 {
447 if ((copySize % 8) == 0) // QWORD boundary
448 {
449 uint64_t val = (static_cast<uint64_t>(transformColour) << 32) | transformColour;
450 QuadWordSet(dest, val, copySize / 8);
451 } else
452 DoubleWordSet(dest, transformColour, copySize / 4);
453 } else if (bytesPerPixel == 3) {
454 // 24-bit has to set three bytes at a time and leave the top byte
455 // untouched. Painful.
456 for (size_t i = 0; i < (copySize / 3); i++) {
457 uint32_t* p = reinterpret_cast<uint32_t*>(m_FramebufferBase + frameBufferOffset + (i * 3));
458 *p = (*p & 0xFF000000) | transformColour;
459 }
460 } else if (bytesPerPixel == 2) {
461 if ((copySize % 8) == 0) // QWORD boundary
462 {
463 uint64_t val = (static_cast<uint64_t>(transformColour) << 48) |
464 (static_cast<uint64_t>(transformColour) << 32) | (transformColour << 16) |
465 transformColour;
466 QuadWordSet(dest, val, copySize / 8);
467 } else if ((copySize % 4) == 0) // DWORD boundary
468 {
469 uint32_t val = (transformColour << 16) | transformColour;
470 DoubleWordSet(dest, val, copySize / 4);
471 } else
472 WordSet(dest, transformColour, copySize / 2);
473 } else
474 ByteSet(dest, transformColour, (bytesPerLine * height));
475 } else {
476 // Line-by-line fill
477 for (size_t desty = y; desty < (y + height); desty++) {
478 size_t frameBufferOffset = (desty * bytesPerLine) + (x * bytesPerPixel);
479
480 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffset);
481
482 size_t copySize = width * bytesPerPixel;
483 if (bytesPerPixel == 4)
484 {
485 if ((copySize % 8) == 0) // QWORD boundary
486 {
487 uint64_t val = (static_cast<uint64_t>(transformColour) << 32) | transformColour;
488 QuadWordSet(dest, val, copySize / 8);
489 } else
490 DoubleWordSet(dest, transformColour, copySize / 4);
491 } else if (bytesPerPixel == 3) {
492 // 24-bit has to set three bytes at a time and leave the top
493 // byte untouched. Painful.
494 for (size_t i = 0; i < (copySize / 3); i++) {
495 uint32_t* p =
496 reinterpret_cast<uint32_t*>(m_FramebufferBase + frameBufferOffset + (i * 3));
497 *p = (*p & 0xFF000000) | transformColour;
498 }
499 } else if (bytesPerPixel == 2) {
500 if ((copySize % 8) == 0) // QWORD boundary
501 {
502 uint64_t val = (static_cast<uint64_t>(transformColour) << 48) |
503 (static_cast<uint64_t>(transformColour) << 32) | (transformColour << 16) |
504 transformColour;
505 QuadWordSet(dest, val, copySize / 8);
506 } else if ((copySize % 4) == 0) // DWORD boundary
507 {
508 uint32_t val = (transformColour << 16) | transformColour;
509 DoubleWordSet(dest, val, copySize / 4);
510 } else
511 WordSet(dest, transformColour, copySize / 2);
512 } else
513 ByteSet(dest, transformColour, (width * bytesPerPixel));
514 }
515 }
516}
517
518void Framebuffer::swCopy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h) {
519 if (UNLIKELY(!m_FramebufferBase))
520 return;
521 if (UNLIKELY(!(w && h)))
522 return;
523 if (UNLIKELY((srcx == destx) && (srcy == desty)))
524 return;
525
526 // Sanity check and clip
527 if ((srcx > m_nWidth) || (srcy > m_nHeight))
528 return;
529 if ((destx > m_nWidth) || (desty > m_nHeight))
530 return;
531 if ((srcx + w) > m_nWidth)
532 w = (srcx + w) - m_nWidth;
533 if ((srcy + h) > m_nHeight)
534 h = (srcy + h) - m_nHeight;
535 if ((destx + w) > m_nWidth)
536 w = (destx + w) - m_nWidth;
537 if ((desty + h) > m_nHeight)
538 h = (desty + h) - m_nHeight;
539
540 if ((srcx == destx) && (srcy == desty))
541 return;
542 if (!(w && h))
543 return;
544
545 size_t bytesPerLine = m_nBytesPerLine;
546 size_t bytesPerPixel = m_nBytesPerPixel;
548
549 // Easy memcpy?
550 if (UNLIKELY(((!srcx) && (!destx)) && (w == m_nWidth))) {
551 size_t frameBufferOffsetSrc = (srcy * bytesPerLine) + (srcx * bytesPerPixel);
552 size_t frameBufferOffsetDest = (desty * bytesPerLine) + (destx * bytesPerPixel);
553
554 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffsetDest);
555 void* src = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffsetSrc);
556
557 MemoryCopy(dest, src, h * bytesPerLine);
558 } else {
559 // Not so easy, but still not too hard
560 for (size_t yoff = 0; yoff < h; yoff++) {
561 size_t frameBufferOffsetSrc = ((srcy + yoff) * bytesPerLine) + (srcx * bytesPerPixel);
562 size_t frameBufferOffsetDest = ((desty + yoff) * bytesPerLine) + (destx * bytesPerPixel);
563
564 void* dest = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffsetDest);
565 void* src = reinterpret_cast<void*>(m_FramebufferBase + frameBufferOffsetSrc);
566
567 MemoryCopy(dest, src, w * bytesPerPixel);
568 }
569 }
570}
571
572void Framebuffer::swLine(size_t x1, size_t y1, size_t x2, size_t y2, uint32_t colour,
573 Graphics::PixelFormat format) {
574 if (UNLIKELY(!m_FramebufferBase))
575 return;
576
577 // Clip co-ordinates where necessary
578 if (x1 > m_nWidth)
579 x1 = m_nWidth;
580 if (x2 > m_nWidth)
581 x2 = m_nWidth;
582 if (y1 > m_nHeight)
583 y1 = m_nHeight;
584 if (y2 > m_nHeight)
585 y2 = m_nHeight;
586
587 // NOTICE("swLine(" << Dec << x1 << ", " << y1 << " -> " << x2 << ", " << y2
588 // << Hex << ")");
589
590 if (UNLIKELY((x1 == x2) && (y1 == y2)))
591 return;
592
593 uint32_t transformColour = 0;
594 if (format == Graphics::Bits8_Idx) {
595 uint32_t source = m_Palette[colour & 0xFF];
596 Graphics::convertPixel(source, Graphics::Bits24_Bgr, transformColour, m_PixelFormat);
597 } else
598 Graphics::convertPixel(colour, format, transformColour, m_PixelFormat);
599
600 // Special cases
601 if (x1 == x2) // Vertical line
602 {
603 if (y1 > y2)
604 swap(y1, y2);
605 for (size_t y = y1; y < y2; y++)
606 setPixel(x1, y, transformColour, m_PixelFormat);
607 return;
608 } else if (y1 == y2) {
609 if (x1 > x2)
610 swap(x1, x2);
611 for (size_t x = x1; x < x2; x++)
612 setPixel(x, y1, transformColour, m_PixelFormat);
613 return;
614 }
615
616 // Bresenham's algorithm, referred to Computer Graphics, C Version (2nd
617 // Edition) from 1997, by D. Hearn and M. Pauline Baker (page 88)
618 // http://www.amazon.com/Computer-Graphics-C-Version-2nd/dp/0135309247
619
620 ssize_t dx = static_cast<ssize_t>(x2) - static_cast<ssize_t>(x1);
621 ssize_t dy = static_cast<ssize_t>(y2) - static_cast<ssize_t>(y1);
622 ssize_t p = 2 * (dy - dx);
623 ssize_t x, y, xEnd;
624
625 if (x1 > x2) {
626 x = x2;
627 y = y2;
628 xEnd = x1;
629 } else {
630 x = x1;
631 y = y1;
632 xEnd = x2;
633 }
634
635 setPixel(x, y, transformColour, m_PixelFormat);
636
637 while (x < xEnd) {
638 x++;
639 if (p < 0)
640 p += (dy * 2);
641 else {
642 y++;
643 p += 2 * (dy - dx);
644 }
645
646 setPixel(x, y, transformColour, m_PixelFormat);
647 }
648}
649
650void Framebuffer::swSetPixel(size_t x, size_t y, uint32_t colour, Graphics::PixelFormat format) {
651 if (UNLIKELY(!m_FramebufferBase))
652 return;
653
654 if (x > m_nWidth)
655 x = m_nWidth;
656 if (y > m_nHeight)
657 y = m_nHeight;
658
659 size_t bytesPerPixel = m_nBytesPerPixel;
660 size_t bytesPerLine = m_nBytesPerLine;
661
662 uint32_t transformColour = 0;
663 if (format == Graphics::Bits8_Idx) {
664 uint32_t source = m_Palette[colour & 0xFF];
665 Graphics::convertPixel(source, Graphics::Bits24_Bgr, transformColour, m_PixelFormat);
666 } else
667 Graphics::convertPixel(colour, format, transformColour, m_PixelFormat);
668
669 size_t frameBufferOffset = (y * bytesPerLine) + (x * bytesPerPixel);
670
671 if (bytesPerPixel == 4) {
672 uint32_t* pDest = reinterpret_cast<uint32_t*>(m_FramebufferBase + frameBufferOffset);
673 *pDest = transformColour;
674 } else if (bytesPerPixel == 3) {
675 // Handle existing data after this byte if it exists
676 uint32_t* pDest = reinterpret_cast<uint32_t*>(m_FramebufferBase + frameBufferOffset);
677 *pDest = (*pDest & 0xFF000000) | (transformColour & 0xFFFFFF);
678 } else if (bytesPerPixel == 2) {
679 uint16_t* pDest = reinterpret_cast<uint16_t*>(m_FramebufferBase + frameBufferOffset);
680 *pDest = transformColour & 0xFFFF;
681 } else if (bytesPerPixel == 1) {
683 }
684}
685
686void Framebuffer::swDraw(void* pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty,
687 size_t width, size_t height, Graphics::PixelFormat format,
688 bool bLowestCall) {
689 // Potentially inefficient use of RAM and VRAM, but best way to avoid
690 // redundant copies of code lying around.
691 Graphics::Buffer* p = createBuffer(pBuffer, format, srcx + width, srcy + height, m_Palette);
692 if (!p) {
693 return;
694 }
695 blit(p, srcx, srcy, destx, desty, width, height, bLowestCall);
696 destroyBuffer(p);
697}
698
699void Framebuffer::swDraw(Graphics::Buffer* pBuffer, size_t srcx, size_t srcy, size_t destx,
700 size_t desty, size_t width, size_t height, bool bLowestCall) {
701 blit(pBuffer, srcx, srcy, destx, desty, width, height, bLowestCall);
702}
703
704void Framebuffer::hwRedraw(size_t x, size_t y, size_t w, size_t h) {}
virtual void hwRedraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL)
Inherited by drivers that provide a hardware redraw function.
uint32_t * m_Palette
Current graphics palette - an array of 256 32-bit RGBA entries.
virtual Graphics::Buffer * createBuffer(const void *srcData, Graphics::PixelFormat srcFormat, size_t width, size_t height, uint32_t *pPalette=0)
Graphics::PixelFormat m_PixelFormat
Framebuffer pixel format.
void swSetPixel(size_t x, size_t y, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb)
virtual void blit(Graphics::Buffer *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, bool bLowestCall=true)
size_t m_nBytesPerPixel
Bytes per pixel in this framebuffer.
virtual void copy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h, bool bLowestCall=true)
bool m_bActive
Whether this framebuffer is active or not.
void swRect(size_t x, size_t y, size_t width, size_t height, uint32_t colour, Graphics::PixelFormat format)
virtual void draw(void *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
Graphics::Buffer * swCreateBuffer(const void *srcData, Graphics::PixelFormat srcFormat, size_t width, size_t height, uint32_t *pPalette)
virtual physical_uintptr_t getPhysicalPage(size_t offset) const
virtual void destroyBuffer(Graphics::Buffer *pBuffer)
virtual void * getRawBuffer() const
void swCopy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h)
void setPalette(uint32_t *palette, size_t nEntries)
size_t m_XPos
X position on our parent's framebuffer.
void setPixel(size_t x, size_t y, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
size_t m_nWidth
Width of the framebuffer in pixels.
size_t m_nHeight
Height of the framebuffer in pixels.
size_t m_YPos
Y position on our parent's framebuffer.
void swBlit(Graphics::Buffer *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height)
virtual void rect(size_t x, size_t y, size_t width, size_t height, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
virtual void line(size_t x1, size_t y1, size_t x2, size_t y2, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
void redraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL, bool bChild=false)
size_t m_nBytesPerLine
Bytes per line in this framebuffer.
Framebuffer * m_pParent
Parent of this framebuffer.
Special memory entity in the kernel's virtual address space.
void * virtualAddress() const
static PhysicalMemoryManager & instance()
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
size_t bytesPerPixel
Number of bytes per pixel (as it may be different to the format).
Definition Graphics.h:93
PixelFormat format
Definition Graphics.h:90
size_t width
Width of the buffer in pixels.
Definition Graphics.h:83
uintptr_t base
Base of this buffer in memory. For internal use only.
Definition Graphics.h:80
size_t height
Height of the buffer in pixels.
Definition Graphics.h:86
size_t bufferId
Buffer ID, for easy identification within drivers.
Definition Graphics.h:96