blob: 871b3301497e0a9ac9043ce455fc7c3365c6cbbd [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
// Copyright (c) 2008-2010, 2015 Travis Geiselbrecht
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <debug.h>
#include <lib/gfx.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <trace.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <arch/ops.h>
#include <dev/display.h>
#define LOCAL_TRACE 0
static void kernel_gfx_log(const char* format, ...) {
if (LOCAL_TRACE) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
}
static void kernel_gfx_flush_cache(void* ptr, size_t size) {
arch_clean_cache_range(reinterpret_cast<vaddr_t>(ptr), size);
}
static const gfx_context g_kernel_ctx = {
.log = kernel_gfx_log,
.panic = panic,
.flush_cache = kernel_gfx_flush_cache,
};
/**
* @brief Create a new graphics surface object
*/
gfx_surface* gfx_create_surface(void* ptr, uint width, uint height, uint stride, gfx_format format,
uint32_t flags) {
return gfx_create_surface_with_context(ptr, &g_kernel_ctx, width, height, stride, format, flags);
}
/**
* @brief Create a new graphics surface object from a display
*/
gfx_surface* gfx_create_surface_from_display(struct display_info* info) {
gfx_surface* surface = static_cast<gfx_surface*>(calloc(1, sizeof(*surface)));
if (surface == NULL)
return NULL;
if (gfx_init_surface_from_display(surface, info)) {
free(surface);
return NULL;
}
return surface;
}
zx_status_t gfx_init_surface_from_display(gfx_surface* surface, struct display_info* info) {
zx_status_t r;
switch (info->format) {
case ZX_PIXEL_FORMAT_RGB_565:
case ZX_PIXEL_FORMAT_RGB_332:
case ZX_PIXEL_FORMAT_RGB_2220:
case ZX_PIXEL_FORMAT_ARGB_8888:
case ZX_PIXEL_FORMAT_RGB_x888:
case ZX_PIXEL_FORMAT_MONO_8:
// supported formats
break;
default:
dprintf(CRITICAL, "invalid graphics format %x", info->format);
return ZX_ERR_INVALID_ARGS;
}
uint32_t flags = (info->flags & DISPLAY_FLAG_NEEDS_CACHE_FLUSH) ? GFX_FLAG_FLUSH_CPU_CACHE : 0;
r = gfx_init_surface(surface, info->framebuffer, info->width, info->height, info->stride,
info->format, flags);
surface->flush = info->flush;
return r;
}
/**
* @brief Write a test pattern to the default display.
*/
void gfx_draw_pattern(void) {
struct display_info info;
if (display_get_info(&info) < 0)
return;
gfx_surface* surface = gfx_create_surface_from_display(&info);
DEBUG_ASSERT(surface != nullptr);
uint x, y;
for (y = 0; y < surface->height; y++) {
for (x = 0; x < surface->width; x++) {
uint scaledx;
uint scaledy;
scaledx = x * 256 / surface->width;
scaledy = y * 256 / surface->height;
gfx_putpixel(surface, x, y,
(0xff << 24) | (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
}
}
gfx_flush(surface);
gfx_surface_destroy(surface);
}
/**
* @brief Fill default display with white
*/
[[maybe_unused]] static void gfx_draw_pattern_white(void) {
struct display_info info;
if (display_get_info(&info) < 0)
return;
gfx_surface* surface = gfx_create_surface_from_display(&info);
DEBUG_ASSERT(surface != nullptr);
uint x, y;
for (y = 0; y < surface->height; y++) {
for (x = 0; x < surface->width; x++) {
gfx_putpixel(surface, x, y, 0xFFFFFFFF);
}
}
gfx_flush(surface);
gfx_surface_destroy(surface);
}
#if LK_DEBUGLEVEL > 1
#include <lib/console.h>
static int cmd_gfx(int argc, const cmd_args* argv, uint32_t flags);
STATIC_COMMAND_START
STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
STATIC_COMMAND_END(gfx)
static int gfx_draw_rgb_bars(gfx_surface* surface) {
uint x, y;
uint step = surface->height * 100 / 256;
uint color;
for (y = 0; y < surface->height; y++) {
// R
for (x = 0; x < surface->width / 3; x++) {
color = y * 100 / step;
gfx_putpixel(surface, x, y, 0xff << 24 | color << 16);
}
// G
for (; x < 2 * (surface->width / 3); x++) {
color = y * 100 / step;
gfx_putpixel(surface, x, y, 0xff << 24 | color << 8);
}
// B
for (; x < surface->width; x++) {
color = y * 100 / step;
gfx_putpixel(surface, x, y, 0xff << 24 | color);
}
}
return 0;
}
static int cmd_gfx(int argc, const cmd_args* argv, uint32_t flags) {
if (argc < 2) {
printf("not enough arguments:\n");
printf("%s display_info : output information bout the current display\n", argv[0].str);
printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str);
printf("%s test_pattern : Fill frame with test pattern\n", argv[0].str);
printf("%s fill r g b : Fill frame buffer with RGB888 value and force update\n", argv[0].str);
return -1;
}
display_info info;
if (display_get_info(&info) < 0) {
printf("no display to draw on!\n");
return -1;
}
gfx_surface* surface = gfx_create_surface_from_display(&info);
DEBUG_ASSERT(surface != nullptr);
if (!strcmp(argv[1].str, "display_info")) {
printf("display:\n");
printf("\tframebuffer %p\n", info.framebuffer);
printf("\twidth %u height %u stride %u\n", info.width, info.height, info.stride);
printf("\tformat 0x%x\n", info.format);
printf("\tflags 0x%x\n", info.flags);
} else if (!strcmp(argv[1].str, "rgb_bars")) {
gfx_draw_rgb_bars(surface);
} else if (!strcmp(argv[1].str, "test_pattern")) {
gfx_draw_pattern();
} else if (!strcmp(argv[1].str, "fill")) {
uint x, y;
uint fillval =
static_cast<uint>((0xff << 24) | (argv[2].u << 16) | (argv[3].u << 8) | argv[4].u);
for (y = 0; y < surface->height; y++) {
for (x = 0; x < surface->width; x++) {
/* write pixel to frame buffer */
gfx_putpixel(surface, x, y, fillval);
}
}
}
gfx_flush(surface);
gfx_surface_destroy(surface);
return 0;
}
#endif