@@ -62,7 +62,7 @@ constexpr uint16_t RGB_LOWER_MASK = (1 << R2_BIT) | (1 << G2_BIT) | (1 << B2_BIT
6262constexpr uint16_t RGB_MASK = RGB_UPPER_MASK | RGB_LOWER_MASK; // 0x003F
6363
6464GdmaDma::GdmaDma (const Hub75Config &config)
65- : config_ (config),
65+ : PlatformDma (config),
6666 dma_chan_ (nullptr ),
6767 bit_depth_(config.bit_depth),
6868 lsbMsbTransitionBit_(0 ),
@@ -85,8 +85,7 @@ GdmaDma::GdmaDma(const Hub75Config &config)
8585 active_idx_ (0 ),
8686 descriptor_count_ (0 ),
8787 basis_brightness_ (config.brightness), // Use config value (default: 128)
88- intensity_ (1 .0f ),
89- lut_ (nullptr ) {
88+ intensity_ (1 .0f ) {
9089 // Zero-copy architecture: DMA buffers ARE the display memory
9190 // Note: panel_width_, etc. will be set in init()
9291}
@@ -466,8 +465,6 @@ void GdmaDma::set_intensity(float intensity) {
466465// Pixel API (Direct DMA Buffer Writes)
467466// ============================================================================
468467
469- void GdmaDma::set_lut (const uint16_t *lut) { lut_ = lut; }
470-
471468HUB75_IRAM void GdmaDma::draw_pixels (uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *buffer,
472469 Hub75PixelFormat format, Hub75ColorOrder color_order, bool big_endian) {
473470 // Always write to active buffer (CPU drawing buffer)
@@ -496,102 +493,19 @@ HUB75_IRAM void GdmaDma::draw_pixels(uint16_t x, uint16_t y, uint16_t w, uint16_
496493 uint16_t px = x + dx;
497494 uint16_t py = y + dy;
498495
499- // ============================================================
500- // COORDINATE TRANSFORMATION PIPELINE
501- // ============================================================
502-
503- Coords c = {.x = px, .y = py};
504-
505- // Step 1: Panel layout remapping (if multi-panel grid)
506- if (needs_layout_remap_) {
507- c = PanelLayoutRemap::remap (c, layout_, panel_width_, panel_height_, layout_rows_, layout_cols_);
508- }
509-
510- // Step 2: Scan pattern remapping (if non-standard panel)
511- if (needs_scan_remap_) {
512- c = ScanPatternRemap::remap (c, scan_wiring_, panel_width_);
513- }
514-
515- // Use transformed coordinates for DMA buffer writes
516- px = c.x ;
517- py = c.y ;
518-
519- // Debug assertions - automatically disabled in release builds
520- assert (px < dma_width_ && " Transformed X exceeds DMA buffer width!" );
521- assert (py < panel_height_ && " Transformed Y exceeds row buffer height!" );
522-
523- const uint16_t row = py % (panel_height_ / 2 );
524- const bool is_lower = (py >= panel_height_ / 2 );
496+ // Coordinate transformation pipeline (layout + scan remapping)
497+ auto transformed =
498+ transform_coordinate (px, py, needs_layout_remap_, needs_scan_remap_, layout_, scan_wiring_, panel_width_,
499+ panel_height_, layout_rows_, layout_cols_, dma_width_, num_rows_);
500+ px = transformed.x ;
501+ const uint16_t row = transformed.row ;
502+ const bool is_lower = transformed.is_lower ;
525503
526504 const size_t pixel_idx = (dy * w) + dx;
527505 uint8_t r8 = 0 , g8 = 0 , b8 = 0 ;
528506
529- // Extract RGB based on format
530- switch (format) {
531- case Hub75PixelFormat::RGB565: {
532- // 16-bit RGB565
533- const uint8_t *p = buffer + (pixel_idx * 2 );
534- uint16_t rgb565;
535- // No endianness hint - LVGL default is big-endian, ESP32-native is little-endian
536- if (big_endian) {
537- rgb565 = (uint16_t (p[0 ]) << 8 ) | p[1 ];
538- } else {
539- rgb565 = (uint16_t (p[1 ]) << 8 ) | p[0 ];
540- }
541-
542- // Extract RGB565 components
543- const uint8_t r5 = (rgb565 >> 11 ) & 0x1F ;
544- const uint8_t g6 = (rgb565 >> 5 ) & 0x3F ;
545- const uint8_t b5 = rgb565 & 0x1F ;
546-
547- // Scale to 8-bit using color conversion helpers
548- r8 = scale_5bit_to_8bit (r5);
549- g8 = scale_6bit_to_8bit (g6);
550- b8 = scale_5bit_to_8bit (b5);
551- break ;
552- }
553-
554- case Hub75PixelFormat::RGB888: {
555- // 24-bit packed RGB
556- const uint8_t *p = buffer + (pixel_idx * 3 );
557- r8 = p[0 ];
558- g8 = p[1 ];
559- b8 = p[2 ];
560- break ;
561- }
562-
563- case Hub75PixelFormat::RGB888_32: {
564- // 32-bit RGB with padding
565- const uint8_t *p = buffer + (pixel_idx * 4 );
566- if (color_order == Hub75ColorOrder::RGB) {
567- // No endianness hint - split between LVGL default and ESP32-native
568- if (big_endian) {
569- // Big-endian xRGB: [x][R][G][B]
570- r8 = p[1 ];
571- g8 = p[2 ];
572- b8 = p[3 ];
573- } else {
574- // Little-endian xRGB stored as BGRx: [B][G][R][x]
575- r8 = p[2 ];
576- g8 = p[1 ];
577- b8 = p[0 ];
578- }
579- } else { // BGR
580- if (big_endian) {
581- // Big-endian xBGR: [x][B][G][R]
582- r8 = p[3 ];
583- g8 = p[2 ];
584- b8 = p[1 ];
585- } else {
586- // Little-endian xBGR stored as RGBx: [R][G][B][x]
587- r8 = p[0 ];
588- g8 = p[1 ];
589- b8 = p[2 ];
590- }
591- }
592- break ;
593- }
594- }
507+ // Extract RGB888 from pixel format
508+ extract_rgb888_from_format (buffer, pixel_idx, format, color_order, big_endian, r8, g8, b8);
595509
596510 // Apply LUT correction
597511 const uint16_t r_corrected = lut_[r8];
0 commit comments