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 }