xref: /haiku/src/system/boot/platform/generic/video_splash.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
1 /*
2  * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2008, Stephan Aßmus <superstippi@gmx.de>
4  * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include <arch/cpu.h>
10 #include <boot/stage2.h>
11 #include <boot/platform.h>
12 #include <boot/menu.h>
13 #include <boot/kernel_args.h>
14 #include <boot/platform/generic/video.h>
15 #include <boot/images.h>
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 
20 #include <zlib.h>
21 
22 
23 //#define TRACE_VIDEO
24 #ifdef TRACE_VIDEO
25 #	define TRACE(x) dprintf x
26 #else
27 #	define TRACE(x) ;
28 #endif
29 
30 
31 static status_t
32 uncompress(const uint8 compressed[], unsigned int compressedSize,
33 	uint8* uncompressed, unsigned int uncompressedSize)
34 {
35 	if (compressedSize == 0 || uncompressedSize == 0)
36 		return B_BAD_VALUE;
37 
38 	// prepare zlib stream
39 	z_stream zStream = {
40 		(Bytef*)compressed,		// next_in
41 		compressedSize,			// avail_in
42 		0,						// total_in
43 		(Bytef*)uncompressed,	// next_out
44 		uncompressedSize,		// avail_out
45 		0,						// total_out
46 		0,						// msg
47 		0,						// state
48 		Z_NULL,					// zalloc (kernel_args_malloc?)
49 		Z_NULL,					// zfree (kernel_args_free?)
50 		Z_NULL,					// opaque
51 		0,						// data_type
52 		0,						// adler
53 		0						// reserved
54 	};
55 
56 	int zlibError = inflateInit(&zStream);
57 	if (zlibError != Z_OK)
58 		return B_ERROR;	// TODO: translate zlibError
59 
60 	// inflate
61 	status_t status = B_OK;
62 	zlibError = inflate(&zStream, Z_FINISH);
63 	if (zlibError != Z_STREAM_END) {
64 		if (zlibError == Z_OK)
65 			status = B_BUFFER_OVERFLOW;
66 		else
67 			status = B_ERROR;	// TODO: translate zlibError
68 	}
69 
70 	// clean up
71 	zlibError = inflateEnd(&zStream);
72 	if (zlibError != Z_OK && status == B_OK)
73 		status = B_ERROR;	// TODO: translate zlibError
74 
75 	if (status == B_OK && zStream.total_out != uncompressedSize)
76 		status = B_ERROR;
77 
78 	return status;
79 }
80 
81 
82 extern "C" status_t
83 video_display_splash(addr_t frameBuffer)
84 {
85 	if (!gKernelArgs.frame_buffer.enabled)
86 		return B_NO_INIT;
87 
88 	addr_t pos = 0;
89 	// Limit area to clear to estimated screen area
90 	// UEFI can happily report a >256M framebuffer
91 	addr_t size = min_c(gKernelArgs.frame_buffer.width
92 			* gKernelArgs.frame_buffer.height * 4u,
93 		gKernelArgs.frame_buffer.physical_buffer.size);
94 
95 	if (size >= 64) {
96 		// Align writes
97 		for (addr_t align = (8 - (frameBuffer & 7)) & 7; pos < align; pos++)
98 			*(char*)(frameBuffer + pos) = 0;
99 		// Write eight bytes, many many times, but not too many
100 		for (addr_t alignSize = size - 8; pos < alignSize; pos +=8) {
101 			*(uint32*)(frameBuffer + pos) = 0;
102 			*(uint32*)(frameBuffer + pos + 4) = 0;
103 		}
104 	}
105 	// Write a few bytes more
106 	for (; pos < size; pos++)
107 		*(char*)(frameBuffer + pos) = 0;
108 
109 	uint8* uncompressedLogo = NULL;
110 	unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight;
111 	switch (gKernelArgs.frame_buffer.depth) {
112 		case 8:
113 			platform_set_palette(k8BitPalette);
114 			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
115 			if (uncompressedLogo == NULL)
116 				return B_NO_MEMORY;
117 
118 			uncompress(kSplashLogo8BitCompressedImage,
119 				sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo,
120 				uncompressedSize);
121 		break;
122 		default: // 24 bits is assumed here
123 			uncompressedSize *= 3;
124 			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
125 			if (uncompressedLogo == NULL)
126 				return B_NO_MEMORY;
127 
128 			uncompress(kSplashLogo24BitCompressedImage,
129 				sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo,
130 				uncompressedSize);
131 		break;
132 	}
133 
134 	// TODO: support 4-bit indexed version of the images!
135 
136 	// render splash logo
137 	uint16 iconsHalfHeight = kSplashIconsHeight / 2;
138 
139 	int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width);
140 	int height = min_c(kSplashLogoHeight + iconsHalfHeight,
141 		gKernelArgs.frame_buffer.height);
142 	int placementX = max_c(0, min_c(100, kSplashLogoPlacementX));
143 	int placementY = max_c(0, min_c(100, kSplashLogoPlacementY));
144 
145 	int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
146 	int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100;
147 
148 	height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height);
149 	switch (gKernelArgs.frame_buffer.depth) {
150 		case 8:
151 			break;
152 	}
153 	video_blit_image(frameBuffer, uncompressedLogo, width, height,
154 		kSplashLogoWidth, x, y);
155 
156 	kernel_args_free(uncompressedLogo);
157 
158 	const uint8* lowerHalfIconImage;
159 	uncompressedSize = kSplashIconsWidth * kSplashIconsHeight;
160 	switch (gKernelArgs.frame_buffer.depth) {
161 		case 8:
162 			// pointer into the lower half of the icons image data
163 			gKernelArgs.boot_splash
164 				= (uint8*)kernel_args_malloc(uncompressedSize);
165 			if (gKernelArgs.boot_splash == NULL)
166 				return B_NO_MEMORY;
167 			uncompress(kSplashIcons8BitCompressedImage,
168 				sizeof(kSplashIcons8BitCompressedImage),
169 				gKernelArgs.boot_splash, uncompressedSize);
170 			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
171 				+ (kSplashIconsWidth * iconsHalfHeight);
172 		break;
173 		default:	// 24bits is assumed here
174 			uncompressedSize *= 3;
175 			// pointer into the lower half of the icons image data
176 			gKernelArgs.boot_splash
177 				= (uint8*)kernel_args_malloc(uncompressedSize);
178 			if (gKernelArgs.boot_splash == NULL)
179 				return B_NO_MEMORY;
180 			uncompress(kSplashIcons24BitCompressedImage,
181 				sizeof(kSplashIcons24BitCompressedImage),
182 				gKernelArgs.boot_splash, uncompressedSize);
183 			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
184 				+ (kSplashIconsWidth * iconsHalfHeight) * 3;
185 		break;
186 	}
187 
188 	// render initial (grayed out) icons
189 	// the grayed out version is the lower half of the icons image
190 
191 	width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width);
192 	height = min_c(kSplashLogoHeight + iconsHalfHeight,
193 		gKernelArgs.frame_buffer.height);
194 	placementX = max_c(0, min_c(100, kSplashIconsPlacementX));
195 	placementY = max_c(0, min_c(100, kSplashIconsPlacementY));
196 
197 	x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
198 	y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height)
199 		* placementY / 100;
200 
201 	height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height);
202 	video_blit_image(frameBuffer, lowerHalfIconImage, width, height,
203 		kSplashIconsWidth, x, y);
204 	return B_OK;
205 }
206 
207 
208 
209