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