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