drivers: display: sdl: Correcting display_read()
Fixed an issue where `display_read()` in the SDL driver was not working. In the current implementation, use texture to represent screen images. To read this, draw it once on another surface and then read it. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
This commit is contained in:
parent
a4de15ba1c
commit
321389df92
|
@ -10,6 +10,7 @@
|
|||
#include <zephyr/drivers/display.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <soc.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include "display_sdl_bottom.h"
|
||||
|
@ -29,10 +30,13 @@ struct sdl_display_config {
|
|||
struct sdl_display_data {
|
||||
void *window;
|
||||
void *renderer;
|
||||
void *mutex;
|
||||
void *texture;
|
||||
void *read_texture;
|
||||
bool display_on;
|
||||
enum display_pixel_format current_pixel_format;
|
||||
uint8_t *buf;
|
||||
uint8_t *read_buf;
|
||||
};
|
||||
|
||||
static int sdl_display_init(const struct device *dev)
|
||||
|
@ -64,10 +68,10 @@ static int sdl_display_init(const struct device *dev)
|
|||
sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT;
|
||||
}
|
||||
|
||||
int rc = sdl_display_init_bottom(config->height, config->width,
|
||||
sdl_display_zoom_pct, use_accelerator,
|
||||
&disp_data->window, &disp_data->renderer,
|
||||
&disp_data->texture);
|
||||
int rc = sdl_display_init_bottom(config->height, config->width, sdl_display_zoom_pct,
|
||||
use_accelerator, &disp_data->window, &disp_data->renderer,
|
||||
&disp_data->mutex, &disp_data->texture,
|
||||
&disp_data->read_texture);
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Failed to create SDL display");
|
||||
|
@ -248,28 +252,166 @@ static int sdl_display_write(const struct device *dev, const uint16_t x,
|
|||
}
|
||||
|
||||
sdl_display_write_bottom(desc->height, desc->width, x, y,
|
||||
disp_data->renderer, disp_data->texture,
|
||||
disp_data->renderer, disp_data->mutex, disp_data->texture,
|
||||
disp_data->buf, disp_data->display_on);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdl_display_read_argb8888(const uint8_t *read_buf,
|
||||
const struct display_buffer_descriptor *desc, void *buf)
|
||||
{
|
||||
__ASSERT((desc->pitch * 4U * desc->height) <= desc->buf_size, "Read buffer is too small");
|
||||
|
||||
memcpy(buf, read_buf, desc->pitch * 4U * desc->height);
|
||||
}
|
||||
|
||||
static void sdl_display_read_rgb888(const uint8_t *read_buf,
|
||||
const struct display_buffer_descriptor *desc, void *buf)
|
||||
{
|
||||
uint32_t w_idx;
|
||||
uint32_t h_idx;
|
||||
uint8_t *buf8;
|
||||
const uint32_t *pix_ptr;
|
||||
|
||||
__ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size, "Read buffer is too small");
|
||||
|
||||
for (h_idx = 0U; h_idx < desc->height; ++h_idx) {
|
||||
buf8 = ((uint8_t *)buf) + desc->pitch * 3U * h_idx;
|
||||
|
||||
for (w_idx = 0U; w_idx < desc->width; ++w_idx) {
|
||||
pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx);
|
||||
*buf8 = (*pix_ptr & 0xFF0000) >> 16;
|
||||
buf8 += 1;
|
||||
*buf8 = (*pix_ptr & 0xFF00) >> 8;
|
||||
buf8 += 1;
|
||||
*buf8 = (*pix_ptr & 0xFF);
|
||||
buf8 += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_display_read_rgb565(const uint8_t *read_buf,
|
||||
const struct display_buffer_descriptor *desc, void *buf)
|
||||
{
|
||||
uint32_t w_idx;
|
||||
uint32_t h_idx;
|
||||
uint16_t pixel;
|
||||
uint16_t *buf16;
|
||||
const uint32_t *pix_ptr;
|
||||
|
||||
__ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small");
|
||||
|
||||
for (h_idx = 0U; h_idx < desc->height; ++h_idx) {
|
||||
buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx);
|
||||
|
||||
for (w_idx = 0U; w_idx < desc->width; ++w_idx) {
|
||||
pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx);
|
||||
pixel = (*pix_ptr & 0xF80000) >> 8;
|
||||
pixel |= (*pix_ptr & 0x00FC00) >> 5;
|
||||
pixel |= (*pix_ptr & 0x0000F8) >> 3;
|
||||
*buf16 = sys_be16_to_cpu(pixel);
|
||||
buf16 += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_display_read_bgr565(const uint8_t *read_buf,
|
||||
const struct display_buffer_descriptor *desc, void *buf)
|
||||
{
|
||||
uint32_t w_idx;
|
||||
uint32_t h_idx;
|
||||
uint16_t pixel;
|
||||
uint16_t *buf16;
|
||||
const uint32_t *pix_ptr;
|
||||
|
||||
__ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small");
|
||||
|
||||
for (h_idx = 0U; h_idx < desc->height; ++h_idx) {
|
||||
buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx);
|
||||
|
||||
for (w_idx = 0U; w_idx < desc->width; ++w_idx) {
|
||||
pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx);
|
||||
pixel = (*pix_ptr & 0xF80000) >> 8;
|
||||
pixel |= (*pix_ptr & 0x00FC00) >> 5;
|
||||
pixel |= (*pix_ptr & 0x0000F8) >> 3;
|
||||
*buf16 = pixel;
|
||||
buf16 += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_display_read_mono(const uint8_t *read_buf,
|
||||
const struct display_buffer_descriptor *desc, void *buf,
|
||||
const bool one_is_black)
|
||||
{
|
||||
uint32_t w_idx;
|
||||
uint32_t h_idx;
|
||||
uint32_t tile_idx;
|
||||
uint8_t tile;
|
||||
const uint32_t *pix_ptr;
|
||||
uint8_t *buf8;
|
||||
|
||||
__ASSERT((desc->pitch * desc->height) <= (desc->buf_size * 8U), "Read buffer is too small");
|
||||
__ASSERT((desc->height % 8U) == 0U, "Read buffer height not aligned per 8 pixels");
|
||||
|
||||
for (tile_idx = 0U; tile_idx < (desc->height / 8U); ++tile_idx) {
|
||||
buf8 = (void *)(((uint8_t *)buf) + desc->pitch * tile_idx);
|
||||
|
||||
for (w_idx = 0U; w_idx < desc->width; ++w_idx) {
|
||||
tile = 0;
|
||||
|
||||
for (h_idx = 0U; h_idx < 8; ++h_idx) {
|
||||
pix_ptr = (const uint32_t *)read_buf +
|
||||
((tile_idx * 8 + h_idx) * desc->pitch + w_idx);
|
||||
if ((*pix_ptr)) {
|
||||
tile |= BIT(7 - h_idx);
|
||||
}
|
||||
}
|
||||
*buf8 = one_is_black ? ~tile : tile;
|
||||
buf8 += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sdl_display_read(const struct device *dev, const uint16_t x,
|
||||
const uint16_t y,
|
||||
const struct display_buffer_descriptor *desc,
|
||||
void *buf)
|
||||
{
|
||||
struct sdl_display_data *disp_data = dev->data;
|
||||
int err;
|
||||
|
||||
LOG_DBG("Reading %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width,
|
||||
desc->height, x, y);
|
||||
|
||||
__ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width");
|
||||
__ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size,
|
||||
"Input buffer to small");
|
||||
__ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width");
|
||||
|
||||
return sdl_display_read_bottom(desc->height, desc->width, x, y,
|
||||
disp_data->renderer, buf, desc->pitch);
|
||||
memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4);
|
||||
|
||||
err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer,
|
||||
disp_data->read_buf, desc->pitch, disp_data->mutex,
|
||||
disp_data->texture, disp_data->read_texture);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) {
|
||||
sdl_display_read_argb8888(disp_data->read_buf, desc, buf);
|
||||
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) {
|
||||
sdl_display_read_rgb888(disp_data->read_buf, desc, buf);
|
||||
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) {
|
||||
sdl_display_read_mono(disp_data->read_buf, desc, buf, true);
|
||||
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) {
|
||||
sdl_display_read_mono(disp_data->read_buf, desc, buf, false);
|
||||
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) {
|
||||
sdl_display_read_rgb565(disp_data->read_buf, desc, buf);
|
||||
} else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) {
|
||||
sdl_display_read_bgr565(disp_data->read_buf, desc, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdl_display_blanking_off(const struct device *dev)
|
||||
|
@ -339,7 +481,8 @@ static int sdl_display_set_pixel_format(const struct device *dev,
|
|||
|
||||
static void sdl_display_cleanup(struct sdl_display_data *disp_data)
|
||||
{
|
||||
sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->texture);
|
||||
sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->mutex,
|
||||
&disp_data->texture, &disp_data->read_texture);
|
||||
}
|
||||
|
||||
static const struct display_driver_api sdl_display_api = {
|
||||
|
@ -359,8 +502,11 @@ static const struct display_driver_api sdl_display_api = {
|
|||
\
|
||||
static uint8_t sdl_buf_##n[4 * DT_INST_PROP(n, height) \
|
||||
* DT_INST_PROP(n, width)]; \
|
||||
static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \
|
||||
* DT_INST_PROP(n, width)]; \
|
||||
static struct sdl_display_data sdl_data_##n = { \
|
||||
.buf = sdl_buf_##n, \
|
||||
.read_buf = sdl_read_buf_##n, \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
#include "nsi_tracing.h"
|
||||
|
||||
int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
|
||||
bool use_accelerator, void **window, void **renderer, void **texture)
|
||||
bool use_accelerator, void **window, void **renderer, void **mutex,
|
||||
void **texture, void **read_texture)
|
||||
{
|
||||
*window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100,
|
||||
|
@ -34,6 +35,12 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
|
|||
return -1;
|
||||
}
|
||||
|
||||
*mutex = SDL_CreateMutex();
|
||||
if (*mutex == NULL) {
|
||||
nsi_print_warning("Failed to create SDL mutex: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_RenderSetLogicalSize(*renderer, width, height);
|
||||
|
||||
*texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||
|
@ -43,6 +50,13 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
|
|||
return -1;
|
||||
}
|
||||
|
||||
*read_texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||
SDL_TEXTUREACCESS_TARGET, width, height);
|
||||
if (*read_texture == NULL) {
|
||||
nsi_print_warning("Failed to create SDL texture for read: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(*renderer, 0, 0, 0, 0xFF);
|
||||
SDL_RenderClear(*renderer);
|
||||
SDL_RenderPresent(*renderer);
|
||||
|
@ -52,16 +66,23 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
|
|||
|
||||
void sdl_display_write_bottom(const uint16_t height, const uint16_t width,
|
||||
const uint16_t x, const uint16_t y,
|
||||
void *renderer, void *texture,
|
||||
void *renderer, void *mutex, void *texture,
|
||||
uint8_t *buf, bool display_on)
|
||||
{
|
||||
SDL_Rect rect;
|
||||
int err;
|
||||
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = width;
|
||||
rect.h = height;
|
||||
|
||||
err = SDL_TryLockMutex(mutex);
|
||||
if (err) {
|
||||
nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(texture, &rect, buf, 4 * rect.w);
|
||||
|
||||
if (display_on) {
|
||||
|
@ -69,20 +90,40 @@ void sdl_display_write_bottom(const uint16_t height, const uint16_t width,
|
|||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(mutex);
|
||||
}
|
||||
|
||||
int sdl_display_read_bottom(const uint16_t height, const uint16_t width,
|
||||
const uint16_t x, const uint16_t y,
|
||||
void *renderer, void *buf, uint16_t pitch)
|
||||
void *renderer, void *buf, uint16_t pitch,
|
||||
void *mutex, void *texture, void *read_texture)
|
||||
{
|
||||
SDL_Rect rect;
|
||||
int err;
|
||||
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = width;
|
||||
rect.h = height;
|
||||
|
||||
return SDL_RenderReadPixels(renderer, &rect, 0, buf, pitch * 4U);
|
||||
err = SDL_TryLockMutex(mutex);
|
||||
if (err) {
|
||||
nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_SetRenderTarget(renderer, read_texture);
|
||||
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderReadPixels(renderer, &rect, SDL_PIXELFORMAT_ARGB8888, buf, width * 4);
|
||||
|
||||
SDL_SetRenderTarget(renderer, NULL);
|
||||
|
||||
SDL_UnlockMutex(mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void sdl_display_blanking_off_bottom(void *renderer, void *texture)
|
||||
|
@ -98,13 +139,24 @@ void sdl_display_blanking_on_bottom(void *renderer)
|
|||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture)
|
||||
void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture,
|
||||
void **read_texture)
|
||||
{
|
||||
if (*read_texture != NULL) {
|
||||
SDL_DestroyTexture(*read_texture);
|
||||
*read_texture = NULL;
|
||||
}
|
||||
|
||||
if (*texture != NULL) {
|
||||
SDL_DestroyTexture(*texture);
|
||||
*texture = NULL;
|
||||
}
|
||||
|
||||
if (*mutex != NULL) {
|
||||
SDL_DestroyMutex(*mutex);
|
||||
*mutex = NULL;
|
||||
}
|
||||
|
||||
if (*renderer != NULL) {
|
||||
SDL_DestroyRenderer(*renderer);
|
||||
*renderer = NULL;
|
||||
|
|
|
@ -21,17 +21,20 @@ extern "C" {
|
|||
/* Note: None of these functions are public interfaces. But internal to the SDL display driver */
|
||||
|
||||
int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
|
||||
bool use_accelerator, void **window, void **renderer, void **texture);
|
||||
bool use_accelerator, void **window, void **renderer, void **mutex,
|
||||
void **texture, void **read_texture);
|
||||
void sdl_display_write_bottom(const uint16_t height, const uint16_t width,
|
||||
const uint16_t x, const uint16_t y,
|
||||
void *renderer, void *texture,
|
||||
void *renderer, void *mutex, void *texture,
|
||||
uint8_t *buf, bool display_on);
|
||||
int sdl_display_read_bottom(const uint16_t height, const uint16_t width,
|
||||
const uint16_t x, const uint16_t y,
|
||||
void *renderer, void *buf, uint16_t pitch);
|
||||
void *renderer, void *buf, uint16_t pitch,
|
||||
void *mutex, void *texture, void **read_texture);
|
||||
void sdl_display_blanking_off_bottom(void *renderer, void *texture);
|
||||
void sdl_display_blanking_on_bottom(void *renderer);
|
||||
void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture);
|
||||
void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture,
|
||||
void **read_texture);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue