196 lines
5.5 KiB
C
196 lines
5.5 KiB
C
/*
|
|
* Copyright (C) Texas Instruments - http://www.ti.com/
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include <cutils/log.h>
|
|
#include <cutils/properties.h>
|
|
#include <png.h>
|
|
|
|
#include <linux/fb.h>
|
|
|
|
#include "hwc_dev.h"
|
|
#include "dock_image.h"
|
|
|
|
static struct dock_image_state {
|
|
void *buffer; /* start of fb for hdmi */
|
|
uint32_t buffer_size; /* size of fb for hdmi */
|
|
|
|
uint32_t max_width;
|
|
uint32_t max_height;
|
|
|
|
image_info_t image;
|
|
} dock_image;
|
|
|
|
static void free_png_image(image_info_t *img)
|
|
{
|
|
memset(img, 0, sizeof(*img));
|
|
}
|
|
|
|
static int load_png_image(char *path, image_info_t *img)
|
|
{
|
|
static png_bytepp row_pointers = NULL; /* static prevents setjmp corruption. */
|
|
|
|
FILE *fd = fopen(path, "rb");
|
|
if (!fd) {
|
|
ALOGE("failed to open PNG file %s: (%d)", path, errno);
|
|
return -EINVAL;
|
|
}
|
|
|
|
const int SIZE_PNG_HEADER = 8;
|
|
uint8_t header[SIZE_PNG_HEADER];
|
|
fread(header, 1, SIZE_PNG_HEADER, fd);
|
|
if (png_sig_cmp(header, 0, SIZE_PNG_HEADER)) {
|
|
ALOGE("%s is not a PNG file", path);
|
|
goto fail;
|
|
}
|
|
|
|
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
if (!png_ptr)
|
|
goto fail_alloc;
|
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
|
if (!info_ptr)
|
|
goto fail_alloc;
|
|
|
|
if (setjmp(png_jmpbuf(png_ptr)))
|
|
goto fail_alloc;
|
|
|
|
png_init_io(png_ptr, fd);
|
|
png_set_sig_bytes(png_ptr, SIZE_PNG_HEADER);
|
|
png_set_user_limits(png_ptr, dock_image.max_width, dock_image.max_height);
|
|
png_read_info(png_ptr, info_ptr);
|
|
|
|
uint8_t bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
|
uint32_t width = png_get_image_width(png_ptr, info_ptr);
|
|
uint32_t height = png_get_image_height(png_ptr, info_ptr);
|
|
uint8_t color_type = png_get_color_type(png_ptr, info_ptr);
|
|
|
|
switch (color_type) {
|
|
case PNG_COLOR_TYPE_PALETTE:
|
|
png_set_palette_to_rgb(png_ptr);
|
|
png_set_filler(png_ptr, 128, PNG_FILLER_AFTER);
|
|
break;
|
|
case PNG_COLOR_TYPE_GRAY:
|
|
if (bit_depth < 8) {
|
|
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
|
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
|
|
png_set_tRNS_to_alpha(png_ptr);
|
|
} else {
|
|
png_set_filler(png_ptr, 128, PNG_FILLER_AFTER);
|
|
}
|
|
/* fall through */
|
|
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
png_set_gray_to_rgb(png_ptr);
|
|
break;
|
|
case PNG_COLOR_TYPE_RGB:
|
|
png_set_filler(png_ptr, 128, PNG_FILLER_AFTER);
|
|
/* fall through */
|
|
case PNG_COLOR_TYPE_RGB_ALPHA:
|
|
png_set_bgr(png_ptr);
|
|
break;
|
|
default:
|
|
ALOGE("unsupported PNG color: %x", color_type);
|
|
goto fail_alloc;
|
|
}
|
|
|
|
if (bit_depth == 16)
|
|
png_set_strip_16(png_ptr);
|
|
|
|
const uint32_t bpp = 4;
|
|
img->size = ALIGN(width * height * bpp, 4096);
|
|
if ((uint32_t)img->size > dock_image.buffer_size) {
|
|
ALOGE("image does not fit into framebuffer area (%d > %d)", img->size, dock_image.buffer_size);
|
|
goto fail_alloc;
|
|
}
|
|
img->ptr = dock_image.buffer;
|
|
|
|
row_pointers = calloc(height, sizeof(*row_pointers));
|
|
if (!row_pointers) {
|
|
ALOGE("failed to allocate row pointers");
|
|
goto fail_alloc;
|
|
}
|
|
uint32_t i;
|
|
for (i = 0; i < height; i++)
|
|
row_pointers[i] = img->ptr + i * width * bpp;
|
|
png_set_rows(png_ptr, info_ptr, row_pointers);
|
|
png_read_update_info(png_ptr, info_ptr);
|
|
img->rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
|
|
|
png_read_image(png_ptr, row_pointers);
|
|
png_read_end(png_ptr, NULL);
|
|
free(row_pointers);
|
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
|
fclose(fd);
|
|
img->width = width;
|
|
img->height = height;
|
|
return 0;
|
|
|
|
fail_alloc:
|
|
free_png_image(img);
|
|
free(row_pointers);
|
|
if (!png_ptr || !info_ptr)
|
|
ALOGE("failed to allocate PNG structures");
|
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
|
fail:
|
|
fclose(fd);
|
|
return -EINVAL;
|
|
}
|
|
|
|
int init_dock_image(omap_hwc_device_t *hwc_dev, uint32_t max_width, uint32_t max_height)
|
|
{
|
|
int err = 0;
|
|
|
|
struct fb_fix_screeninfo fix;
|
|
if (ioctl(hwc_dev->fb_fd, FBIOGET_FSCREENINFO, &fix)) {
|
|
ALOGE("failed to get fb info (%d)", errno);
|
|
err = -errno;
|
|
goto done;
|
|
}
|
|
|
|
dock_image.buffer_size = fix.smem_len;
|
|
dock_image.buffer = mmap(NULL, fix.smem_len, PROT_WRITE, MAP_SHARED, hwc_dev->fb_fd, 0);
|
|
if (dock_image.buffer == MAP_FAILED) {
|
|
ALOGE("failed to map fb memory");
|
|
err = -errno;
|
|
goto done;
|
|
}
|
|
|
|
dock_image.max_width = max_width;
|
|
dock_image.max_height = max_height;
|
|
|
|
done:
|
|
return err;
|
|
}
|
|
|
|
void load_dock_image()
|
|
{
|
|
if (!dock_image.image.rowbytes) {
|
|
char value[PROPERTY_VALUE_MAX];
|
|
property_get("persist.hwc.dock_image", value, "/vendor/res/images/dock/dock.png");
|
|
load_png_image(value, &dock_image.image);
|
|
}
|
|
}
|
|
|
|
image_info_t *get_dock_image()
|
|
{
|
|
return &dock_image.image;
|
|
}
|
|
|