logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

qp_surface_common.c (5323B)


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