wasm-micro-runtime/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c

370 lines
9.4 KiB
C

/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* 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 <stdio.h>
#include <stdbool.h>
#include "display_indev.h"
#include "SDL2/SDL.h"
#include "sys/time.h"
#include "wasm_export.h"
#define MONITOR_HOR_RES 320
#define MONITOR_VER_RES 240
#ifndef MONITOR_ZOOM
#define MONITOR_ZOOM 1
#endif
#define SDL_REFR_PERIOD 50
void monitor_sdl_init(void);
void monitor_sdl_refr_core(void);
void monitor_sdl_clean_up(void);
static uint32_t tft_fb[MONITOR_HOR_RES * MONITOR_VER_RES];
int
time_get_ms(wasm_module_inst_t module_inst)
{
static struct timeval tv;
gettimeofday(&tv, NULL);
long long time_in_mill = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
return (int) time_in_mill;
}
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * texture;
static volatile bool sdl_inited = false;
static volatile bool sdl_refr_qry = false;
static volatile bool sdl_quit_qry = false;
void monitor_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if (x2 < 0 || y2 < 0 || x1 > MONITOR_HOR_RES - 1
|| y1 > MONITOR_VER_RES - 1) {
return;
}
int32_t y;
uint32_t w = x2 - x1 + 1;
for (y = y1; y <= y2; y++) {
memcpy(&tft_fb[y * MONITOR_HOR_RES + x1], color_p,
w * sizeof(lv_color_t));
color_p += w;
}
sdl_refr_qry = true;
/*IMPORTANT! It must be called to tell the system the flush is ready*/
}
/**
* Fill out the marked area with a color
* @param x1 left coordinate
* @param y1 top coordinate
* @param x2 right coordinate
* @param y2 bottom coordinate
* @param color fill color
*/
void monitor_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
lv_color_t color)
{
/*Return if the area is out the screen*/
if (x2 < 0)
return;
if (y2 < 0)
return;
if (x1 > MONITOR_HOR_RES - 1)
return;
if (y1 > MONITOR_VER_RES - 1)
return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2;
int32_t x;
int32_t y;
uint32_t color32 = color.full; //lv_color_to32(color);
for (x = act_x1; x <= act_x2; x++) {
for (y = act_y1; y <= act_y2; y++) {
tft_fb[y * MONITOR_HOR_RES + x] = color32;
}
}
sdl_refr_qry = true;
}
/**
* Put a color map to the marked area
* @param x1 left coordinate
* @param y1 top coordinate
* @param x2 right coordinate
* @param y2 bottom coordinate
* @param color_p an array of colors
*/
void monitor_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if (x2 < 0)
return;
if (y2 < 0)
return;
if (x1 > MONITOR_HOR_RES - 1)
return;
if (y1 > MONITOR_VER_RES - 1)
return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > MONITOR_HOR_RES - 1 ? MONITOR_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > MONITOR_VER_RES - 1 ? MONITOR_VER_RES - 1 : y2;
int32_t x;
int32_t y;
for (y = act_y1; y <= act_y2; y++) {
for (x = act_x1; x <= act_x2; x++) {
tft_fb[y * MONITOR_HOR_RES + x] = color_p->full; //lv_color_to32(*color_p);
color_p++;
}
color_p += x2 - act_x2;
}
sdl_refr_qry = true;
}
void
display_init(wasm_module_inst_t module_inst)
{
}
void
display_flush(wasm_module_inst_t module_inst,
int32_t x1, int32_t y1, int32_t x2, int32_t y2,
int32 color_p_offset)
{
if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1))
return;
lv_color_t * color_p = wasm_runtime_addr_app_to_native(module_inst,
color_p_offset);
monitor_flush(x1, y1, x2, y2, color_p);
}
void
display_fill(wasm_module_inst_t module_inst,
int32_t x1, int32_t y1, int32_t x2, int32_t y2,
lv_color_t color_p)
{
monitor_fill(x1, y1, x2, y2, color_p);
}
void
display_map(wasm_module_inst_t module_inst,
int32_t x1, int32_t y1, int32_t x2, int32_t y2,
const lv_color_t * color_p)
{
monitor_map(x1, y1, x2, y2, color_p);
}
bool
display_input_read(wasm_module_inst_t module_inst,
int32 data_p_offset)
{
bool ret;
if (!wasm_runtime_validate_app_addr(module_inst, data_p_offset, 1))
return false;
struct {
lv_point_t point;
int32 user_data_offset;
uint8 state;
} *data_app;
lv_indev_data_t data;
ret = mouse_read(&data);
data_app = wasm_runtime_addr_app_to_native(module_inst,
data_p_offset);
data_app->point = data.point;
data_app->user_data_offset =
wasm_runtime_addr_native_to_app(module_inst, data.user_data);
data_app->state = data.state;
return ret;
}
void
display_deinit(wasm_module_inst_t module_inst)
{
}
void
display_vdb_write(wasm_module_inst_t module_inst,
int32 buf_offset, lv_coord_t buf_w, lv_coord_t x,
lv_coord_t y, int32 color_p_offset, lv_opa_t opa)
{
if (!wasm_runtime_validate_app_addr(module_inst, color_p_offset, 1))
return;
lv_color_t *color = wasm_runtime_addr_app_to_native(module_inst,
color_p_offset);
void *buf = wasm_runtime_addr_app_to_native(module_inst, buf_offset);
unsigned char *buf_xy = buf + 4 * x + 4 * y * buf_w;
lv_color_t * temp = (lv_color_t *) buf_xy;
*temp = *color;
/*
if (opa != LV_OPA_COVER) {
lv_color_t mix_color;
mix_color.red = *buf_xy;
mix_color.green = *(buf_xy+1);
mix_color.blue = *(buf_xy+2);
color = lv_color_mix(color, mix_color, opa);
}
*/
/*
*buf_xy = color->red;
*(buf_xy + 1) = color->green;
*(buf_xy + 2) = color->blue;
*/
}
int monitor_sdl_refr_thread(void * param)
{
(void) param;
/*If not OSX initialize SDL in the Thread*/
monitor_sdl_init();
/*Run until quit event not arrives*/
while (sdl_quit_qry == false) {
/*Refresh handling*/
monitor_sdl_refr_core();
}
monitor_sdl_clean_up();
exit(0);
return 0;
}
extern void mouse_handler(SDL_Event *event);
void monitor_sdl_refr_core(void)
{
if (sdl_refr_qry != false) {
sdl_refr_qry = false;
SDL_UpdateTexture(texture, NULL, tft_fb,
MONITOR_HOR_RES * sizeof(uint32_t));
SDL_RenderClear(renderer);
/*Update the renderer with the texture containing the rendered image*/
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_Event event;
while (SDL_PollEvent(&event)) {
mouse_handler(&event);
if ((&event)->type == SDL_WINDOWEVENT) {
switch ((&event)->window.event) {
#if SDL_VERSION_ATLEAST(2, 0, 5)
case SDL_WINDOWEVENT_TAKE_FOCUS:
#endif
case SDL_WINDOWEVENT_EXPOSED:
SDL_UpdateTexture(texture, NULL, tft_fb,
MONITOR_HOR_RES * sizeof(uint32_t));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
break;
default:
break;
}
}
}
/*Sleep some time*/
SDL_Delay(SDL_REFR_PERIOD);
}
int quit_filter(void * userdata, SDL_Event * event)
{
(void) userdata;
if (event->type == SDL_QUIT) {
sdl_quit_qry = true;
}
return 1;
}
void monitor_sdl_clean_up(void)
{
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
void monitor_sdl_init(void)
{
/*Initialize the SDL*/
SDL_Init(SDL_INIT_VIDEO);
SDL_SetEventFilter(quit_filter, NULL);
window = SDL_CreateWindow("TFT Simulator", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/
renderer = SDL_CreateRenderer(window, -1, 0);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
/*Initialize the frame buffer to gray (77 is an empirical value) */
memset(tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t));
SDL_UpdateTexture(texture, NULL, tft_fb,
MONITOR_HOR_RES * sizeof(uint32_t));
sdl_refr_qry = true;
sdl_inited = true;
}
void display_SDL_init()
{
SDL_CreateThread(monitor_sdl_refr_thread, "sdl_refr", NULL);
while (sdl_inited == false)
; /*Wait until 'sdl_refr' initializes the SDL*/
}