sandbox: video: Support 8bpp depth

At present sandbox only supports 16 and 32bpp depths, since those are the
easy ones with SDL.

We can support other depths by manually converting the pixel formats. Add
support for this, to enable an 8ppp (monochrome) format.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
index bef5abd..7ff0df2 100644
--- a/arch/sandbox/cpu/sdl.c
+++ b/arch/sandbox/cpu/sdl.c
@@ -44,6 +44,8 @@
  * @stopping: true if audio will stop once it runs out of data
  * @texture: SDL texture to use for U-Boot display contents
  * @renderer: SDL renderer to use
+ * @src_depth: Number of bits per pixel in the source frame buffer (that we read
+ * from and render to SDL)
  */
 static struct sdl_info {
 	int width;
@@ -61,6 +63,7 @@
 	bool stopping;
 	SDL_Texture *texture;
 	SDL_Renderer *renderer;
+	int src_depth;
 } sdl;
 
 static void sandbox_sdl_poll_events(void)
@@ -126,6 +129,9 @@
 	if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
 		printf("Unable to init hinting: %s", SDL_GetError());
 
+	sdl.src_depth = 1 << log2_bpp;
+	if (log2_bpp != 4 && log2_bpp != 5)
+		log2_bpp = 5;
 	sdl.depth = 1 << log2_bpp;
 	sdl.pitch = sdl.width * sdl.depth / 8;
 	SDL_Window *screen = SDL_CreateWindow("U-Boot", SDL_WINDOWPOS_UNDEFINED,
@@ -137,10 +143,6 @@
 		       SDL_GetError());
 		return -EIO;
 	}
-	if (log2_bpp != 4 && log2_bpp != 5) {
-		printf("U-Boot SDL does not support depth %d\n", log2_bpp);
-		return -EINVAL;
-	}
 	sdl.renderer = SDL_CreateRenderer(screen, -1,
 					  SDL_RENDERER_ACCELERATED |
 					  SDL_RENDERER_PRESENTVSYNC);
@@ -165,6 +167,55 @@
 	return 0;
 }
 
+static int copy_to_texture(void *lcd_base)
+{
+	char *dest;
+	int pitch, x, y;
+	int src_pitch;
+	void *pixels;
+	char *src;
+	int ret;
+
+	if (sdl.src_depth == sdl.depth) {
+		SDL_UpdateTexture(sdl.texture, NULL, lcd_base, sdl.pitch);
+		return 0;
+	}
+
+	/*
+	 * We only support copying from an 8bpp to a 32bpp texture since the
+	 * other cases are supported directly by the texture.
+	 */
+	if (sdl.depth != 32 && sdl.src_depth != 8) {
+		printf("Need depth 32bpp for copy\n");
+		return -EINVAL;
+	}
+
+	ret = SDL_LockTexture(sdl.texture, NULL, &pixels, &pitch);
+	if (ret) {
+		printf("SDL lock %d: %s\n", ret, SDL_GetError());
+		return ret;
+	}
+
+	/* Copy the pixels one by one */
+	src_pitch = sdl.width * sdl.src_depth / 8;
+	for (y = 0; y < sdl.height; y++) {
+		char val;
+
+		dest = pixels + y * pitch;
+		src = lcd_base + src_pitch * y;
+		for (x = 0; x < sdl.width; x++, dest += 4) {
+			val = *src++;
+			dest[0] = val;
+			dest[1] = val;
+			dest[2] = val;
+			dest[3] = 0;
+		}
+	}
+	SDL_UnlockTexture(sdl.texture);
+
+	return 0;
+}
+
 int sandbox_sdl_sync(void *lcd_base)
 {
 	struct SDL_Rect rect;
@@ -173,7 +224,11 @@
 	if (!sdl.texture)
 		return 0;
 	SDL_RenderClear(sdl.renderer);
-	SDL_UpdateTexture(sdl.texture, NULL, lcd_base, sdl.pitch);
+	ret = copy_to_texture(lcd_base);
+	if (ret) {
+		printf("copy_to_texture: %d: %s\n", ret, SDL_GetError());
+		return -EIO;
+	}
 	ret = SDL_RenderCopy(sdl.renderer, sdl.texture, NULL, NULL);
 	if (ret) {
 		printf("SDL copy %d: %s\n", ret, SDL_GetError());