summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@arm.linux.org.uk>2016-03-09 22:55:25 +0000
committerRussell King <rmk@arm.linux.org.uk>2016-03-09 22:55:25 +0000
commitd3bc22162ee3f6635844c4c9ab6a50db6b911c51 (patch)
tree1a9e5e7802de086183dcf9ba54c2a4423becff0b
parent4b8042d79670239b14ae18158eb68227b5b8290d (diff)
detile: major update to detiler
Update the detiler to accept command line options for width and height, as well as selecting between normal tiling and multitiling modes. Optionally accept the file to be detiled on the command line too, and read it into memory if we aren't able to mmap() it. Lastly, improve the safety of writing the resulting image out by handling short writes and signals gracefully. Signed-off-by: Russell King <rmk@arm.linux.org.uk>
-rw-r--r--detile/viv-demultitile.c162
1 files changed, 148 insertions, 14 deletions
diff --git a/detile/viv-demultitile.c b/detile/viv-demultitile.c
index 1162bef..5968cae 100644
--- a/detile/viv-demultitile.c
+++ b/detile/viv-demultitile.c
@@ -1,10 +1,62 @@
+#include <errno.h>
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
+static int safe_write(int fd, void *buf, size_t size)
+{
+ size_t written = 0;
+ ssize_t ret = 0;
+
+ while (size) {
+ ret = write(fd, buf, size);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ } else if (ret > 0) {
+ written += ret;
+ buf += ret;
+ size -= ret;
+ } else if (written) {
+ ret = written;
+ break;
+ } else {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int safe_read(int fd, void *buf, size_t size)
+{
+ size_t rd = 0;
+ ssize_t ret = 0;
+
+ while (size) {
+ ret = read(fd, buf, size);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ } else if (ret > 0) {
+ rd += ret;
+ buf += ret;
+ size -= ret;
+ } else if (rd) {
+ ret = rd;
+ break;
+ } else {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
static void detile_gen(void *dst, void *src, unsigned int unit_size,
unsigned int tile_width, unsigned int tile_height,
unsigned int blocks_x, unsigned int blocks_y)
@@ -44,8 +96,9 @@ static void demultitile(void *dst, void *src, unsigned ps, unsigned w, unsigned
int x, y;
/*
- * u1 u2 l1 l2 u5 u6 l5 l6
- * l3 l4 u3 u4 l7 l8 u7 u8
+ * 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64
+ * u1 u2 l1 l2 u5 u6 l5 l6 u9 u10 l9 l10 u13 u14 l13 l14
+ * l3 l4 u3 u4 l7 l8 u7 u8 l11 l12 u11 u12 l15 l16 u15 u16
*/
tile_bytes = ps * 4 * 4; /* each 4x4 tile */
@@ -54,9 +107,11 @@ static void demultitile(void *dst, void *src, unsigned ps, unsigned w, unsigned
src_u = src;
src_l = src + tile_stride * tile_h / 2;
- fprintf(stderr, "tile bytes = 0x%x\n", tile_bytes);
- fprintf(stderr, "tile stride = 0x%x\n", tile_stride);
- fprintf(stderr, "u -> l = 0x%x\n", src_l - src_u);
+ if (0) {
+ fprintf(stderr, "tile bytes = 0x%x\n", tile_bytes);
+ fprintf(stderr, "tile stride = 0x%x\n", tile_stride);
+ fprintf(stderr, "u -> l = 0x%x\n", src_l - src_u);
+ }
for (y = 0; y < tile_h / 2; y++) {
void *dpyu = tmp + y * 2 * tile_stride;
@@ -89,22 +144,101 @@ int main(int argc, char *argv[])
{
struct stat st;
void *ptr, *out;
+ int fd = 0;
+ int opt, ret, cpp = 4, width = 0, height = -1, multitile = 0;
+ size_t size;
+
+ while ((opt = getopt(argc, argv, "w:h:m")) != -1) {
+ switch (opt) {
+ case 'w':
+ width = strtoul(optarg, NULL, 10);
+ break;
+ case 'h':
+ height = strtoul(optarg, NULL, 10);
+ break;
+ case 'm':
+ multitile = 1;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-w WIDTH] [-h HEIGHT] [FILE]\n",
+ argv[0]);
+ return 1;
+ }
+ }
- if (fstat(0, &st) == -1) {
- perror("failed to stat");
- return 1;
+ if (optind < argc) {
+ fd = open(argv[optind], O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: %s: %m\n", argv[0], argv[optind]);
+ return 1;
+ }
+ } else {
+ fd = dup(0);
}
- ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, 0, 0);
- if (ptr == (void *)-1) {
- perror("failed to mmap");
+ if (fstat(fd, &st) == -1) {
+ fprintf(stderr, "%s: failed to stat: %m\n", argv[0]);
+ close(fd);
return 1;
}
- out = malloc(st.st_size);
+ if (height == -1)
+ height = st.st_size / (width * cpp);
+
+ size = cpp * width * height;
+ if (st.st_size) {
+ if (size > st.st_size) {
+ fprintf(stderr, "%s: width/height exceeds file size\n",
+ argv[0]);
+ close(fd);
+ return 1;
+ }
+
+ ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (ptr == (void *)-1) {
+ fprintf(stderr, "%s: failed to mmap: %m", argv[0]);
+ close(fd);
+ return 1;
+ }
+ } else {
+ ptr = malloc(size);
+ if (!ptr) {
+ fprintf(stderr, "%s: out of memory\n", argv[0]);
+ close(fd);
+ return 1;
+ }
+ ret = safe_read(fd, ptr, size);
+ if (ret < 0) {
+ fprintf(stderr, "%s: %m\n", argv[0]);
+ free(ptr);
+ close(fd);
+ return 1;
+ } else if (ret != size) {
+ fprintf(stderr, "%s: short read\n", argv[0]);
+ free(ptr);
+ close(fd);
+ return 1;
+ }
+ }
+
+ out = malloc(size);
+
+ if (multitile)
+ demultitile(out, ptr, cpp, width, height);
+ else
+ detile(out, ptr, cpp, width, height);
+
+ ret = safe_write(1, out, size);
- demultitile(out, ptr, 4, 256, 256);
+ free(out);
+
+ if (ret < 0) {
+ fprintf(stderr, "%s: write: %m\n", argv[0]);
+ return 1;
+ } else if (ret != size) {
+ fprintf(stderr, "%s: short write\n", argv[0]);
+ return 1;
+ }
- write(1, out, st.st_size);
return 0;
}