mirror of
https://github.com/google/pebble.git
synced 2025-05-29 06:23:13 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
361
tests/fw/graphics/test_bitblt_palette.c
Normal file
361
tests/fw/graphics/test_bitblt_palette.c
Normal file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* 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 "applib/graphics/graphics.h"
|
||||
#include "applib/graphics/bitblt.h"
|
||||
#include "applib/graphics/bitblt_private.h"
|
||||
#include "applib/graphics/8_bit/framebuffer.h"
|
||||
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Stubs
|
||||
////////////////////////////////////
|
||||
#include "graphics_common_stubs.h"
|
||||
#include "stubs_applib_resource.h"
|
||||
#include "stubs_compiled_with_legacy2_sdk.h"
|
||||
#include "test_graphics.h"
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////
|
||||
static GContext ctx;
|
||||
static FrameBuffer framebuffer;
|
||||
static uint8_t dest_bitmap_data[FRAMEBUFFER_SIZE_BYTES];
|
||||
static GBitmap dest_bitmap = {
|
||||
.addr = dest_bitmap_data,
|
||||
.row_size_bytes = FRAMEBUFFER_BYTES_PER_ROW,
|
||||
.info.is_bitmap_heap_allocated = false,
|
||||
.info.format = GBitmapFormat8Bit,
|
||||
.info.version = GBITMAP_VERSION_CURRENT,
|
||||
.bounds = {
|
||||
.size = {
|
||||
.w = DISP_COLS,
|
||||
.h = DISP_ROWS
|
||||
},
|
||||
.origin = { 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
// Utilities
|
||||
////////////////////////////////////
|
||||
#if SCREEN_COLOR_DEPTH_BITS == 8
|
||||
extern GColor get_bitmap_color(GBitmap *bmp, int x, int y);
|
||||
#endif
|
||||
|
||||
// @param color_index the color index (the value) to put into the bitmap at (x, y).
|
||||
// @param bpp Bits per pixel.
|
||||
// @para line_stride how many bytes per line in the bitmap data.
|
||||
void packed_pixel_set(uint8_t *buf, uint8_t color_index, int16_t x, int16_t y,
|
||||
uint8_t bpp, int16_t line_stride) {
|
||||
const uint8_t ppb = 8 / bpp;
|
||||
uint8_t idx = y*line_stride + (x/(ppb));
|
||||
const uint8_t shift = (8 - bpp) - bpp * (x % ppb);
|
||||
const uint8_t mask = ~(((1 << bpp) - 1) << shift);
|
||||
buf[idx] = buf[idx] & mask;
|
||||
buf[idx] |= ((color_index & ((1 << bpp) - 1)) << shift);
|
||||
}
|
||||
|
||||
static bool prv_check_source_stripe_blit(const uint8_t *data,
|
||||
const GBitmap *src_bmp, GColor surround_color) {
|
||||
for (uint8_t y = 0; y < (FRAMEBUFFER_SIZE_BYTES / FRAMEBUFFER_BYTES_PER_ROW); ++y) {
|
||||
for (uint8_t x = 0; x < FRAMEBUFFER_BYTES_PER_ROW; ++x) {
|
||||
uint8_t color = data[y*FRAMEBUFFER_BYTES_PER_ROW + x];
|
||||
if (y < src_bmp->bounds.size.h && x < src_bmp->bounds.size.w) {
|
||||
if (color != src_bmp->palette[x].argb) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (color != surround_color.argb) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////
|
||||
|
||||
// setup and teardown
|
||||
void test_bitblt_palette__initialize(void) {
|
||||
framebuffer_init(&framebuffer, &(GSize) { DISP_COLS, DISP_ROWS });
|
||||
test_graphics_context_init(&ctx, &framebuffer);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_bitblt_palette__1Bit_color(void) {
|
||||
const int BITS_PER_PIXEL = 1;
|
||||
const int PIXELS_PER_BYTE = (8 / BITS_PER_PIXEL);
|
||||
const int WIDTH = 2;
|
||||
const int HEIGHT = 2;
|
||||
const int ROW_STRIDE = (WIDTH + (PIXELS_PER_BYTE - 1)) / PIXELS_PER_BYTE;
|
||||
|
||||
uint8_t s_data[ROW_STRIDE * HEIGHT];
|
||||
GColor s_palette[1 << 1] = {
|
||||
GColorMelon, GColorIcterine
|
||||
};
|
||||
cl_assert(sizeof(s_palette) == (1 << BITS_PER_PIXEL));
|
||||
GBitmap s_bmp = (GBitmap) {
|
||||
.addr = s_data,
|
||||
.row_size_bytes = ROW_STRIDE,
|
||||
.info.format = GBitmapFormat1BitPalette,
|
||||
.info.version = GBITMAP_VERSION_CURRENT,
|
||||
.bounds = { .size = { WIDTH, HEIGHT } },
|
||||
.palette = s_palette,
|
||||
};
|
||||
memset(s_data, 0, sizeof(s_data));
|
||||
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
packed_pixel_set(s_data, x /* color_index */, x, y, BITS_PER_PIXEL, s_bmp.row_size_bytes);
|
||||
}
|
||||
}
|
||||
memset(dest_bitmap_data, GColorWhite.argb, sizeof(dest_bitmap_data));
|
||||
|
||||
#if SCREEN_COLOR_DEPTH_BITS == 8
|
||||
char print_buf[20];
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
snprintf(print_buf, sizeof(print_buf), "Failed index = %d, %d", x, y);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_assign(void) {
|
||||
const int BITS_PER_PIXEL = 4;
|
||||
const int PIXELS_PER_BYTE = (8 / BITS_PER_PIXEL);
|
||||
const int WIDTH = 16;
|
||||
const int HEIGHT = 16;
|
||||
const int ROW_STRIDE = (WIDTH + (PIXELS_PER_BYTE - 1)) / PIXELS_PER_BYTE;
|
||||
|
||||
uint8_t s_data[ROW_STRIDE * HEIGHT];
|
||||
GColor s_palette[1 << 4] = {
|
||||
GColorMelon, GColorIcterine, GColorYellow, GColorSunsetOrange,
|
||||
GColorScreaminGreen, GColorMagenta, GColorOrange, GColorFolly,
|
||||
GColorLimerick, GColorPictonBlue, GColorPurple, GColorCadetBlue,
|
||||
GColorMalachite, GColorGreen, GColorIndigo, GColorVividCerulean
|
||||
};
|
||||
cl_assert(sizeof(s_palette) == (1 << BITS_PER_PIXEL));
|
||||
GBitmap s_bmp = (GBitmap) {
|
||||
.addr = s_data,
|
||||
.row_size_bytes = ROW_STRIDE,
|
||||
.info.format = GBitmapFormat4BitPalette,
|
||||
.info.version = GBITMAP_VERSION_CURRENT,
|
||||
.bounds = { .size = { WIDTH, HEIGHT } },
|
||||
.palette = s_palette,
|
||||
};
|
||||
memset(s_data, 0, sizeof(s_data));
|
||||
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
packed_pixel_set(s_data, x /* color_index */, x, y, BITS_PER_PIXEL, s_bmp.row_size_bytes);
|
||||
}
|
||||
}
|
||||
memset(dest_bitmap_data, GColorWhite.argb, sizeof(dest_bitmap_data));
|
||||
|
||||
#if SCREEN_COLOR_DEPTH_BITS == 8
|
||||
char print_buf[20];
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
snprintf(print_buf, sizeof(print_buf), "Failed index = %d, %d", x, y);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bitblt_bitmap_into_bitmap(&dest_bitmap, &s_bmp, GPointZero, GCompOpAssign, GColorWhite);
|
||||
|
||||
cl_assert(prv_check_source_stripe_blit(dest_bitmap_data, &s_bmp, GColorWhite));
|
||||
}
|
||||
|
||||
static void prv_opaque_2bit_simple(GCompOp compositing_mode) {
|
||||
const int BITS_PER_PIXEL = 2;
|
||||
const int PIXELS_PER_BYTE = (8 / BITS_PER_PIXEL);
|
||||
const int WIDTH = 4;
|
||||
const int HEIGHT = 4;
|
||||
const int ROW_STRIDE = (WIDTH + (PIXELS_PER_BYTE - 1)) / PIXELS_PER_BYTE;
|
||||
|
||||
uint8_t s_data[ROW_STRIDE * HEIGHT];
|
||||
GColor s_palette[] = {
|
||||
GColorRed, GColorWhite, GColorBlack, GColorBlue
|
||||
};
|
||||
|
||||
cl_assert(sizeof(s_palette) == (1 << BITS_PER_PIXEL));
|
||||
|
||||
GBitmap s_bmp = (GBitmap) {
|
||||
.addr = s_data,
|
||||
.row_size_bytes = ROW_STRIDE,
|
||||
.info.format = GBitmapFormat2BitPalette,
|
||||
.info.version = GBITMAP_VERSION_CURRENT,
|
||||
.bounds = { .size = { WIDTH, HEIGHT } },
|
||||
.palette = s_palette,
|
||||
};
|
||||
|
||||
memset(s_data, 0, sizeof(s_data));
|
||||
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
packed_pixel_set(s_data, x /* color_index */, x, y, BITS_PER_PIXEL, s_bmp.row_size_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
memset(dest_bitmap_data, GColorWhite.argb, sizeof(dest_bitmap_data));
|
||||
|
||||
#if SCREEN_COLOR_DEPTH_BITS == 8
|
||||
char print_buf[20];
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
snprintf(print_buf, sizeof(print_buf), "Failed index = %d, %d", x, y);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
cl_check_(gcolor_equal(get_bitmap_color(&s_bmp, x, y), s_palette[x]), print_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bitblt_bitmap_into_bitmap(&dest_bitmap, &s_bmp, GPointZero, compositing_mode, GColorWhite);
|
||||
|
||||
switch (compositing_mode) {
|
||||
case GCompOpTint: {
|
||||
// Since this is opaque, the tint_color will be used for the RGB value of the destination
|
||||
// image, so we want to use that as our palette.
|
||||
for (uint8_t idx = 0; idx < WIDTH; idx++) {
|
||||
if (s_palette[idx].a == 3) {
|
||||
s_palette[idx] = GColorWhite;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cl_assert(prv_check_source_stripe_blit(dest_bitmap_data, &s_bmp, GColorWhite));
|
||||
}
|
||||
|
||||
static void prv_4bit_simple(GCompOp compositing_mode, GColor color, bool transparent) {
|
||||
const int BITS_PER_PIXEL = 4;
|
||||
const int PIXELS_PER_BYTE = (8 / BITS_PER_PIXEL);
|
||||
const int WIDTH = 16;
|
||||
const int HEIGHT = 16;
|
||||
const int ROW_STRIDE = (WIDTH + (PIXELS_PER_BYTE - 1)) / PIXELS_PER_BYTE;
|
||||
|
||||
uint8_t s_data[ROW_STRIDE * HEIGHT];
|
||||
GColor s_palette[] = {
|
||||
GColorMelon, GColorIcterine, GColorYellow, GColorSunsetOrange,
|
||||
GColorScreaminGreen, GColorMagenta, GColorOrange, GColorFolly,
|
||||
GColorLimerick, GColorPictonBlue, GColorPurple, GColorCadetBlue,
|
||||
GColorMalachite, GColorGreen, GColorIndigo, GColorVividCerulean
|
||||
};
|
||||
|
||||
cl_assert(sizeof(s_palette) == (1 << BITS_PER_PIXEL));
|
||||
|
||||
if (transparent) {
|
||||
// Make all of those colors fully transparent
|
||||
for (int i = 0; i < sizeof(s_palette); ++i) {
|
||||
s_palette[i].a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GBitmap s_bmp = (GBitmap) {
|
||||
.addr = s_data,
|
||||
.row_size_bytes = ROW_STRIDE,
|
||||
.info.format = GBitmapFormat4BitPalette,
|
||||
.info.version = GBITMAP_VERSION_CURRENT,
|
||||
.bounds = { .size = { WIDTH, HEIGHT } },
|
||||
.palette = s_palette,
|
||||
};
|
||||
|
||||
memset(s_data, 0, sizeof(s_data));
|
||||
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
packed_pixel_set(s_data, x /* color_index */, x, y, BITS_PER_PIXEL, s_bmp.row_size_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
memset(dest_bitmap_data, GColorWhite.argb, sizeof(dest_bitmap_data));
|
||||
|
||||
bitblt_bitmap_into_bitmap(&dest_bitmap, &s_bmp, GPointZero, compositing_mode, color);
|
||||
|
||||
switch (compositing_mode) {
|
||||
case GCompOpSet: {
|
||||
if (transparent) {
|
||||
memset(s_palette, color.argb, sizeof(s_palette));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GCompOpAssign:
|
||||
break;
|
||||
case GCompOpTint: {
|
||||
for (uint8_t idx = 0; idx < WIDTH; idx++) {
|
||||
if (s_palette[idx].a == 3 || transparent) {
|
||||
s_palette[idx] = color;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cl_assert(prv_check_source_stripe_blit(dest_bitmap_data, &s_bmp, GColorWhite));
|
||||
}
|
||||
|
||||
void test_bitblt_palette__2Bit_assign_opaque(void) {
|
||||
prv_opaque_2bit_simple(GCompOpAssign);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__2Bit_set_opaque(void) {
|
||||
prv_opaque_2bit_simple(GCompOpSet);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__2Bit_comptint_opaque(void) {
|
||||
prv_opaque_2bit_simple(GCompOpTint);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_assign_opaque(void) {
|
||||
prv_4bit_simple(GCompOpAssign, GColorWhite, false /* opaque */);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_assign_transparent(void) {
|
||||
prv_4bit_simple(GCompOpAssign, GColorWhite, true /* transparent */);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_set_opaque(void) {
|
||||
prv_4bit_simple(GCompOpSet, GColorWhite, false /* opaque */);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_set_transparent(void) {
|
||||
prv_4bit_simple(GCompOpSet, GColorWhite, true /* transparent */);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_comptint_opaque(void) {
|
||||
prv_4bit_simple(GCompOpTint, GColorBlack, false /* opaque */);
|
||||
prv_4bit_simple(GCompOpTint, GColorBlue, false /* opaque */);
|
||||
}
|
||||
|
||||
void test_bitblt_palette__4Bit_comptint_transparent(void) {
|
||||
prv_4bit_simple(GCompOpTint, GColorWhite, true /* transparent */);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue