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