| // 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 |