17db9fbfeSFrançois Revol /*
27db9fbfeSFrançois Revol * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de.
37db9fbfeSFrançois Revol * Copyright 2008, Stephan Aßmus <superstippi@gmx.de>
47db9fbfeSFrançois Revol * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
57db9fbfeSFrançois Revol * Distributed under the terms of the MIT License.
67db9fbfeSFrançois Revol */
77db9fbfeSFrançois Revol
87db9fbfeSFrançois Revol
97db9fbfeSFrançois Revol #include <arch/cpu.h>
107db9fbfeSFrançois Revol #include <boot/stage2.h>
117db9fbfeSFrançois Revol #include <boot/platform.h>
127db9fbfeSFrançois Revol #include <boot/menu.h>
137db9fbfeSFrançois Revol #include <boot/kernel_args.h>
147db9fbfeSFrançois Revol #include <boot/platform/generic/video.h>
15029e447bSAugustin Cavalier #include <boot/platform/generic/video_blitter.h>
16*de8d5cfbSAugustin Cavalier
1789fa2a85SPhilippe Houdoin #include <boot/images.h>
18*de8d5cfbSAugustin Cavalier #include <boot/platform/generic/video_splash.h>
197db9fbfeSFrançois Revol
207db9fbfeSFrançois Revol #include <stdio.h>
217db9fbfeSFrançois Revol #include <stdlib.h>
227db9fbfeSFrançois Revol
2367938b0dSPhilippe Houdoin #include <zlib.h>
2467938b0dSPhilippe Houdoin
257db9fbfeSFrançois Revol
267db9fbfeSFrançois Revol //#define TRACE_VIDEO
277db9fbfeSFrançois Revol #ifdef TRACE_VIDEO
287db9fbfeSFrançois Revol # define TRACE(x) dprintf x
297db9fbfeSFrançois Revol #else
307db9fbfeSFrançois Revol # define TRACE(x) ;
317db9fbfeSFrançois Revol #endif
327db9fbfeSFrançois Revol
337db9fbfeSFrançois Revol
3467938b0dSPhilippe Houdoin static status_t
uncompress(const uint8 compressed[],unsigned int compressedSize,uint8 * uncompressed,unsigned int uncompressedSize)3567938b0dSPhilippe Houdoin uncompress(const uint8 compressed[], unsigned int compressedSize,
3667938b0dSPhilippe Houdoin uint8* uncompressed, unsigned int uncompressedSize)
3767938b0dSPhilippe Houdoin {
3867938b0dSPhilippe Houdoin if (compressedSize == 0 || uncompressedSize == 0)
3967938b0dSPhilippe Houdoin return B_BAD_VALUE;
4067938b0dSPhilippe Houdoin
4167938b0dSPhilippe Houdoin // prepare zlib stream
4267938b0dSPhilippe Houdoin z_stream zStream = {
4367938b0dSPhilippe Houdoin (Bytef*)compressed, // next_in
4467938b0dSPhilippe Houdoin compressedSize, // avail_in
4567938b0dSPhilippe Houdoin 0, // total_in
4667938b0dSPhilippe Houdoin (Bytef*)uncompressed, // next_out
4767938b0dSPhilippe Houdoin uncompressedSize, // avail_out
4867938b0dSPhilippe Houdoin 0, // total_out
4967938b0dSPhilippe Houdoin 0, // msg
5067938b0dSPhilippe Houdoin 0, // state
5167938b0dSPhilippe Houdoin Z_NULL, // zalloc (kernel_args_malloc?)
5267938b0dSPhilippe Houdoin Z_NULL, // zfree (kernel_args_free?)
5367938b0dSPhilippe Houdoin Z_NULL, // opaque
5467938b0dSPhilippe Houdoin 0, // data_type
5567938b0dSPhilippe Houdoin 0, // adler
5667938b0dSPhilippe Houdoin 0 // reserved
5767938b0dSPhilippe Houdoin };
5867938b0dSPhilippe Houdoin
5967938b0dSPhilippe Houdoin int zlibError = inflateInit(&zStream);
6067938b0dSPhilippe Houdoin if (zlibError != Z_OK)
6167938b0dSPhilippe Houdoin return B_ERROR; // TODO: translate zlibError
6267938b0dSPhilippe Houdoin
6367938b0dSPhilippe Houdoin // inflate
6467938b0dSPhilippe Houdoin status_t status = B_OK;
6567938b0dSPhilippe Houdoin zlibError = inflate(&zStream, Z_FINISH);
6667938b0dSPhilippe Houdoin if (zlibError != Z_STREAM_END) {
6767938b0dSPhilippe Houdoin if (zlibError == Z_OK)
6867938b0dSPhilippe Houdoin status = B_BUFFER_OVERFLOW;
6967938b0dSPhilippe Houdoin else
7067938b0dSPhilippe Houdoin status = B_ERROR; // TODO: translate zlibError
7167938b0dSPhilippe Houdoin }
7267938b0dSPhilippe Houdoin
7367938b0dSPhilippe Houdoin // clean up
7467938b0dSPhilippe Houdoin zlibError = inflateEnd(&zStream);
7567938b0dSPhilippe Houdoin if (zlibError != Z_OK && status == B_OK)
7667938b0dSPhilippe Houdoin status = B_ERROR; // TODO: translate zlibError
7767938b0dSPhilippe Houdoin
7867938b0dSPhilippe Houdoin if (status == B_OK && zStream.total_out != uncompressedSize)
7967938b0dSPhilippe Houdoin status = B_ERROR;
8067938b0dSPhilippe Houdoin
8167938b0dSPhilippe Houdoin return status;
8267938b0dSPhilippe Houdoin }
8367938b0dSPhilippe Houdoin
8467938b0dSPhilippe Houdoin
85029e447bSAugustin Cavalier extern "C" void
video_blit_image(addr_t frameBuffer,const uint8 * data,uint16 width,uint16 height,uint16 imageWidth,uint16 left,uint16 top)86029e447bSAugustin Cavalier video_blit_image(addr_t frameBuffer, const uint8 *data,
87029e447bSAugustin Cavalier uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
88029e447bSAugustin Cavalier {
89029e447bSAugustin Cavalier if (gKernelArgs.frame_buffer.depth == 4) {
90029e447bSAugustin Cavalier // call platform specific code since it's really platform-specific.
91029e447bSAugustin Cavalier platform_blit4(frameBuffer, data, width, height,
92029e447bSAugustin Cavalier imageWidth, left, top);
93029e447bSAugustin Cavalier } else {
94029e447bSAugustin Cavalier BlitParameters params;
95029e447bSAugustin Cavalier params.from = data;
96029e447bSAugustin Cavalier params.fromWidth = imageWidth;
97029e447bSAugustin Cavalier params.fromLeft = params.fromTop = 0;
98029e447bSAugustin Cavalier params.fromRight = width;
99029e447bSAugustin Cavalier params.fromBottom = height;
100029e447bSAugustin Cavalier params.to = (uint8*)frameBuffer;
101029e447bSAugustin Cavalier params.toBytesPerRow = gKernelArgs.frame_buffer.bytes_per_row;
102029e447bSAugustin Cavalier params.toLeft = left;
103029e447bSAugustin Cavalier params.toTop = top;
104029e447bSAugustin Cavalier blit(params, gKernelArgs.frame_buffer.depth);
105029e447bSAugustin Cavalier }
106029e447bSAugustin Cavalier }
107029e447bSAugustin Cavalier
108029e447bSAugustin Cavalier
1097db9fbfeSFrançois Revol extern "C" status_t
video_display_splash(addr_t frameBuffer)11004cbc258SFredrik Holmqvist video_display_splash(addr_t frameBuffer)
1117db9fbfeSFrançois Revol {
1127db9fbfeSFrançois Revol if (!gKernelArgs.frame_buffer.enabled)
1137db9fbfeSFrançois Revol return B_NO_INIT;
1147db9fbfeSFrançois Revol
11504cbc258SFredrik Holmqvist addr_t pos = 0;
11604cbc258SFredrik Holmqvist // Limit area to clear to estimated screen area
11704cbc258SFredrik Holmqvist // UEFI can happily report a >256M framebuffer
11804cbc258SFredrik Holmqvist addr_t size = min_c(gKernelArgs.frame_buffer.width
1191368eabbSFredrik Holmqvist * gKernelArgs.frame_buffer.height * 4u,
1207db9fbfeSFrançois Revol gKernelArgs.frame_buffer.physical_buffer.size);
1217db9fbfeSFrançois Revol
12204cbc258SFredrik Holmqvist if (size >= 64) {
12304cbc258SFredrik Holmqvist // Align writes
1241368eabbSFredrik Holmqvist for (addr_t align = (8 - (frameBuffer & 7)) & 7; pos < align; pos++)
12504cbc258SFredrik Holmqvist *(char*)(frameBuffer + pos) = 0;
12604cbc258SFredrik Holmqvist // Write eight bytes, many many times, but not too many
12704cbc258SFredrik Holmqvist for (addr_t alignSize = size - 8; pos < alignSize; pos +=8) {
12804cbc258SFredrik Holmqvist *(uint32*)(frameBuffer + pos) = 0;
12904cbc258SFredrik Holmqvist *(uint32*)(frameBuffer + pos + 4) = 0;
13004cbc258SFredrik Holmqvist }
13104cbc258SFredrik Holmqvist }
13204cbc258SFredrik Holmqvist // Write a few bytes more
13304cbc258SFredrik Holmqvist for (; pos < size; pos++)
13404cbc258SFredrik Holmqvist *(char*)(frameBuffer + pos) = 0;
13504cbc258SFredrik Holmqvist
1367db9fbfeSFrançois Revol uint8* uncompressedLogo = NULL;
13767938b0dSPhilippe Houdoin unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight;
1387db9fbfeSFrançois Revol switch (gKernelArgs.frame_buffer.depth) {
1397db9fbfeSFrançois Revol case 8:
1407db9fbfeSFrançois Revol platform_set_palette(k8BitPalette);
14167938b0dSPhilippe Houdoin uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
1427db9fbfeSFrançois Revol if (uncompressedLogo == NULL)
1437db9fbfeSFrançois Revol return B_NO_MEMORY;
14467938b0dSPhilippe Houdoin
14567938b0dSPhilippe Houdoin uncompress(kSplashLogo8BitCompressedImage,
14667938b0dSPhilippe Houdoin sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo,
14767938b0dSPhilippe Houdoin uncompressedSize);
1487db9fbfeSFrançois Revol break;
14967938b0dSPhilippe Houdoin default: // 24 bits is assumed here
15067938b0dSPhilippe Houdoin uncompressedSize *= 3;
15167938b0dSPhilippe Houdoin uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
1527db9fbfeSFrançois Revol if (uncompressedLogo == NULL)
1537db9fbfeSFrançois Revol return B_NO_MEMORY;
15467938b0dSPhilippe Houdoin
15567938b0dSPhilippe Houdoin uncompress(kSplashLogo24BitCompressedImage,
15667938b0dSPhilippe Houdoin sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo,
15767938b0dSPhilippe Houdoin uncompressedSize);
1587db9fbfeSFrançois Revol break;
1597db9fbfeSFrançois Revol }
1607db9fbfeSFrançois Revol
1617db9fbfeSFrançois Revol // TODO: support 4-bit indexed version of the images!
1627db9fbfeSFrançois Revol
1637db9fbfeSFrançois Revol // render splash logo
164*de8d5cfbSAugustin Cavalier int width, height, x, y;
165*de8d5cfbSAugustin Cavalier compute_splash_logo_placement(gKernelArgs.frame_buffer.width, gKernelArgs.frame_buffer.height,
166*de8d5cfbSAugustin Cavalier width, height, x, y);
1677db9fbfeSFrançois Revol video_blit_image(frameBuffer, uncompressedLogo, width, height,
1687db9fbfeSFrançois Revol kSplashLogoWidth, x, y);
1697db9fbfeSFrançois Revol
1707db9fbfeSFrançois Revol kernel_args_free(uncompressedLogo);
1717db9fbfeSFrançois Revol
1727db9fbfeSFrançois Revol const uint8* lowerHalfIconImage;
17367938b0dSPhilippe Houdoin uncompressedSize = kSplashIconsWidth * kSplashIconsHeight;
174*de8d5cfbSAugustin Cavalier const uint16 iconsHalfHeight = kSplashIconsHeight / 2;
1757db9fbfeSFrançois Revol switch (gKernelArgs.frame_buffer.depth) {
1767db9fbfeSFrançois Revol case 8:
1777db9fbfeSFrançois Revol // pointer into the lower half of the icons image data
1787db9fbfeSFrançois Revol gKernelArgs.boot_splash
17967938b0dSPhilippe Houdoin = (uint8*)kernel_args_malloc(uncompressedSize);
18062d36f98SAlex Smith if (gKernelArgs.boot_splash == NULL)
1817db9fbfeSFrançois Revol return B_NO_MEMORY;
18267938b0dSPhilippe Houdoin uncompress(kSplashIcons8BitCompressedImage,
18367938b0dSPhilippe Houdoin sizeof(kSplashIcons8BitCompressedImage),
18467938b0dSPhilippe Houdoin gKernelArgs.boot_splash, uncompressedSize);
185d8efc6caSAlex Smith lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
1867db9fbfeSFrançois Revol + (kSplashIconsWidth * iconsHalfHeight);
1877db9fbfeSFrançois Revol break;
18867938b0dSPhilippe Houdoin default: // 24bits is assumed here
18967938b0dSPhilippe Houdoin uncompressedSize *= 3;
1907db9fbfeSFrançois Revol // pointer into the lower half of the icons image data
1917db9fbfeSFrançois Revol gKernelArgs.boot_splash
19267938b0dSPhilippe Houdoin = (uint8*)kernel_args_malloc(uncompressedSize);
19362d36f98SAlex Smith if (gKernelArgs.boot_splash == NULL)
1947db9fbfeSFrançois Revol return B_NO_MEMORY;
19567938b0dSPhilippe Houdoin uncompress(kSplashIcons24BitCompressedImage,
19667938b0dSPhilippe Houdoin sizeof(kSplashIcons24BitCompressedImage),
19767938b0dSPhilippe Houdoin gKernelArgs.boot_splash, uncompressedSize);
198d8efc6caSAlex Smith lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
1997db9fbfeSFrançois Revol + (kSplashIconsWidth * iconsHalfHeight) * 3;
2007db9fbfeSFrançois Revol break;
2017db9fbfeSFrançois Revol }
2027db9fbfeSFrançois Revol
2037db9fbfeSFrançois Revol // render initial (grayed out) icons
2047db9fbfeSFrançois Revol // the grayed out version is the lower half of the icons image
205*de8d5cfbSAugustin Cavalier compute_splash_icons_placement(gKernelArgs.frame_buffer.width, gKernelArgs.frame_buffer.height,
206*de8d5cfbSAugustin Cavalier width, height, x, y);
2077db9fbfeSFrançois Revol
2087db9fbfeSFrançois Revol video_blit_image(frameBuffer, lowerHalfIconImage, width, height,
2097db9fbfeSFrançois Revol kSplashIconsWidth, x, y);
210477d2636SFrançois Revol return B_OK;
2117db9fbfeSFrançois Revol }
212