qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

qp_surface_common.c (5323B)


      1 // Copyright 2022 Nick Brassel (@tzarc)
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 
      4 #include "color.h"
      5 #include "qp_draw.h"
      6 #include "qp_surface_internal.h"
      7 
      8 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      9 // Driver storage
     10 
     11 surface_painter_device_t surface_drivers[SURFACE_NUM_DEVICES] = {0};
     12 
     13 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     14 // Helpers
     15 
     16 void qp_surface_increment_pixdata_location(surface_viewport_data_t *viewport) {
     17     // Increment the X-position
     18     viewport->pixdata_x++;
     19 
     20     // If the x-coord has gone past the right-side edge, loop it back around and increment the y-coord
     21     if (viewport->pixdata_x > viewport->viewport_r) {
     22         viewport->pixdata_x = viewport->viewport_l;
     23         viewport->pixdata_y++;
     24     }
     25 
     26     // If the y-coord has gone past the bottom, loop it back to the top
     27     if (viewport->pixdata_y > viewport->viewport_b) {
     28         viewport->pixdata_y = viewport->viewport_t;
     29     }
     30 }
     31 
     32 void qp_surface_update_dirty(surface_dirty_data_t *dirty, uint16_t x, uint16_t y) {
     33     // Maintain dirty region
     34     if (dirty->l > x) {
     35         dirty->l        = x;
     36         dirty->is_dirty = true;
     37     }
     38     if (dirty->r < x) {
     39         dirty->r        = x;
     40         dirty->is_dirty = true;
     41     }
     42     if (dirty->t > y) {
     43         dirty->t        = y;
     44         dirty->is_dirty = true;
     45     }
     46     if (dirty->b < y) {
     47         dirty->b        = y;
     48         dirty->is_dirty = true;
     49     }
     50 }
     51 
     52 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     53 // Driver vtable
     54 
     55 bool qp_surface_init(painter_device_t device, painter_rotation_t rotation) {
     56     painter_driver_t         *driver  = (painter_driver_t *)device;
     57     surface_painter_device_t *surface = (surface_painter_device_t *)driver;
     58     memset(surface->buffer, 0, SURFACE_REQUIRED_BUFFER_BYTE_SIZE(driver->panel_width, driver->panel_height, driver->native_bits_per_pixel));
     59 
     60     surface->dirty.l        = 0;
     61     surface->dirty.t        = 0;
     62     surface->dirty.r        = surface->base.panel_width - 1;
     63     surface->dirty.b        = surface->base.panel_height - 1;
     64     surface->dirty.is_dirty = true;
     65 
     66     return true;
     67 }
     68 
     69 bool qp_surface_power(painter_device_t device, bool power_on) {
     70     // No-op.
     71     return true;
     72 }
     73 
     74 bool qp_surface_clear(painter_device_t device) {
     75     painter_driver_t *driver = (painter_driver_t *)device;
     76     driver->driver_vtable->init(device, driver->rotation); // Re-init the surface
     77     return true;
     78 }
     79 
     80 bool qp_surface_flush(painter_device_t device) {
     81     painter_driver_t         *driver  = (painter_driver_t *)device;
     82     surface_painter_device_t *surface = (surface_painter_device_t *)driver;
     83     surface->dirty.l = surface->dirty.t = UINT16_MAX;
     84     surface->dirty.r = surface->dirty.b = 0;
     85     surface->dirty.is_dirty             = false;
     86     return true;
     87 }
     88 
     89 bool qp_surface_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
     90     painter_driver_t         *driver  = (painter_driver_t *)device;
     91     surface_painter_device_t *surface = (surface_painter_device_t *)driver;
     92 
     93     // Set the viewport locations
     94     surface->viewport.viewport_l = left;
     95     surface->viewport.viewport_t = top;
     96     surface->viewport.viewport_r = right;
     97     surface->viewport.viewport_b = bottom;
     98 
     99     // Reset the write location to the top left
    100     surface->viewport.pixdata_x = left;
    101     surface->viewport.pixdata_y = top;
    102     return true;
    103 }
    104 
    105 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    106 // Drawing routine to copy out the dirty region and send it to another device
    107 
    108 bool qp_surface_draw(painter_device_t surface, painter_device_t target, uint16_t x, uint16_t y, bool entire_surface) {
    109     painter_driver_t         *surface_driver = (painter_driver_t *)surface;
    110     surface_painter_device_t *surface_handle = (surface_painter_device_t *)surface_driver;
    111     painter_driver_t         *target_driver  = (painter_driver_t *)target;
    112 
    113     // If we're not dirty... we're done.
    114     if (!surface_handle->dirty.is_dirty) {
    115         qp_dprintf("qp_surface_draw: ok (not dirty, skipping)\n");
    116         return true;
    117     }
    118 
    119     // If we have incompatible bit depths, drop out
    120     if (surface_driver->native_bits_per_pixel != target_driver->native_bits_per_pixel) {
    121         qp_dprintf("qp_surface_draw: fail (incompatible bpp: surface=%d, target=%d)\n", (int)surface_driver->native_bits_per_pixel, (int)target_driver->native_bits_per_pixel);
    122         return false;
    123     }
    124 
    125     // Offload to the pixdata transfer function
    126     surface_painter_driver_vtable_t *vtable = (surface_painter_driver_vtable_t *)surface_driver->driver_vtable;
    127     bool                             ok     = vtable->target_pixdata_transfer(surface_driver, target_driver, x, y, entire_surface);
    128     if (!ok) {
    129         qp_dprintf("qp_surface_draw: fail (could not transfer pixel data)\n");
    130         return false;
    131     }
    132 
    133     // Clear the dirty info for the surface
    134     ok = qp_flush(surface);
    135     if (!ok) {
    136         qp_dprintf("qp_surface_draw: fail (could not flush)\n");
    137         return false;
    138     }
    139     qp_dprintf("qp_surface_draw: ok\n");
    140     return true;
    141 }