summaryrefslogtreecommitdiff
path: root/test/test1
diff options
context:
space:
mode:
authorlibdlo <libdlo@displaylink.com>2009-05-13 15:01:59 -0700
committerlibdlo <libdlo@displaylink.com>2009-05-13 15:01:59 -0700
commit08128c66469b26ee44d8f43641c9c4aad81bbd3d (patch)
tree208b96a5a4c1f122cfb214824ec4b19f4682f4cd /test/test1
parentce1c0c08f74c41be2d47ddee2c40b5850521053f (diff)
Repurpose maintainer-clean to get to clean autotools files
so changes that need to be committed via git are more clear.
Diffstat (limited to 'test/test1')
-rw-r--r--test/test1/Makefile.am4
-rw-r--r--test/test1/test1.c1881
2 files changed, 947 insertions, 938 deletions
diff --git a/test/test1/Makefile.am b/test/test1/Makefile.am
index cb2d0f2..0a8fe23 100644
--- a/test/test1/Makefile.am
+++ b/test/test1/Makefile.am
@@ -1,2 +1,4 @@
bin_PROGRAMS = test1
-test1_SOURCES = test1.c \ No newline at end of file
+test1_SOURCES = test1.c
+test1_LDADD = ../../src/libdlo.la
+test1_LDFLAGS = -lusb \ No newline at end of file
diff --git a/test/test1/test1.c b/test/test1/test1.c
index 9c1b2ea..071764d 100644
--- a/test/test1/test1.c
+++ b/test/test1/test1.c
@@ -1,937 +1,944 @@
-/** @file test1.c
- *
- * @brief This file demonstrates basic graphics primitive features of libdlo.
- *
- * DisplayLink Open Source Software (libdlo)
- * Copyright (C) 2009, DisplayLink
- * www.displaylink.com
- *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Library General Public License as published by the Free
- * Software Foundation; LGPL version 2, dated June 1991.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "sys/time.h"
-#include "libdlo.h"
-#include "dlo_defs.h"
-
-
-/** Default horizontal resolution we will use for tests (pixels).
- */
-#define SCREEN_X (1280)
-
-/** Default vertical resolution we will use for tests (pixels).
- */
-#define SCREEN_Y (1024)
-
-/** Default screen refresh rate we will use for tests (Hz).
- */
-#define SCREEN_RATE (0)
-
-/** Default screen colour depth we will use for tests (bits per pixel).
- */
-#define SCREEN_BPP (24)
-
-/** Number of random dots to plot.
- */
-#define NUM_DOTS (299)
-
-/** Number of random rectangles to plot.
- */
-#define NUM_RECTS (99)
-
-/** Number of steps (gradient) in colour blended rectangles.
- */
-#define NUM_GRAD (99)
-
-/** Division factor for scale of central rectangle.
- */
-#define MID_REC_DIV (5)
-
-/** Windows BMP magic ID bytes.
- */
-#define BMP_MAGIC (0x4D42)
-
-/** Given a bits per pixel value, return the bytes per pixel.
- */
-#define BYTES_PER_PIXEL(bpp) (unsigned int)(((bpp) + 7) / 8)
-
-/** Horizontal subdivision of the screen for overlapping rectangle copy tests.
- */
-#define ZONE_X (SCREEN_X / 3)
-
-/** Vertical subdivision of the screen for overlapping rectangle copy tests.
- */
-#define ZONE_Y (SCREEN_Y / 3)
-
-/** Horizontal size of the rectangle to copy in the overlapping rectangle copy tests.
- */
-#define COPY_X (ZONE_X / 2)
-
-/** Vertical size of the rectangle to copy in the overlapping rectangle copy tests.
- */
-#define COPY_Y (ZONE_Y / 2)
-
-/** Size of a component of a rectangle copy offset (horizontal or vertical).
- */
-#define STEP (80)
-
-
-/** Array of offsets for overlapping rectangle copy test.
- */
-const dlo_dot_t overlap[9] =
-{
- { -STEP, -STEP },
- { 0, -STEP },
- { STEP, -STEP },
- { -STEP, 0 },
- { 0, 0 },
- { STEP, 0 },
- { -STEP, STEP },
- { 0, STEP },
- { STEP, STEP }
-};
-
-
-/** The main header block from a Windows BMP file.
- */
-typedef struct __packed bmp_header_s
-{
- uint16_t magic; /**< Magic ID bytes for Windows BMP format. */
- uint32_t file_sz; /**< Total bitmap file size (bytes). */
- uint16_t reserved1; /**< Unused. */
- uint16_t reserved2; /**< Unused. */
- uint32_t pix_offset; /**< Offset from start of file to start of pixel data (bytes). */
-} bmp_header_t; /**< A struct @a bmp_header_s. */
-
-
-/** The DIB header block from a Windows BMP file.
- */
-typedef struct __packed dib_header_s
-{
- uint32_t dib_hdr_sz; /**< Size of the DIB header block (bytes). */
- uint32_t width; /**< Width of the bitmap (pixels). */
- uint32_t height; /**< Height of the bitmap (pixels). */
- uint16_t col_planes; /**< Number of colour planes. */
- uint16_t bpp; /**< Bits per pixel. */
- uint32_t compression; /**< Compression, pixel format. */
- uint32_t raw_size; /**< Size of the raw pixel data. */
- uint32_t x_pix_meter; /**< Horizontal resolution (pixels per meter). */
- uint32_t y_pix_meter; /**< Vertical resolution (pixels per meter). */
- uint32_t pal_entries; /**< Number of palette entries. */
- uint32_t imp_cols; /**< Important colours (ignored). */
-} dib_header_t; /**< A struct @a dib_header_s. */
-
-
-/** A Windows BMP file.
- */
-typedef struct __packed bmp_s
-{
- bmp_header_t hdr; /**< Windows BMP header block. */
- dib_header_t dib; /**< DIB header block. */
- uint8_t data[]; /**< Pixel data. */
-} bmp_t; /**< A struct @a bmp_s. */
-
-
-/** Report an error and exit.
- *
- * @param str Pointer to the error message string.
- */
-static void my_error(const char * const str)
-{
- printf("test: ERROR: %s\n", str);
- exit(1);
-}
-
-
-/** Return the microsecond time, as an unsigned 64 bit integer.
- *
- * @return Number of microseconds since the start of the Epoch.
- */
-static uint64_t now(void)
-{
- static struct timeval unix_time = { 0 };
- static struct timeval *unix_time_ptr = &unix_time;
-
- gettimeofday(unix_time_ptr, NULL);
- return ((uint64_t)unix_time.tv_sec * 1000000ll) + (uint64_t)unix_time.tv_usec;
-}
-
-
-/** Pause execution for the specified number of centiseconds.
- *
- * @param from Time to start the pause interval.
- * @param millisec Number of milliseconds to pause for.
- */
-static void wait_ms(const uint64_t from, const uint64_t millisec)
-{
- uint64_t to = from + (millisec * 1000);
-
- while (to > now()) ;
-}
-
-
-/** Plot a rectangular outline in the specified colour.
- *
- * @param uid Unique ID of the device.
- * @param view Viewport for plot destination.
- * @param rec Rectangle co-ordinates within the viewport.
- * @param col Colour of rectangle.
- *
- * @return Return code, zero for no error.
- */
-static dlo_retcode_t box(const dlo_dev_t uid, const dlo_view_t * const view, const dlo_rect_t * const rec, const dlo_col32_t col)
-{
- dlo_rect_t line;
-
- line.origin.x = rec->origin.x;
- line.origin.y = rec->origin.y;
- line.width = rec->width;
- line.height = 1;
- ERR(dlo_fill_rect(uid, view, &line, col));
-
- line.width = 1;
- line.height = rec->height;
- ERR(dlo_fill_rect(uid, view, &line, col));
-
- line.origin.y += line.height - 1;
- line.width = rec->width;
- line.height = 1;
- ERR(dlo_fill_rect(uid, view, &line, col));
-
- line.origin.x += line.width;
- line.origin.y = rec->origin.y;
- line.width = 1;
- line.height = rec->height;
- ERR(dlo_fill_rect(uid, view, &line, col));
-
- return dlo_ok;
-}
-
-
-/** Test the basic graphics primitives (filled rectangle and rectangle copy).
- *
- * @param uid Unique ID of the device.
- *
- * @return Return code, zero for no error.
- */
-static dlo_retcode_t basic_grfx_test(const dlo_dev_t uid)
-{
- dlo_mode_t mode;
- dlo_mode_t *mode_info;
- dlo_devinfo_t *dev_info;
- dlo_view_t *view;
- dlo_rect_t rec;
- dlo_dot_t dot;
- uint32_t i;
- uint64_t start;
-
- /* Read some information on the device */
- dev_info = dlo_device_info(uid);
- NERR(dev_info);
- printf("test: device info: uid &%X\n", (int)dev_info->uid);
- printf("test: device info: serial '%s'\n", dev_info->serial);
- printf("test: device info: type &%X\n", (uint32_t)dev_info->type);
-
- /* Read current mode information (if we're already in the display's native mode) */
- mode_info = dlo_get_mode(uid);
- NERR(mode_info);
- printf("test: native mode info...\n");
- printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
-
- /* Select a fairly standard mode */
- printf("test: set_mode...\n");
- mode.view.width = SCREEN_X;
- mode.view.height = SCREEN_Y;
- mode.view.bpp = SCREEN_BPP;
- mode.view.base = 0;
- mode.refresh = SCREEN_RATE;
- ERR(dlo_set_mode(uid, &mode));
-
- /* Read current mode information */
- mode_info = dlo_get_mode(uid);
- NERR(mode_info);
- printf("test: mode info...\n");
- printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
- view = &(mode_info->view);
-
- /* Clear screen */
- printf("test: cls...");
- start = now();
- ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Plot some random white dots */
- printf("test: random white dots...");
- start = now();
- rec.width = 1;
- rec.height = 1;
- for (i = 0; i < NUM_DOTS; i++)
- {
- rec.origin.x = rand() % view->width;
- rec.origin.y = rand() % view->height;
- ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
- }
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Plot random filled rectangles */
- printf("test: random rectangles...");
- start = now();
- for (i = 0; i < NUM_RECTS; i++)
- {
- rec.width = rand() % (view->width / 4);
- rec.height = rand() % (view->height / 4);
- rec.origin.x = (rand() % (uint32_t)(1.25 * view->width)) - (view->width / 8);
- rec.origin.y = (rand() % (uint32_t)(1.25 * view->height)) - (view->height / 8);
- ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(rand() % 0xFF, rand() % 0xFF, rand() % 0xFF)));
- }
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Plot a set of rectangles, one over the other (colour gradient) */
- printf("test: central rectangles...");
- start = now();
- for (i = 0; i < NUM_GRAD; i++)
- {
- dlo_col32_t col = DLO_RGB((i*3) % 256, (i*5) % 256, 255 - ((i*7) % 256));
-
- rec.width = (view->width / MID_REC_DIV) - 2*i;
- rec.height = (view->height / MID_REC_DIV) - 2*i;
- rec.origin.x = i + (view->width / 2) - (view->width / MID_REC_DIV / 2);
- rec.origin.y = i + (view->height / 2) - (view->height/ MID_REC_DIV / 2);
- ERR(dlo_fill_rect(uid, view, &rec, col));
- }
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Plot the outline of the box we're going to copy */
- printf("test: white box outline...");
- start = now();
- rec.width = view->width / MID_REC_DIV;
- rec.height = view->height / MID_REC_DIV;
- rec.origin.x = (view->width / 2) - (rec.width / 2);
- rec.origin.y = (view->height / 2) - (rec.height / 2);
- ERR(box(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Copy a rectangle from the centre of the screen to other locations */
- printf("test: copy central box...");
- start = now();
- rec.origin.x++;
- rec.origin.y++;
- rec.width -= 2;
- rec.height -= 2;
- dot.x = 8;
- dot.y = 8;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.x = view->width - 8 - rec.width;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.y = view->height - 8 - rec.height;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.x = 8;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Check that basic clipping works */
- printf("test: copy central box (off edges of viewport)...");
- start = now();
- dot.x = -(rec.width / 2);
- dot.y = (view->height / 2) - (rec.height / 2) - 32;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.x += view->width;
- dot.y += 64;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.x = (view->width / 2) - (rec.width / 2) - 128;
- dot.y = -(rec.height / 2);
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- dot.x += 256;
- dot.y += view->height;
- ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- return dlo_ok;
-}
-
-
-/** Plot a few coloured rectangles one above another.
- *
- * @param uid Unique ID of the device.
- * @param inrec Input rectangle (the outer bounding box of the design).
- *
- * @return Return code, zero for no error.
- */
-static dlo_retcode_t squares(const dlo_dev_t uid, const dlo_rect_t * const inrec)
-{
- dlo_rect_t rec = *inrec;
-
- /* Plot the outer (red) rectangle */
- ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0, 0)));
-
- /* Plot the middle (white) rectangle */
- rec.origin.x += 20;
- rec.origin.y += 20;
- rec.width -= 40;
- rec.height -= 40;
- ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0xCC, 0xCC)));
-
- /* Plot the inner (blue) rectangle */
- rec.origin.x += 20;
- rec.origin.y += 20;
- rec.width -= 40;
- rec.height -= 40;
-
- return dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0, 0xCC));
-}
-
-
-/** Test copying rectangles to and from overlapping regions (in various directions).
- *
- * @param uid Unique ID of the device.
- *
- * @return Return code, zero for no error.
- */
-static dlo_retcode_t overlap_test(const dlo_dev_t uid)
-{
- dlo_rect_t rec;
- dlo_dot_t mid, dot;
- uint32_t idx = 0;
-
- /* Clear screen to black */
- ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
-
- rec.width = COPY_X;
- rec.height = COPY_Y;
- for (mid.y = ZONE_Y / 2; mid.y < SCREEN_Y; mid.y += ZONE_Y)
- {
- for (mid.x = ZONE_X / 2; mid.x < SCREEN_X; mid.x += ZONE_X)
- {
- rec.origin.x = mid.x - (COPY_X / 2);
- rec.origin.y = mid.y - (COPY_Y / 2);
- dot.x = rec.origin.x + overlap[idx].x;
- dot.y = rec.origin.y + overlap[idx].y;
- idx++;
- ERR(squares(uid, &rec));
- ERR(dlo_copy_rect(uid, NULL, &rec, NULL, &dot));
- }
- }
- return dlo_ok;
-}
-
-
-/** Convert a bits per pixel value into a bytes per pixel value.
- *
- * @param bpp Bits per pixel.
- *
- * @return Bytes per pixel.
- */
-static uint8_t bpp_to_bytes(const uint32_t bpp)
-{
- return (uint8_t)((bpp + 7) / 8);
-}
-
-
-/** Test the use of viewports as screen banks (ensure clipping is working).
- *
- * @param uid Unique ID of the device.
- *
- * @return Return code, zero for no error.
- *
- * Create three viewports (screen banks) and switch the display between them.
- * While we're at it, test the filled rectangle plotting clips correctly and
- * doesn't overflow into surrounding screen banks or off the edges of the
- * screen.
- */
-static dlo_retcode_t viewport_test(const dlo_dev_t uid)
-{
- dlo_mode_t mode;
- dlo_mode_t *desc;
- dlo_view_t view[3];
- dlo_rect_t rec;
- uint32_t i;
- uint64_t start;
-
- /* Read current mode information */
- desc = dlo_get_mode(uid);
- NERR(desc);
-
- /* Create three viewports - each representing a screen bank */
- view[0] = desc->view;
- view[1] = view[0];
- view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
- view[2] = view[1];
- view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
-
- /* Clear screens to different colours */
- printf("test: cls (three banks)...");
- start = now();
- ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0xFF)));
- ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0xFF, 0)));
- ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0xFF, 0, 0)));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Plot a couple of rectangles in each bank to test the clipping */
- printf("test: plot crosses (three banks)...");
- start = now();
- rec.width = view[0].width / 8;
- rec.height = view[0].height * 1.5;
- rec.origin.x = (view[0].width / 2) - (rec.width / 2);
- rec.origin.y = -(view[0].height / 4);
- ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
- ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
- ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
- rec.width = view[0].width * 1.5;
- rec.height = view[0].height / 8;
- rec.origin.x = -(view[0].width / 4);
- rec.origin.y = (view[0].height / 2) - (rec.height / 2);
- ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
- ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
- ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
- printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
-
- /* Switch through the screen banks */
- for (i = 1; i < 4; i++)
- {
- wait_ms(now(), 1000);
-
- printf("test: switching to screen bank %u...\n", i % 3);
- mode.view.width = view[i % 3].width;
- mode.view.height = view[i % 3].height;
- mode.view.bpp = view[i % 3].bpp;
- mode.view.base = view[i % 3].base;
- mode.refresh = 0;
- ERR(dlo_set_mode(uid, &mode));
- }
-
- return dlo_ok;
-}
-
-
-/** Load a Windows BMP file into memory.
- *
- * @param bmpfile Pointer to the filename.
- *
- * @return Pointer to the loaded bitmap's structure (or NULL if failed).
- *
- * Load a bitmap from a file and create a @a dlo_fbuf_t structure to suit.
- * If the bitmap has a palette, we need to swap the red/blue order of the
- * colour components in order to convert the palette entries into
- * @a dlo_col32_t values.
- */
-static bmp_t *load_bmp(const char * const bmpfile)
-{
- long int size;
- bmp_t *bmp;
- FILE *fp;
-
- fp = fopen(bmpfile, "rb");
- if (!fp)
- return NULL;
-
- if (fseek(fp, 0, SEEK_END))
- return NULL;
-
- size = ftell(fp);
- if (size == -1L)
- return NULL;
-
- if (fseek(fp, 0, SEEK_SET))
- return NULL;
-
- bmp = malloc(size);
- if (!bmp)
- return NULL;
-
- if (1 != fread(bmp, size, 1, fp))
- goto error;
-
- if (bmp->hdr.magic != BMP_MAGIC)
- goto error;
-
- /* If there is a palette, we need to reverse the RGB component order */
- if (bmp->dib.pal_entries)
- {
- dlo_col32_t *palette;
- uint32_t i;
-
- palette = (dlo_col32_t *)((unsigned long)bmp + sizeof(bmp_header_t) + sizeof(dib_header_t));
-
- for (i = 0; i < bmp->dib.pal_entries; i++)
- {
- dlo_col32_t col = palette[i];
-
- palette[i] = DLO_RGB(DLO_RGB_GETBLU(col), DLO_RGB_GETGRN(col), DLO_RGB_GETRED(col));
- }
- }
- return bmp;
-
-error:
- free(bmp);
-
- return NULL;
-}
-
-
-/** Given a bitmap pointer, check various aspects of it and return a framebuffer structure pointer.
- *
- * @param bmp Pointer to a loaded bitmap structure.
- *
- * @return Pointer to a framebuffer structure associated with the bitmap.
- *
- * NOTE: the bitmap plotting code requires some special-case Windows BMP format
- * bitmaps as input; they must include a DIB header (very common) and their width
- * must be such that they don't require any padding bytes at the end of each pixel
- * row.
- *
- * The padding issue could be fixed very simply by calling the dlo_copy_host_bmp()
- * for each pixel row individually but for the sake of a simple demo, we impose
- * the constraint and make only one call to dlo_copy_host_bmp() here.
- */
-static dlo_fbuf_t *bmp_to_fbuf(const bmp_t * const bmp)
-{
- static dlo_fbuf_t fbuf;
-
- printf("bmp->hdr.magic %04X\n"
- "bmp->hdr.file_sz %08X (%u)\n"
- "bmp->hdr.reserved1 %04X\n"
- "bmp->hdr.reserved2 %04X\n"
- "bmp->hdr.pix_offset %08X\n"
- "bmp->dib.dib_hdr_sz %08X\n"
- "bmp->dib.width %08X (%u)\n"
- "bmp->dib.height %08X (%u)\n"
- "bmp->dib.col_planes %04X\n"
- "bmp->dib.bpp %04X (%u)\n"
- "bmp->dib.compression %08X\n"
- "bmp->dib.raw_size %08X (%u)\n"
- "bmp->dib.x_pix_meter %08X\n"
- "bmp->dib.y_pix_meter %08X\n"
- "bmp->dib.pal_entries %08X (%u)\n"
- "bmp->dib.imp_cols %08X\n",
- bmp->hdr.magic,
- bmp->hdr.file_sz, bmp->hdr.file_sz,
- bmp->hdr.reserved1,
- bmp->hdr.reserved2,
- bmp->hdr.pix_offset,
- bmp->dib.dib_hdr_sz,
- bmp->dib.width, bmp->dib.width,
- bmp->dib.height, bmp->dib.height,
- bmp->dib.col_planes,
- bmp->dib.bpp, bmp->dib.bpp,
- bmp->dib.compression,
- bmp->dib.raw_size, bmp->dib.raw_size,
- bmp->dib.x_pix_meter,
- bmp->dib.y_pix_meter,
- bmp->dib.pal_entries, bmp->dib.pal_entries,
- bmp->dib.imp_cols);
-
- if (bmp->dib.compression)
- my_error("Unsupported bitmap compression mode");
- if (bmp->dib.col_planes != 1)
- my_error("Unsupported bitmap colour plane specification");
- if ((bmp->dib.width * BYTES_PER_PIXEL(bmp->dib.bpp)) & 3)
- my_error("Bitmap width must be whole multiple of four bytes (no padding)");
-
- fbuf.width = bmp->dib.width;
- fbuf.height = bmp->dib.height;
- fbuf.base = bmp->hdr.pix_offset + (uint8_t *)bmp;
- fbuf.stride = fbuf.width;
- switch (bmp->dib.bpp)
- {
- case 8:
- {
- fbuf.fmt = (dlo_pixfmt_t)(sizeof(bmp_header_t) + sizeof(dib_header_t) + (uint8_t *)bmp);
- if (bmp->dib.pal_entries != 256)
- my_error("Unsupported bitmap palette size");
- break;
- }
- case 16:
- {
- fbuf.fmt = dlo_pixfmt_srgb1555;
- break;
- }
- case 24:
- {
- fbuf.fmt = dlo_pixfmt_rgb888;
- break;
- }
- case 32:
- {
- fbuf.fmt = dlo_pixfmt_argb8888;
- break;
- }
- default:
- my_error("Unsupported bitmap colour depth");
- }
- return &fbuf;
-}
-
-
-/** Run some tests involving the loading, scraping and plotting of a bitmap.
- *
- * @param uid Unique ID of the device.
- * @param bmpfile Pointer to a Windows BMP filename.
- *
- * @return Return code, zero for no error.
- *
- * Load a bitmap, clear the screen and plot the bitmap at the centre of the
- * screen as well as off each edge of the screen.
- */
-static dlo_retcode_t bitmap_test(const dlo_dev_t uid, const bool cross, const char * const bmpfile)
-{
- dlo_bmpflags_t flags = { 0 };
- dlo_retcode_t err;
- dlo_mode_t *desc;
- dlo_fbuf_t *fbuf;
- dlo_view_t view;
- dlo_dot_t dot;
- bmp_t *bmp;
-
- printf("\ntest: bitmap file '%s'\n", bmpfile);
-
- /* Read current mode information */
- desc = dlo_get_mode(uid);
- NERR(desc);
- view = desc->view;
-
- /* Clear screen to black */
- ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
-
- /* Load the Windows BMP bitmap file into memory */
- bmp = load_bmp(bmpfile);
- NERR(bmp);
-
- /* Initialise a dlo_fbuf structure from our loaded bitmap file */
- fbuf = bmp_to_fbuf(bmp);
- NERR_GOTO(fbuf);
-
- /* Test plotting of bitmap in centre of screen */
- dot.x = (view.width / 2) - (fbuf->width / 2);
- dot.y = (view.height / 2) - (fbuf->height / 2);
- flags.v_flip = 1;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
-
- /* Now a few plots that lie a little off the edges of the screen */
- flags.v_flip = 0;
- if (cross)
- {
- dot.y = -fbuf->height / 2;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.y += view.height;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.x = -fbuf->width / 2;
- dot.y = (view.height / 2) - (fbuf->height / 2);
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.x += view.width;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- }
- else
- {
- dot.x = -fbuf->width / 2;
- dot.y = -fbuf->height / 2;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.y += view.height;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.x += view.width;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- dot.y -= view.height;
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
- }
-
- /* Discard the bitmap */
- free(bmp);
-
- return dlo_ok;
-
-error:
- free(bmp);
- return err;
-}
-
-
-/** Run some screen scraping tests with a set of input bitmaps.
- *
- * @param uid Unique ID of the device.
- *
- * @return Return code, zero for no error.
- *
- * This test sequence checks that the @c dlo_copy_host_bmp() call works correctly for
- * a number of source pixel formats by loading some different bitmaps and scraping
- * directly from them (using their palette where required).
- */
-static dlo_retcode_t scrape_tests(const dlo_dev_t uid)
-{
- ERR(bitmap_test(uid, false, "images/test08.bmp"));
-
- wait_ms(now(), 1000);
- ERR(bitmap_test(uid, true, "images/test16.bmp"));
-
- wait_ms(now(), 1000);
- ERR(bitmap_test(uid, false, "images/test24.bmp"));
-
- wait_ms(now(), 1000);
- return bitmap_test(uid, true, "images/test32.bmp");
-}
-
-
-/** Test the clipping of bitmaps relative to other screen banks.
- *
- * @param uid Unique ID of the device.
- *
- * @return Return code, zero for no error.
- *
- * The point of this test is to plot lots of bitmaps in random positions (some
- * completely off-screen) into the middle of three screen banks. We switch between
- * each bank to check that the bitmaps only appear on the middle one and haven't
- * spilled over into the surrounding memory.
- */
-static dlo_retcode_t bmp_clip_test(const dlo_dev_t uid)
-{
- dlo_bmpflags_t flags = { 0 };
- dlo_retcode_t err;
- dlo_mode_t mode;
- dlo_mode_t *desc;
- dlo_fbuf_t *fbuf;
- dlo_view_t view[3];
- dlo_dot_t dot;
- bmp_t *bmp;
- uint32_t i;
-
- /* Read current mode information */
- desc = dlo_get_mode(uid);
- NERR(desc);
-
- /* Create three viewports - each representing a screen bank */
- view[0] = desc->view;
- view[1] = view[0];
- view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
- view[2] = view[1];
- view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
-
- /* Clear screen banks */
- wait_ms(now(), 2000);
- ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0x50)));
- ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0, 0)));
- ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0, 0x50, 0)));
-
- /* Load the Windows BMP bitmap file into memory */
- bmp = load_bmp("images/test08.bmp");
- NERR(bmp);
-
- /* Initialise a dlo_fbuf structure from our loaded bitmap file */
- fbuf = bmp_to_fbuf(bmp);
- NERR_GOTO(fbuf);
-
- /* Plot lots of bitmaps into the second screen bank */
- for (i = 0; i < 399; i++)
- {
- flags.v_flip = rand() % 2;
- dot.x = -fbuf->width + (rand() % (view[1].width + fbuf->width));
- dot.y = -fbuf->height + (rand() % (view[1].height + fbuf->height));
- ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, &view[1], &dot));
- }
-
- /* Switch to middle bank */
- wait_ms(now(), 2000);
- mode.view.width = view[1].width;
- mode.view.height = view[1].height;
- mode.view.bpp = view[1].bpp;
- mode.view.base = view[1].base;
- mode.refresh = 0;
- ERR_GOTO(dlo_set_mode(uid, &mode));
-
- /* Switch to third bank */
- wait_ms(now(), 2000);
- mode.view.width = view[2].width;
- mode.view.height = view[2].height;
- mode.view.bpp = view[2].bpp;
- mode.view.base = view[2].base;
- mode.refresh = 0;
- ERR_GOTO(dlo_set_mode(uid, &mode));
-
- /* Switch to middle bank */
- wait_ms(now(), 2000);
- mode.view.width = view[1].width;
- mode.view.height = view[1].height;
- mode.view.bpp = view[1].bpp;
- mode.view.base = view[1].base;
- mode.refresh = 0;
- ERR_GOTO(dlo_set_mode(uid, &mode));
-
- /* Discard the bitmap */
- free(bmp);
-
- return dlo_ok;
-
-error:
- free(bmp);
- return err;
-}
-
-
-/**********************************************************************/
-int main(int argc, char *argv[])
-{
- dlo_init_t ini_flags = { 0 };
- dlo_final_t fin_flags = { 0 };
- dlo_claim_t cnf_flags = { 0 };
- dlo_retcode_t err;
- dlo_dev_t uid = 0;
-
- IGNORE(argc);
- IGNORE(argv);
-
- /* Initialise the random number generator with the microsecond time as a seed */
- srand((unsigned int)now());
-
- /* Initialise libdlo */
- printf("test: init...\n");
- ERR_GOTO(dlo_init(ini_flags));
-
- /* Look for a DisplayLink device to connect to */
- uid = dlo_claim_first_device(cnf_flags, 0);
-
- /* If we found one, perform some tests with it */
- if (uid)
- {
- printf("\ntest: basic graphics tests...\n");
- ERR_GOTO(basic_grfx_test(uid));
- wait_ms(now(), 3000);
-
- printf("\test: overlapping copy tests...\n");
- ERR_GOTO(overlap_test(uid));
-
- wait_ms(now(), 3000);
-
- printf("\ntest: viewport tests...\n");
- ERR_GOTO(viewport_test(uid));
-
- printf("\ntest: screen scraping tests...\n");
- ERR_GOTO(scrape_tests(uid));
-
- printf("test: bitmap clipping test...\n");
- ERR_GOTO(bmp_clip_test(uid));
-
- printf("test: release &%X...\n", (uintptr_t)uid);
- ERR_GOTO(dlo_release_device(uid));
- }
-
- /* Finalise libdlo, free up resources */
- printf("test: final...\n");
- ERR_GOTO(dlo_final(fin_flags));
- printf("test: finished.\n");
- return 0;
-
-error:
- printf("test: error %u '%s'\n", (int)err, dlo_strerror(err));
- return 0;
-}
+/** @file test1.c
+ *
+ * @brief This file demonstrates basic graphics primitive features of libdlo.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "sys/time.h"
+#include "libdlo.h"
+#include "../../src/dlo_defs.h"
+
+
+/** Default horizontal resolution we will use for tests (pixels).
+ */
+#define SCREEN_X (1280)
+
+/** Default vertical resolution we will use for tests (pixels).
+ */
+#define SCREEN_Y (1024)
+
+/** Default screen refresh rate we will use for tests (Hz).
+ */
+#define SCREEN_RATE (0)
+
+/** Default screen colour depth we will use for tests (bits per pixel).
+ */
+#define SCREEN_BPP (24)
+
+/** Number of random dots to plot.
+ */
+#define NUM_DOTS (299)
+
+/** Number of random rectangles to plot.
+ */
+#define NUM_RECTS (99)
+
+/** Number of steps (gradient) in colour blended rectangles.
+ */
+#define NUM_GRAD (99)
+
+/** Division factor for scale of central rectangle.
+ */
+#define MID_REC_DIV (5)
+
+/** Windows BMP magic ID bytes.
+ */
+#define BMP_MAGIC (0x4D42)
+
+/** Given a bits per pixel value, return the bytes per pixel.
+ */
+#define BYTES_PER_PIXEL(bpp) (unsigned int)(((bpp) + 7) / 8)
+
+/** Horizontal subdivision of the screen for overlapping rectangle copy tests.
+ */
+#define ZONE_X (SCREEN_X / 3)
+
+/** Vertical subdivision of the screen for overlapping rectangle copy tests.
+ */
+#define ZONE_Y (SCREEN_Y / 3)
+
+/** Horizontal size of the rectangle to copy in the overlapping rectangle copy tests.
+ */
+#define COPY_X (ZONE_X / 2)
+
+/** Vertical size of the rectangle to copy in the overlapping rectangle copy tests.
+ */
+#define COPY_Y (ZONE_Y / 2)
+
+/** Size of a component of a rectangle copy offset (horizontal or vertical).
+ */
+#define STEP (80)
+
+
+/** Array of offsets for overlapping rectangle copy test.
+ */
+const dlo_dot_t overlap[9] =
+{
+ { -STEP, -STEP },
+ { 0, -STEP },
+ { STEP, -STEP },
+ { -STEP, 0 },
+ { 0, 0 },
+ { STEP, 0 },
+ { -STEP, STEP },
+ { 0, STEP },
+ { STEP, STEP }
+};
+
+
+/** The main header block from a Windows BMP file.
+ */
+typedef struct __packed bmp_header_s
+{
+ uint16_t magic; /**< Magic ID bytes for Windows BMP format. */
+ uint32_t file_sz; /**< Total bitmap file size (bytes). */
+ uint16_t reserved1; /**< Unused. */
+ uint16_t reserved2; /**< Unused. */
+ uint32_t pix_offset; /**< Offset from start of file to start of pixel data (bytes). */
+} bmp_header_t; /**< A struct @a bmp_header_s. */
+
+
+/** The DIB header block from a Windows BMP file.
+ */
+typedef struct __packed dib_header_s
+{
+ uint32_t dib_hdr_sz; /**< Size of the DIB header block (bytes). */
+ uint32_t width; /**< Width of the bitmap (pixels). */
+ uint32_t height; /**< Height of the bitmap (pixels). */
+ uint16_t col_planes; /**< Number of colour planes. */
+ uint16_t bpp; /**< Bits per pixel. */
+ uint32_t compression; /**< Compression, pixel format. */
+ uint32_t raw_size; /**< Size of the raw pixel data. */
+ uint32_t x_pix_meter; /**< Horizontal resolution (pixels per meter). */
+ uint32_t y_pix_meter; /**< Vertical resolution (pixels per meter). */
+ uint32_t pal_entries; /**< Number of palette entries. */
+ uint32_t imp_cols; /**< Important colours (ignored). */
+} dib_header_t; /**< A struct @a dib_header_s. */
+
+
+/** A Windows BMP file.
+ */
+typedef struct __packed bmp_s
+{
+ bmp_header_t hdr; /**< Windows BMP header block. */
+ dib_header_t dib; /**< DIB header block. */
+ uint8_t data[]; /**< Pixel data. */
+} bmp_t; /**< A struct @a bmp_s. */
+
+
+/** Report an error and exit.
+ *
+ * @param str Pointer to the error message string.
+ */
+static void my_error(const char * const str)
+{
+ printf("test: ERROR: %s\n", str);
+ exit(1);
+}
+
+
+/** Return the microsecond time, as an unsigned 64 bit integer.
+ *
+ * @return Number of microseconds since the start of the Epoch.
+ */
+static uint64_t now(void)
+{
+ static struct timeval unix_time = { 0 };
+ static struct timeval *unix_time_ptr = &unix_time;
+
+ gettimeofday(unix_time_ptr, NULL);
+ return ((uint64_t)unix_time.tv_sec * 1000000ll) + (uint64_t)unix_time.tv_usec;
+}
+
+
+/** Pause execution for the specified number of centiseconds.
+ *
+ * @param from Time to start the pause interval.
+ * @param millisec Number of milliseconds to pause for.
+ */
+static void wait_ms(const uint64_t from, const uint64_t millisec)
+{
+ uint64_t to = from + (millisec * 1000);
+
+ while (to > now()) ;
+}
+
+
+/** Plot a rectangular outline in the specified colour.
+ *
+ * @param uid Unique ID of the device.
+ * @param view Viewport for plot destination.
+ * @param rec Rectangle co-ordinates within the viewport.
+ * @param col Colour of rectangle.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t box(const dlo_dev_t uid, const dlo_view_t * const view, const dlo_rect_t * const rec, const dlo_col32_t col)
+{
+ dlo_rect_t line;
+
+ line.origin.x = rec->origin.x;
+ line.origin.y = rec->origin.y;
+ line.width = rec->width;
+ line.height = 1;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.width = 1;
+ line.height = rec->height;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.origin.y += line.height - 1;
+ line.width = rec->width;
+ line.height = 1;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.origin.x += line.width;
+ line.origin.y = rec->origin.y;
+ line.width = 1;
+ line.height = rec->height;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ return dlo_ok;
+}
+
+
+/** Test the basic graphics primitives (filled rectangle and rectangle copy).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t basic_grfx_test(const dlo_dev_t uid)
+{
+ dlo_mode_t mode;
+ dlo_mode_t *mode_info;
+ dlo_devinfo_t *dev_info;
+ dlo_view_t *view;
+ dlo_rect_t rec;
+ dlo_dot_t dot;
+ uint32_t i;
+ uint64_t start;
+
+ /* Read some information on the device */
+ dev_info = dlo_device_info(uid);
+ NERR(dev_info);
+ printf("test: device info: uid &%X\n", (int)dev_info->uid);
+ printf("test: device info: serial '%s'\n", dev_info->serial);
+ printf("test: device info: type &%X\n", (uint32_t)dev_info->type);
+
+ /* Read current mode information (if we're already in the display's native mode) */
+ mode_info = dlo_get_mode(uid);
+ NERR(mode_info);
+ printf("test: native mode info...\n");
+ printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
+
+ /* Select a fairly standard mode */
+ printf("test: set_mode...\n");
+ mode.view.width = SCREEN_X;
+ mode.view.height = SCREEN_Y;
+ mode.view.bpp = SCREEN_BPP;
+ mode.view.base = 0;
+ mode.refresh = SCREEN_RATE;
+ ERR(dlo_set_mode(uid, &mode));
+ wait_ms(now(), 1000);
+
+
+ /* Read current mode information */
+ mode_info = dlo_get_mode(uid);
+ NERR(mode_info);
+ printf("test: mode info...\n");
+ printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
+ view = &(mode_info->view);
+
+ /* Clear screen */
+ printf("test: cls...");
+ start = now();
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot some random white dots */
+ printf("test: random white dots...");
+ start = now();
+ rec.width = 1;
+ rec.height = 1;
+ for (i = 0; i < NUM_DOTS; i++)
+ {
+ rec.origin.x = rand() % view->width;
+ rec.origin.y = rand() % view->height;
+ ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot random filled rectangles */
+ printf("test: random rectangles...");
+ start = now();
+ for (i = 0; i < NUM_RECTS; i++)
+ {
+ rec.width = rand() % (view->width / 4);
+ rec.height = rand() % (view->height / 4);
+ rec.origin.x = (rand() % (uint32_t)(1.25 * view->width)) - (view->width / 8);
+ rec.origin.y = (rand() % (uint32_t)(1.25 * view->height)) - (view->height / 8);
+ ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(rand() % 0xFF, rand() % 0xFF, rand() % 0xFF)));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot a set of rectangles, one over the other (colour gradient) */
+ printf("test: central rectangles...");
+ start = now();
+ for (i = 0; i < NUM_GRAD; i++)
+ {
+ dlo_col32_t col = DLO_RGB((i*3) % 256, (i*5) % 256, 255 - ((i*7) % 256));
+
+ rec.width = (view->width / MID_REC_DIV) - 2*i;
+ rec.height = (view->height / MID_REC_DIV) - 2*i;
+ rec.origin.x = i + (view->width / 2) - (view->width / MID_REC_DIV / 2);
+ rec.origin.y = i + (view->height / 2) - (view->height/ MID_REC_DIV / 2);
+ ERR(dlo_fill_rect(uid, view, &rec, col));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot the outline of the box we're going to copy */
+ printf("test: white box outline...");
+ start = now();
+ rec.width = view->width / MID_REC_DIV;
+ rec.height = view->height / MID_REC_DIV;
+ rec.origin.x = (view->width / 2) - (rec.width / 2);
+ rec.origin.y = (view->height / 2) - (rec.height / 2);
+ ERR(box(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Copy a rectangle from the centre of the screen to other locations */
+ printf("test: copy central box...");
+ start = now();
+ rec.origin.x++;
+ rec.origin.y++;
+ rec.width -= 2;
+ rec.height -= 2;
+ dot.x = 8;
+ dot.y = 8;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = view->width - 8 - rec.width;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.y = view->height - 8 - rec.height;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = 8;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Check that basic clipping works */
+ printf("test: copy central box (off edges of viewport)...");
+ start = now();
+ dot.x = -(rec.width / 2);
+ dot.y = (view->height / 2) - (rec.height / 2) - 32;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x += view->width;
+ dot.y += 64;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = (view->width / 2) - (rec.width / 2) - 128;
+ dot.y = -(rec.height / 2);
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x += 256;
+ dot.y += view->height;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ return dlo_ok;
+}
+
+
+/** Plot a few coloured rectangles one above another.
+ *
+ * @param uid Unique ID of the device.
+ * @param inrec Input rectangle (the outer bounding box of the design).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t squares(const dlo_dev_t uid, const dlo_rect_t * const inrec)
+{
+ dlo_rect_t rec = *inrec;
+
+ /* Plot the outer (red) rectangle */
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0, 0)));
+
+ /* Plot the middle (white) rectangle */
+ rec.origin.x += 20;
+ rec.origin.y += 20;
+ rec.width -= 40;
+ rec.height -= 40;
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0xCC, 0xCC)));
+
+ /* Plot the inner (blue) rectangle */
+ rec.origin.x += 20;
+ rec.origin.y += 20;
+ rec.width -= 40;
+ rec.height -= 40;
+
+ return dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0, 0xCC));
+}
+
+
+/** Test copying rectangles to and from overlapping regions (in various directions).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t overlap_test(const dlo_dev_t uid)
+{
+ dlo_rect_t rec;
+ dlo_dot_t mid, dot;
+ uint32_t idx = 0;
+
+ /* Clear screen to black */
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+
+ rec.width = COPY_X;
+ rec.height = COPY_Y;
+ for (mid.y = ZONE_Y / 2; mid.y < SCREEN_Y; mid.y += ZONE_Y)
+ {
+ for (mid.x = ZONE_X / 2; mid.x < SCREEN_X; mid.x += ZONE_X)
+ {
+ rec.origin.x = mid.x - (COPY_X / 2);
+ rec.origin.y = mid.y - (COPY_Y / 2);
+ dot.x = rec.origin.x + overlap[idx].x;
+ dot.y = rec.origin.y + overlap[idx].y;
+ idx++;
+ ERR(squares(uid, &rec));
+ ERR(dlo_copy_rect(uid, NULL, &rec, NULL, &dot));
+ }
+ }
+ return dlo_ok;
+}
+
+
+/** Convert a bits per pixel value into a bytes per pixel value.
+ *
+ * @param bpp Bits per pixel.
+ *
+ * @return Bytes per pixel.
+ */
+static uint8_t bpp_to_bytes(const uint32_t bpp)
+{
+ return (uint8_t)((bpp + 7) / 8);
+}
+
+
+/** Test the use of viewports as screen banks (ensure clipping is working).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Create three viewports (screen banks) and switch the display between them.
+ * While we're at it, test the filled rectangle plotting clips correctly and
+ * doesn't overflow into surrounding screen banks or off the edges of the
+ * screen.
+ */
+static dlo_retcode_t viewport_test(const dlo_dev_t uid)
+{
+ dlo_mode_t mode;
+ dlo_mode_t *desc;
+ dlo_view_t view[3];
+ dlo_rect_t rec;
+ uint32_t i;
+ uint64_t start;
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+
+ /* Create three viewports - each representing a screen bank */
+ view[0] = desc->view;
+ view[1] = view[0];
+ view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
+ view[2] = view[1];
+ view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
+
+ /* Clear screens to different colours */
+ printf("test: cls (three banks)...");
+ start = now();
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0xFF, 0, 0)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot a couple of rectangles in each bank to test the clipping */
+ printf("test: plot crosses (three banks)...");
+ start = now();
+ rec.width = view[0].width / 8;
+ rec.height = view[0].height * 1.5;
+ rec.origin.x = (view[0].width / 2) - (rec.width / 2);
+ rec.origin.y = -(view[0].height / 4);
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
+ rec.width = view[0].width * 1.5;
+ rec.height = view[0].height / 8;
+ rec.origin.x = -(view[0].width / 4);
+ rec.origin.y = (view[0].height / 2) - (rec.height / 2);
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Switch through the screen banks */
+ for (i = 1; i < 4; i++)
+ {
+ wait_ms(now(), 1000);
+
+ printf("test: switching to screen bank %u...\n", i % 3);
+ mode.view.width = view[i % 3].width;
+ mode.view.height = view[i % 3].height;
+ mode.view.bpp = view[i % 3].bpp;
+ mode.view.base = view[i % 3].base;
+ mode.refresh = 0;
+ ERR(dlo_set_mode(uid, &mode));
+ }
+
+ return dlo_ok;
+}
+
+
+/** Load a Windows BMP file into memory.
+ *
+ * @param bmpfile Pointer to the filename.
+ *
+ * @return Pointer to the loaded bitmap's structure (or NULL if failed).
+ *
+ * Load a bitmap from a file and create a @a dlo_fbuf_t structure to suit.
+ * If the bitmap has a palette, we need to swap the red/blue order of the
+ * colour components in order to convert the palette entries into
+ * @a dlo_col32_t values.
+ */
+static bmp_t *load_bmp(const char * const bmpfile)
+{
+ long int size;
+ bmp_t *bmp;
+ FILE *fp;
+
+ fp = fopen(bmpfile, "rb");
+ if (!fp)
+ return NULL;
+
+ if (fseek(fp, 0, SEEK_END))
+ return NULL;
+
+ size = ftell(fp);
+ if (size == -1L)
+ return NULL;
+
+ if (fseek(fp, 0, SEEK_SET))
+ return NULL;
+
+ bmp = malloc(size);
+ if (!bmp)
+ return NULL;
+
+ if (1 != fread(bmp, size, 1, fp))
+ goto error;
+
+ if (bmp->hdr.magic != BMP_MAGIC)
+ goto error;
+
+ /* If there is a palette, we need to reverse the RGB component order */
+ if (bmp->dib.pal_entries)
+ {
+ dlo_col32_t *palette;
+ uint32_t i;
+
+ palette = (dlo_col32_t *)((unsigned long)bmp + sizeof(bmp_header_t) + sizeof(dib_header_t));
+
+ for (i = 0; i < bmp->dib.pal_entries; i++)
+ {
+ dlo_col32_t col = palette[i];
+
+ palette[i] = DLO_RGB(DLO_RGB_GETBLU(col), DLO_RGB_GETGRN(col), DLO_RGB_GETRED(col));
+ }
+ }
+ return bmp;
+
+error:
+ free(bmp);
+
+ return NULL;
+}
+
+
+/** Given a bitmap pointer, check various aspects of it and return a framebuffer structure pointer.
+ *
+ * @param bmp Pointer to a loaded bitmap structure.
+ *
+ * @return Pointer to a framebuffer structure associated with the bitmap.
+ *
+ * NOTE: the bitmap plotting code requires some special-case Windows BMP format
+ * bitmaps as input; they must include a DIB header (very common) and their width
+ * must be such that they don't require any padding bytes at the end of each pixel
+ * row.
+ *
+ * The padding issue could be fixed very simply by calling the dlo_copy_host_bmp()
+ * for each pixel row individually but for the sake of a simple demo, we impose
+ * the constraint and make only one call to dlo_copy_host_bmp() here.
+ */
+static dlo_fbuf_t *bmp_to_fbuf(const bmp_t * const bmp)
+{
+ static dlo_fbuf_t fbuf;
+
+ printf("bmp->hdr.magic %04X\n"
+ "bmp->hdr.file_sz %08X (%u)\n"
+ "bmp->hdr.reserved1 %04X\n"
+ "bmp->hdr.reserved2 %04X\n"
+ "bmp->hdr.pix_offset %08X\n"
+ "bmp->dib.dib_hdr_sz %08X\n"
+ "bmp->dib.width %08X (%u)\n"
+ "bmp->dib.height %08X (%u)\n"
+ "bmp->dib.col_planes %04X\n"
+ "bmp->dib.bpp %04X (%u)\n"
+ "bmp->dib.compression %08X\n"
+ "bmp->dib.raw_size %08X (%u)\n"
+ "bmp->dib.x_pix_meter %08X\n"
+ "bmp->dib.y_pix_meter %08X\n"
+ "bmp->dib.pal_entries %08X (%u)\n"
+ "bmp->dib.imp_cols %08X\n",
+ bmp->hdr.magic,
+ bmp->hdr.file_sz, bmp->hdr.file_sz,
+ bmp->hdr.reserved1,
+ bmp->hdr.reserved2,
+ bmp->hdr.pix_offset,
+ bmp->dib.dib_hdr_sz,
+ bmp->dib.width, bmp->dib.width,
+ bmp->dib.height, bmp->dib.height,
+ bmp->dib.col_planes,
+ bmp->dib.bpp, bmp->dib.bpp,
+ bmp->dib.compression,
+ bmp->dib.raw_size, bmp->dib.raw_size,
+ bmp->dib.x_pix_meter,
+ bmp->dib.y_pix_meter,
+ bmp->dib.pal_entries, bmp->dib.pal_entries,
+ bmp->dib.imp_cols);
+
+ if (bmp->dib.compression)
+ my_error("Unsupported bitmap compression mode");
+ if (bmp->dib.col_planes != 1)
+ my_error("Unsupported bitmap colour plane specification");
+ if ((bmp->dib.width * BYTES_PER_PIXEL(bmp->dib.bpp)) & 3)
+ my_error("Bitmap width must be whole multiple of four bytes (no padding)");
+
+ fbuf.width = bmp->dib.width;
+ fbuf.height = bmp->dib.height;
+ fbuf.base = bmp->hdr.pix_offset + (uint8_t *)bmp;
+ fbuf.stride = fbuf.width;
+ switch (bmp->dib.bpp)
+ {
+ case 8:
+ {
+ fbuf.fmt = (dlo_pixfmt_t)(sizeof(bmp_header_t) + sizeof(dib_header_t) + (uint8_t *)bmp);
+ if (bmp->dib.pal_entries != 256)
+ my_error("Unsupported bitmap palette size");
+ break;
+ }
+ case 16:
+ {
+ fbuf.fmt = dlo_pixfmt_srgb1555;
+ break;
+ }
+ case 24:
+ {
+ fbuf.fmt = dlo_pixfmt_rgb888;
+ break;
+ }
+ case 32:
+ {
+ fbuf.fmt = dlo_pixfmt_argb8888;
+ break;
+ }
+ default:
+ my_error("Unsupported bitmap colour depth");
+ }
+ return &fbuf;
+}
+
+
+/** Run some tests involving the loading, scraping and plotting of a bitmap.
+ *
+ * @param uid Unique ID of the device.
+ * @param bmpfile Pointer to a Windows BMP filename.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Load a bitmap, clear the screen and plot the bitmap at the centre of the
+ * screen as well as off each edge of the screen.
+ */
+static dlo_retcode_t bitmap_test(const dlo_dev_t uid, const bool cross, const char * const bmpfile)
+{
+ dlo_bmpflags_t flags = { 0 };
+ dlo_retcode_t err;
+ dlo_mode_t *desc;
+ dlo_fbuf_t *fbuf;
+ dlo_view_t view;
+ dlo_dot_t dot;
+ bmp_t *bmp;
+
+ printf("\ntest: bitmap file '%s'\n", bmpfile);
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+ view = desc->view;
+
+ /* Clear screen to black */
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+
+ /* Load the Windows BMP bitmap file into memory */
+ bmp = load_bmp(bmpfile);
+ NERR(bmp);
+
+ /* Initialise a dlo_fbuf structure from our loaded bitmap file */
+ fbuf = bmp_to_fbuf(bmp);
+ NERR_GOTO(fbuf);
+
+ /* Test plotting of bitmap in centre of screen */
+ dot.x = (view.width / 2) - (fbuf->width / 2);
+ dot.y = (view.height / 2) - (fbuf->height / 2);
+ flags.v_flip = 1;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+
+ /* Now a few plots that lie a little off the edges of the screen */
+ flags.v_flip = 0;
+ if (cross)
+ {
+ dot.y = -fbuf->height / 2;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y += view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x = -fbuf->width / 2;
+ dot.y = (view.height / 2) - (fbuf->height / 2);
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x += view.width;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ }
+ else
+ {
+ dot.x = -fbuf->width / 2;
+ dot.y = -fbuf->height / 2;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y += view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x += view.width;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y -= view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ }
+
+ /* Discard the bitmap */
+ free(bmp);
+
+ return dlo_ok;
+
+error:
+ free(bmp);
+ return err;
+}
+
+
+/** Run some screen scraping tests with a set of input bitmaps.
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * This test sequence checks that the @c dlo_copy_host_bmp() call works correctly for
+ * a number of source pixel formats by loading some different bitmaps and scraping
+ * directly from them (using their palette where required).
+ */
+static dlo_retcode_t scrape_tests(const dlo_dev_t uid)
+{
+ ERR(bitmap_test(uid, false, "images/test08.bmp"));
+
+ wait_ms(now(), 1000);
+ ERR(bitmap_test(uid, true, "images/test16.bmp"));
+
+ wait_ms(now(), 1000);
+ ERR(bitmap_test(uid, false, "images/test24.bmp"));
+
+ wait_ms(now(), 1000);
+ return bitmap_test(uid, true, "images/test32.bmp");
+}
+
+
+/** Test the clipping of bitmaps relative to other screen banks.
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * The point of this test is to plot lots of bitmaps in random positions (some
+ * completely off-screen) into the middle of three screen banks. We switch between
+ * each bank to check that the bitmaps only appear on the middle one and haven't
+ * spilled over into the surrounding memory.
+ */
+static dlo_retcode_t bmp_clip_test(const dlo_dev_t uid)
+{
+ dlo_bmpflags_t flags = { 0 };
+ dlo_retcode_t err;
+ dlo_mode_t mode;
+ dlo_mode_t *desc;
+ dlo_fbuf_t *fbuf;
+ dlo_view_t view[3];
+ dlo_dot_t dot;
+ bmp_t *bmp;
+ uint32_t i;
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+
+ /* Create three viewports - each representing a screen bank */
+ view[0] = desc->view;
+ view[1] = view[0];
+ view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
+ view[2] = view[1];
+ view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
+
+ /* Clear screen banks */
+ wait_ms(now(), 2000);
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0x50)));
+ ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0, 0x50, 0)));
+
+ /* Load the Windows BMP bitmap file into memory */
+ bmp = load_bmp("images/test08.bmp");
+ NERR(bmp);
+
+ /* Initialise a dlo_fbuf structure from our loaded bitmap file */
+ fbuf = bmp_to_fbuf(bmp);
+ NERR_GOTO(fbuf);
+
+ /* Plot lots of bitmaps into the second screen bank */
+ for (i = 0; i < 399; i++)
+ {
+ flags.v_flip = rand() % 2;
+ dot.x = -fbuf->width + (rand() % (view[1].width + fbuf->width));
+ dot.y = -fbuf->height + (rand() % (view[1].height + fbuf->height));
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, &view[1], &dot));
+ }
+
+ /* Switch to middle bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[1].width;
+ mode.view.height = view[1].height;
+ mode.view.bpp = view[1].bpp;
+ mode.view.base = view[1].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+ wait_ms(now(), 1000);
+
+ /* Switch to third bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[2].width;
+ mode.view.height = view[2].height;
+ mode.view.bpp = view[2].bpp;
+ mode.view.base = view[2].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+ wait_ms(now(), 1000);
+
+ /* Switch to middle bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[1].width;
+ mode.view.height = view[1].height;
+ mode.view.bpp = view[1].bpp;
+ mode.view.base = view[1].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+ wait_ms(now(), 1000);
+
+ /* Discard the bitmap */
+ free(bmp);
+
+ return dlo_ok;
+
+error:
+ free(bmp);
+ return err;
+}
+
+
+/**********************************************************************/
+int main(int argc, char *argv[])
+{
+ dlo_init_t ini_flags = { 0 };
+ dlo_final_t fin_flags = { 0 };
+ dlo_claim_t cnf_flags = { 0 };
+ dlo_retcode_t err;
+ dlo_dev_t uid = 0;
+
+ IGNORE(argc);
+ IGNORE(argv);
+
+ /* Initialise the random number generator with the microsecond time as a seed */
+ srand((unsigned int)now());
+
+ /* Initialise libdlo */
+ printf("test: init...\n");
+ ERR_GOTO(dlo_init(ini_flags));
+
+ /* Look for a DisplayLink device to connect to */
+ uid = dlo_claim_first_device(cnf_flags, 0);
+
+ /* If we found one, perform some tests with it */
+ if (uid)
+ {
+ printf("\ntest: basic graphics tests...\n");
+ ERR_GOTO(basic_grfx_test(uid));
+ wait_ms(now(), 3000);
+
+ printf("\test: overlapping copy tests...\n");
+ ERR_GOTO(overlap_test(uid));
+
+ wait_ms(now(), 3000);
+
+ printf("\ntest: viewport tests...\n");
+ ERR_GOTO(viewport_test(uid));
+
+ printf("\ntest: screen scraping tests...\n");
+ ERR_GOTO(scrape_tests(uid));
+
+ printf("test: bitmap clipping test...\n");
+ ERR_GOTO(bmp_clip_test(uid));
+
+ printf("test: release &%X...\n", (uintptr_t)uid);
+ ERR_GOTO(dlo_release_device(uid));
+ } else {
+ printf("test: no DisplayLink devices found\n");
+ }
+
+ /* Finalise libdlo, free up resources */
+ printf("test: final...\n");
+ ERR_GOTO(dlo_final(fin_flags));
+ printf("test: finished.\n");
+ return 0;
+
+error:
+ printf("test: error %u '%s'\n", (int)err, dlo_strerror(err));
+ return 0;
+}