diff --git a/linux_fb_display.cpp b/linux_fb_display.cpp index 53dc932..6292b14 100644 --- a/linux_fb_display.cpp +++ b/linux_fb_display.cpp @@ -97,6 +97,14 @@ void LinuxFBDisplay::writePixel(uint8_t* dst, Color color) const { // --------------------------------------------------------------------------- void LinuxFBDisplay::drawPixelImpl(int16_t x, int16_t y, Color color) { if (!buf_) return; + if (bpp_ == 1) { + uint8_t* p = buf_ + static_cast(y) * line_len_ + + static_cast(x) / 8; + uint8_t bit = static_cast(x) & 7u; + if (color) *p |= (1u << bit); + else *p &= ~(1u << bit); + return; + } uint32_t offset = static_cast(y) * line_len_ + static_cast(x) * (bpp_ / 8); writePixel(buf_ + offset, color); @@ -109,6 +117,35 @@ void LinuxFBDisplay::drawHLineImpl(int16_t x, int16_t y, int16_t w, Color color) { if (!buf_ || w <= 0) return; + if (bpp_ == 1) { + uint8_t* row = buf_ + static_cast(y) * line_len_; + uint32_t x0 = static_cast(x); + uint32_t x1 = x0 + static_cast(w) - 1; + uint32_t b0 = x0 >> 3; + uint32_t b1 = x1 >> 3; + // LSB-first: bit mask for pixel x within its byte = 0x01 << (x & 7) + // A run from x0 to end-of-byte b0 → 0xFF << (x0 & 7) + // A run from start-of-byte b1 to x1 → 0xFF >> (7 - (x1 & 7)) + if (b0 == b1) { + uint8_t mask = (0xFFu << (x0 & 7u)) & (0xFFu >> (7u - (x1 & 7u))); + if (color) row[b0] |= mask; + else row[b0] &= ~mask; + } else { + uint8_t lead = 0xFFu << (x0 & 7u); + uint8_t trail = 0xFFu >> (7u - (x1 & 7u)); + if (color) { + row[b0] |= lead; + if (b1 > b0 + 1) std::memset(row + b0 + 1, 0xFF, b1 - b0 - 1); + row[b1] |= trail; + } else { + row[b0] &= ~lead; + if (b1 > b0 + 1) std::memset(row + b0 + 1, 0x00, b1 - b0 - 1); + row[b1] &= ~trail; + } + } + return; + } + uint32_t bytes_pp = bpp_ / 8; uint8_t* row = buf_ + static_cast(y) * line_len_ + static_cast(x) * bytes_pp; @@ -143,6 +180,18 @@ void LinuxFBDisplay::drawVLineImpl(int16_t x, int16_t y, int16_t h, Color color) { if (!buf_ || h <= 0) return; + if (bpp_ == 1) { + uint8_t bit = static_cast(x) & 7u; + uint8_t* p = buf_ + static_cast(y) * line_len_ + + static_cast(x) / 8; + for (int16_t i = 0; i < h; ++i) { + if (color) *p |= (1u << bit); + else *p &= ~(1u << bit); + p += line_len_; + } + return; + } + uint32_t bytes_pp = bpp_ / 8; uint8_t* p = buf_ + static_cast(y) * line_len_ + static_cast(x) * bytes_pp; @@ -164,6 +213,36 @@ void LinuxFBDisplay::fillRectImpl(int16_t x, int16_t y, int16_t w, int16_t h, Color color) { if (!buf_ || w <= 0 || h <= 0) return; + if (bpp_ == 1) { + uint32_t x0 = static_cast(x); + uint32_t x1 = x0 + static_cast(w) - 1; + uint32_t b0 = x0 >> 3; + uint32_t b1 = x1 >> 3; + + // Fill the first row (handles partial edge bytes correctly). + drawHLineImpl(x, y, w, color); + + if (h == 1) return; + + uint8_t* src = buf_ + static_cast(y) * line_len_ + b0; + uint32_t span = b1 - b0 + 1; + + if ((x0 & 7u) == 0 && (x1 & 7u) == 7u) { + // Byte-aligned: safe to memcpy the full span to every subsequent row. + uint8_t* dst = src + line_len_; + for (int16_t r = 1; r < h; ++r) { + std::memcpy(dst, src, span); + dst += line_len_; + } + } else { + // Unaligned: edge bytes are shared with neighboring pixels, + // so each row must be drawn individually. + for (int16_t r = 1; r < h; ++r) + drawHLineImpl(x, y + r, w, color); + } + return; + } + // For 32-bpp with color == black or white, we can use memset for the // entire rectangle. Otherwise, fill the first row with drawHLineImpl // and memcpy it to subsequent rows. diff --git a/linux_fb_display.h b/linux_fb_display.h index c746e06..7254841 100644 --- a/linux_fb_display.h +++ b/linux_fb_display.h @@ -1,6 +1,6 @@ // linux_fb_display.h — GfxCanvas subclass for Linux framebuffer devices. // -// Supports XRGB8888 (32 bpp), RGB565 (16 bpp), and 8-bit grayscale. +// Supports XRGB8888 (32 bpp), RGB565 (16 bpp), 8-bit grayscale, and 1 bpp (SSD1306). // Uses mmap for zero-copy access to the kernel framebuffer. #ifndef LINUX_FB_DISPLAY_H