1 /*
2 * Copyright (c) 2018 Jan Van Winkel <jan.van_winkel@dxplore.eu>
3 * Copyright (c) 2023 Nordic Semiconductor
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include "display_sdl_bottom.h"
9
10 #include <stdint.h>
11 #include <stddef.h>
12 #include <stdbool.h>
13 #include <SDL.h>
14 #include "nsi_tracing.h"
15
sdl_display_init_bottom(uint16_t height,uint16_t width,uint16_t zoom_pct,bool use_accelerator,void ** window,const void * window_user_data,const char * title,void ** renderer,void ** mutex,void ** texture,void ** read_texture,void ** background_texture,uint32_t transparency_grid_color1,uint32_t transparency_grid_color2,uint16_t transparency_grid_cell_size)16 int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct,
17 bool use_accelerator, void **window, const void *window_user_data,
18 const char *title, void **renderer, void **mutex, void **texture,
19 void **read_texture, void **background_texture,
20 uint32_t transparency_grid_color1, uint32_t transparency_grid_color2,
21 uint16_t transparency_grid_cell_size)
22 {
23 /* clang-format off */
24 *window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
25 width * zoom_pct / 100,
26 height * zoom_pct / 100, SDL_WINDOW_SHOWN);
27 /* clang-format on */
28 if (*window == NULL) {
29 nsi_print_warning("Failed to create SDL window %s: %s", title, SDL_GetError());
30 return -1;
31 }
32 SDL_SetWindowData(*window, "zephyr_display", (void *)window_user_data);
33
34 if (use_accelerator) {
35 *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED);
36 } else {
37 *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_SOFTWARE);
38 }
39
40 if (*renderer == NULL) {
41 nsi_print_warning("Failed to create SDL renderer: %s",
42 SDL_GetError());
43 return -1;
44 }
45
46 *mutex = SDL_CreateMutex();
47 if (*mutex == NULL) {
48 nsi_print_warning("Failed to create SDL mutex: %s", SDL_GetError());
49 return -1;
50 }
51
52 SDL_RenderSetLogicalSize(*renderer, width, height);
53
54 *texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888,
55 SDL_TEXTUREACCESS_STATIC, width, height);
56 if (*texture == NULL) {
57 nsi_print_warning("Failed to create SDL texture: %s", SDL_GetError());
58 return -1;
59 }
60 SDL_SetTextureBlendMode(*texture, SDL_BLENDMODE_BLEND);
61
62 *read_texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888,
63 SDL_TEXTUREACCESS_TARGET, width, height);
64 if (*read_texture == NULL) {
65 nsi_print_warning("Failed to create SDL texture for read: %s", SDL_GetError());
66 return -1;
67 }
68
69 *background_texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888,
70 SDL_TEXTUREACCESS_STREAMING, width, height);
71 if (*background_texture == NULL) {
72 nsi_print_warning("Failed to create SDL texture: %s", SDL_GetError());
73 return -1;
74 }
75
76 void *background_data;
77 int background_pitch;
78 int err;
79
80 err = SDL_LockTexture(*background_texture, NULL, &background_data, &background_pitch);
81 if (err != 0) {
82 nsi_print_warning("Failed to lock background texture: %d", err);
83 return -1;
84 }
85 for (int y = 0; y < height; y++) {
86 uint32_t *row = (uint32_t *)((uint8_t *)background_data + background_pitch * y);
87
88 for (int x = 0; x < width; x++) {
89 bool x_cell_even = ((x / transparency_grid_cell_size) % 2) == 0;
90 bool y_cell_even = ((y / transparency_grid_cell_size) % 2) == 0;
91
92 if (x_cell_even == y_cell_even) {
93 row[x] = transparency_grid_color1 | 0xff000000;
94 } else {
95 row[x] = transparency_grid_color2 | 0xff000000;
96 }
97 }
98 }
99 SDL_UnlockTexture(*background_texture);
100
101 SDL_SetRenderDrawColor(*renderer, 0, 0, 0, 0xFF);
102 SDL_RenderClear(*renderer);
103 SDL_RenderCopy(*renderer, *background_texture, NULL, NULL);
104 SDL_RenderPresent(*renderer);
105
106 return 0;
107 }
108
sdl_display_write_bottom(const uint16_t height,const uint16_t width,const uint16_t x,const uint16_t y,void * renderer,void * mutex,void * texture,void * background_texture,uint8_t * buf,bool display_on,bool frame_incomplete,uint32_t color_tint)109 void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x,
110 const uint16_t y, void *renderer, void *mutex, void *texture,
111 void *background_texture, uint8_t *buf, bool display_on,
112 bool frame_incomplete, uint32_t color_tint)
113 {
114 SDL_Rect rect;
115 int err;
116
117 rect.x = x;
118 rect.y = y;
119 rect.w = width;
120 rect.h = height;
121
122 err = SDL_TryLockMutex(mutex);
123 if (err) {
124 nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError());
125 return;
126 }
127
128 SDL_UpdateTexture(texture, &rect, buf, 4 * rect.w);
129
130 if (display_on && !frame_incomplete) {
131 SDL_RenderClear(renderer);
132 SDL_RenderCopy(renderer, background_texture, NULL, NULL);
133 SDL_SetTextureColorMod(texture,
134 (color_tint >> 16) & 0xff,
135 (color_tint >> 8) & 0xff,
136 color_tint & 0xff);
137 SDL_RenderCopy(renderer, texture, NULL, NULL);
138 SDL_SetTextureColorMod(texture, 255, 255, 255);
139 SDL_RenderPresent(renderer);
140 }
141
142 SDL_UnlockMutex(mutex);
143 }
144
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 * mutex,void * texture,void * read_texture)145 int sdl_display_read_bottom(const uint16_t height, const uint16_t width,
146 const uint16_t x, const uint16_t y,
147 void *renderer, void *buf, uint16_t pitch,
148 void *mutex, void *texture, void *read_texture)
149 {
150 SDL_Rect rect;
151 int err;
152
153 rect.x = x;
154 rect.y = y;
155 rect.w = width;
156 rect.h = height;
157
158 err = SDL_TryLockMutex(mutex);
159 if (err) {
160 nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError());
161 return -1;
162 }
163
164 SDL_SetRenderTarget(renderer, read_texture);
165 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
166
167 SDL_RenderClear(renderer);
168 SDL_RenderCopy(renderer, texture, NULL, NULL);
169 SDL_RenderReadPixels(renderer, &rect, SDL_PIXELFORMAT_ARGB8888, buf, width * 4);
170
171 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
172 SDL_SetRenderTarget(renderer, NULL);
173
174 SDL_UnlockMutex(mutex);
175
176 return err;
177 }
178
sdl_display_blanking_off_bottom(void * renderer,void * texture,void * background_texture,uint32_t color_tint)179 void sdl_display_blanking_off_bottom(void *renderer, void *texture, void *background_texture,
180 uint32_t color_tint)
181 {
182 SDL_RenderClear(renderer);
183 SDL_RenderCopy(renderer, background_texture, NULL, NULL);
184 SDL_SetTextureColorMod(texture,
185 (color_tint >> 16) & 0xff,
186 (color_tint >> 8) & 0xff,
187 color_tint & 0xff);
188 SDL_RenderCopy(renderer, texture, NULL, NULL);
189 SDL_SetTextureColorMod(texture, 255, 255, 255);
190 SDL_RenderPresent(renderer);
191 }
192
sdl_display_blanking_on_bottom(void * renderer)193 void sdl_display_blanking_on_bottom(void *renderer)
194 {
195 SDL_RenderClear(renderer);
196 SDL_RenderPresent(renderer);
197 }
198
sdl_display_cleanup_bottom(void ** window,void ** renderer,void ** mutex,void ** texture,void ** read_texture,void ** background_texture)199 void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture,
200 void **read_texture, void **background_texture)
201 {
202 if (*background_texture != NULL) {
203 SDL_DestroyTexture(*background_texture);
204 *background_texture = NULL;
205 }
206
207 if (*read_texture != NULL) {
208 SDL_DestroyTexture(*read_texture);
209 *read_texture = NULL;
210 }
211
212 if (*texture != NULL) {
213 SDL_DestroyTexture(*texture);
214 *texture = NULL;
215 }
216
217 if (*mutex != NULL) {
218 SDL_DestroyMutex(*mutex);
219 *mutex = NULL;
220 }
221
222 if (*renderer != NULL) {
223 SDL_DestroyRenderer(*renderer);
224 *renderer = NULL;
225 }
226
227 if (*window != NULL) {
228 SDL_DestroyWindow(*window);
229 *window = NULL;
230 }
231 }
232