add display driver
parent
4b522dc9e2
commit
9e33f90e34
|
@ -0,0 +1,138 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _DRIVERS_ILI9341_H
|
||||
#define _DRIVERS_ILI9341_H
|
||||
|
||||
#include <osdefs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
#define NO_OPERATION 0x00
|
||||
#define SOFTWARE_RESET 0x01
|
||||
#define READ_ID 0x04
|
||||
#define READ_STATUS 0x09
|
||||
#define READ_POWER_MODE 0x0A
|
||||
#define READ_MADCTL 0x0B
|
||||
#define READ_PIXEL_FORMAT 0x0C
|
||||
#define READ_IMAGE_FORMAT 0x0D
|
||||
#define READ_SIGNAL_MODE 0x0E
|
||||
#define READ_SELT_DIAG_RESULT 0x0F
|
||||
#define SLEEP_ON 0x10
|
||||
#define SLEEP_OFF 0x11
|
||||
#define PARTIAL_DISPALY_ON 0x12
|
||||
#define NORMAL_DISPALY_ON 0x13
|
||||
#define INVERSION_DISPALY_OFF 0x20
|
||||
#define INVERSION_DISPALY_ON 0x21
|
||||
#define GAMMA_SET 0x26
|
||||
#define DISPALY_OFF 0x28
|
||||
#define DISPALY_ON 0x29
|
||||
#define HORIZONTAL_ADDRESS_SET 0x2A
|
||||
#define VERTICAL_ADDRESS_SET 0x2B
|
||||
#define MEMORY_WRITE 0x2C
|
||||
#define COLOR_SET 0x2D
|
||||
#define MEMORY_READ 0x2E
|
||||
#define PARTIAL_AREA 0x30
|
||||
#define VERTICAL_SCROL_DEFINE 0x33
|
||||
#define TEAR_EFFECT_LINE_OFF 0x34
|
||||
#define TEAR_EFFECT_LINE_ON 0x35
|
||||
#define MEMORY_ACCESS_CTL 0x36
|
||||
#define VERTICAL_SCROL_S_ADD 0x37
|
||||
#define IDLE_MODE_OFF 0x38
|
||||
#define IDLE_MODE_ON 0x39
|
||||
#define PIXEL_FORMAT_SET 0x3A
|
||||
#define WRITE_MEMORY_CONTINUE 0x3C
|
||||
#define READ_MEMORY_CONTINUE 0x3E
|
||||
#define SET_TEAR_SCANLINE 0x44
|
||||
#define GET_SCANLINE 0x45
|
||||
#define WRITE_BRIGHTNESS 0x51
|
||||
#define READ_BRIGHTNESS 0x52
|
||||
#define WRITE_CTRL_DISPALY 0x53
|
||||
#define READ_CTRL_DISPALY 0x54
|
||||
#define WRITE_BRIGHTNESS_CTL 0x55
|
||||
#define READ_BRIGHTNESS_CTL 0x56
|
||||
#define WRITE_MIN_BRIGHTNESS 0x5E
|
||||
#define READ_MIN_BRIGHTNESS 0x5F
|
||||
#define READ_ID1 0xDA
|
||||
#define READ_ID2 0xDB
|
||||
#define READ_ID3 0xDC
|
||||
#define RGB_IF_SIGNAL_CTL 0xB0
|
||||
#define NORMAL_FRAME_CTL 0xB1
|
||||
#define IDLE_FRAME_CTL 0xB2
|
||||
#define PARTIAL_FRAME_CTL 0xB3
|
||||
#define INVERSION_CTL 0xB4
|
||||
#define BLANK_PORCH_CTL 0xB5
|
||||
#define DISPALY_FUNCTION_CTL 0xB6
|
||||
#define ENTRY_MODE_SET 0xB7
|
||||
#define BACKLIGHT_CTL1 0xB8
|
||||
#define BACKLIGHT_CTL2 0xB9
|
||||
#define BACKLIGHT_CTL3 0xBA
|
||||
#define BACKLIGHT_CTL4 0xBB
|
||||
#define BACKLIGHT_CTL5 0xBC
|
||||
#define BACKLIGHT_CTL7 0xBE
|
||||
#define BACKLIGHT_CTL8 0xBF
|
||||
#define POWER_CTL1 0xC0
|
||||
#define POWER_CTL2 0xC1
|
||||
#define VCOM_CTL1 0xC5
|
||||
#define VCOM_CTL2 0xC7
|
||||
#define NV_MEMORY_WRITE 0xD0
|
||||
#define NV_MEMORY_PROTECT_KEY 0xD1
|
||||
#define NV_MEMORY_STATUS_READ 0xD2
|
||||
#define READ_ID4 0xD3
|
||||
#define POSITIVE_GAMMA_CORRECT 0xE0
|
||||
#define NEGATIVE_GAMMA_CORRECT 0xE1
|
||||
#define DIGITAL_GAMMA_CTL1 0xE2
|
||||
#define DIGITAL_GAMMA_CTL2 0xE3
|
||||
#define INTERFACE_CTL 0xF6
|
||||
|
||||
enum lcd_dir_t
|
||||
{
|
||||
DIR_XY_RLUD = 0x00,
|
||||
DIR_YX_RLUD = 0x20,
|
||||
DIR_XY_LRUD = 0x40,
|
||||
DIR_YX_LRUD = 0x60,
|
||||
DIR_XY_RLDU = 0x80,
|
||||
DIR_YX_RLDU = 0xA0,
|
||||
DIR_XY_LRDU = 0xC0,
|
||||
DIR_YX_LRDU = 0xE0,
|
||||
DIR_XY_MASK = 0x20,
|
||||
DIR_MASK = 0xE0,
|
||||
};
|
||||
#define LCD_X_MAX 240
|
||||
#define LCD_Y_MAX 320
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* @brief Install a ili9341 lcd driver
|
||||
*
|
||||
* @param[in] spi_handle The SPI controller handle
|
||||
* @param[in] dcx_gpio_handle The GPIO controller handle for dcx
|
||||
* @param[in] dcx_gpio_pin The GPIO pin for dcx
|
||||
*
|
||||
* @return result
|
||||
* - 0 Fail
|
||||
* - other The driver handle
|
||||
*/
|
||||
handle_t ili9341_driver_install(handle_t spi_handle, handle_t dcx_gpio_handle, uint32_t dcx_gpio_pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVERS_ILI9341_H */
|
|
@ -0,0 +1,303 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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 "display/ili9341.h"
|
||||
#include <hal.h>
|
||||
#include <kernel/driver_impl.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
using namespace sys;
|
||||
|
||||
#define SPI_SLAVE_SELECT 3
|
||||
#define SPI_CLOCK_RATE 3200000U
|
||||
#define WAIT_CYCLE 0U
|
||||
|
||||
enum _instruction_length
|
||||
{
|
||||
INSTRUCTION_LEN_0 = 0,
|
||||
INSTRUCTION_LEN_8 = 8,
|
||||
INSTRUCTION_LEN_16 = 16,
|
||||
INSTRUCTION_LEN_32 = 32,
|
||||
};
|
||||
|
||||
enum _address_length
|
||||
{
|
||||
ADDRESS_LEN_0 = 0,
|
||||
ADDRESS_LEN_8 = 8,
|
||||
ADDRESS_LEN_16 = 16,
|
||||
ADDRESS_LEN_32 = 32,
|
||||
};
|
||||
|
||||
enum _frame_length
|
||||
{
|
||||
FRAME_LEN_0 = 0,
|
||||
FRAME_LEN_8 = 8,
|
||||
FRAME_LEN_16 = 16,
|
||||
FRAME_LEN_32 = 32,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dir;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} lcd_ctl_t;
|
||||
|
||||
static lcd_ctl_t lcd_ctl;
|
||||
|
||||
namespace
|
||||
{
|
||||
static constexpr uint16_t pixel_width = LCD_Y_MAX;
|
||||
static constexpr uint16_t pixel_height = LCD_X_MAX;
|
||||
}
|
||||
|
||||
class ili9341_primary_surface : public surface, public heap_object, public free_object_access
|
||||
{
|
||||
public:
|
||||
ili9341_primary_surface()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_first_open() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_last_close() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual size_u_t get_pixel_size() noexcept override
|
||||
{
|
||||
return { pixel_width, pixel_height };
|
||||
}
|
||||
|
||||
virtual color_format_t get_format() noexcept override
|
||||
{
|
||||
return color_format_t::COLOR_FORMAT_B5G6R5_UNORM;
|
||||
}
|
||||
|
||||
virtual surface_data_t lock(const rect_u_t &rect) override
|
||||
{
|
||||
throw std::runtime_error("Not supported.");
|
||||
}
|
||||
|
||||
virtual void unlock(surface_data_t &data) override
|
||||
{
|
||||
throw std::runtime_error("Not supported.");
|
||||
}
|
||||
|
||||
virtual surface_location_t get_location() noexcept override
|
||||
{
|
||||
return surface_location_t::DEVICE_MEMORY;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class ili9341_driver : public display_driver, public heap_object, public free_object_access
|
||||
{
|
||||
public:
|
||||
ili9341_driver(handle_t spi_handle, handle_t dcx_gpio_handle, uint32_t dcx_gpio_pin)
|
||||
: spi_driver_(system_handle_to_object(spi_handle).get_object().as<spi_driver>())
|
||||
, dcx_gpio_driver_(system_handle_to_object(dcx_gpio_handle).get_object().as<gpio_driver>())
|
||||
, dcx_gpio_pin_(dcx_gpio_pin)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void install() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_first_open() override
|
||||
{
|
||||
auto spi = make_accessor(spi_driver_);
|
||||
spi8_dev_ = make_accessor(spi->get_device(SPI_MODE_0, SPI_FF_OCTAL, 1 << SPI_SLAVE_SELECT, 8));
|
||||
spi16_dev_ = make_accessor(spi->get_device(SPI_MODE_0, SPI_FF_OCTAL, 1 << SPI_SLAVE_SELECT, 16));
|
||||
spi32_dev_ = make_accessor(spi->get_device(SPI_MODE_0, SPI_FF_OCTAL, 1 << SPI_SLAVE_SELECT, 32));
|
||||
|
||||
dcx_gpio_ = make_accessor(dcx_gpio_driver_);
|
||||
dcx_gpio_->set_drive_mode(dcx_gpio_pin_, GPIO_DM_OUTPUT);
|
||||
dcx_gpio_->set_pin_value(dcx_gpio_pin_, GPIO_PV_HIGH);
|
||||
|
||||
spi8_dev_->config_non_standard(INSTRUCTION_LEN_8, ADDRESS_LEN_0, WAIT_CYCLE, SPI_AITM_AS_FRAME_FORMAT);
|
||||
spi16_dev_->config_non_standard(INSTRUCTION_LEN_16, ADDRESS_LEN_0, WAIT_CYCLE, SPI_AITM_AS_FRAME_FORMAT);
|
||||
spi32_dev_->config_non_standard(INSTRUCTION_LEN_0, ADDRESS_LEN_32, WAIT_CYCLE, SPI_AITM_AS_FRAME_FORMAT);
|
||||
|
||||
spi8_dev_->set_clock_rate(SPI_CLOCK_RATE);
|
||||
spi16_dev_->set_clock_rate(SPI_CLOCK_RATE);
|
||||
spi32_dev_->set_clock_rate(SPI_CLOCK_RATE);
|
||||
initialize();
|
||||
}
|
||||
|
||||
virtual void on_last_close() override
|
||||
{
|
||||
spi8_dev_.reset();
|
||||
spi16_dev_.reset();
|
||||
spi32_dev_.reset();
|
||||
dcx_gpio_.reset();
|
||||
}
|
||||
|
||||
virtual object_ptr<surface> get_primary_surface() override
|
||||
{
|
||||
return make_object<ili9341_primary_surface>();
|
||||
}
|
||||
|
||||
virtual void clear(object_ptr<surface> surface, const rect_u_t &rect, const color_value_t &color) override
|
||||
{
|
||||
lcd_set_area(rect.left, rect.top, rect.right-1, rect.bottom-1);
|
||||
uint32_t data = (uint32_t)rgb565::from(color).value << 16 | (uint32_t)rgb565::from(color).value;
|
||||
|
||||
tft_fill_data(&data, rect.get_size().width * rect.get_size().height / 2);
|
||||
}
|
||||
|
||||
virtual void copy_subresource(object_ptr<surface> src, object_ptr<surface> dest, const rect_u_t &src_rect, const point_u_t &dest_position) override
|
||||
{
|
||||
if(src->get_location() == surface_location_t::DEVICE_MEMORY)
|
||||
{
|
||||
}
|
||||
if (dest->get_location() == surface_location_t::DEVICE_MEMORY)
|
||||
{
|
||||
auto locker = src->lock(src_rect);
|
||||
lcd_draw_picture(dest_position.x, dest_position.y, src_rect.get_size().width, src_rect.get_size().height, (uint16_t *)locker.data.data());
|
||||
src->unlock(locker);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void set_dcx_control()
|
||||
{
|
||||
dcx_gpio_->set_pin_value(dcx_gpio_pin_, GPIO_PV_LOW);
|
||||
}
|
||||
|
||||
void set_dcx_data()
|
||||
{
|
||||
dcx_gpio_->set_pin_value(dcx_gpio_pin_, GPIO_PV_HIGH);
|
||||
}
|
||||
|
||||
void tft_write_command(const uint8_t data_buff)
|
||||
{
|
||||
set_dcx_control();
|
||||
spi8_dev_->write( {&data_buff, 1L});
|
||||
}
|
||||
|
||||
void tft_write_byte(const uint8_t *data_buff, size_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi8_dev_->write( {data_buff, std::ptrdiff_t(length)} );
|
||||
}
|
||||
|
||||
void tft_write_half(const uint16_t *data_buff, size_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi16_dev_->write({ (const uint8_t *)data_buff, std::ptrdiff_t(length) * 2 });
|
||||
}
|
||||
|
||||
void tft_write_word(const uint32_t *data_buff, size_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi32_dev_->write({ (const uint8_t *)data_buff, std::ptrdiff_t(length) * 4 });
|
||||
}
|
||||
|
||||
void tft_fill_data(uint32_t *data_buf, uint32_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi32_dev_->fill(0, *data_buf, *data_buf, std::ptrdiff_t(length) - 1);
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
uint8_t data;
|
||||
tft_write_command(SOFTWARE_RESET);
|
||||
usleep(100 * 1000);
|
||||
tft_write_command(SLEEP_OFF);
|
||||
usleep(100 * 1000);
|
||||
tft_write_command(PIXEL_FORMAT_SET);
|
||||
data = 0x55;
|
||||
tft_write_byte(&data, 1);
|
||||
lcd_set_direction(DIR_YX_RLUD);
|
||||
tft_write_command(DISPALY_ON);
|
||||
}
|
||||
|
||||
void lcd_set_direction(enum lcd_dir_t dir)
|
||||
{
|
||||
uint8_t dir_data = dir;
|
||||
dir_data |= 0x08;
|
||||
lcd_ctl.dir = dir_data;
|
||||
if (lcd_ctl.dir & DIR_XY_MASK)
|
||||
{
|
||||
lcd_ctl.width = LCD_Y_MAX - 1;
|
||||
lcd_ctl.height = LCD_X_MAX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_ctl.width = LCD_X_MAX - 1;
|
||||
lcd_ctl.height = LCD_Y_MAX - 1;
|
||||
}
|
||||
|
||||
tft_write_command(MEMORY_ACCESS_CTL);
|
||||
tft_write_byte((uint8_t *)&lcd_ctl.dir, 1);
|
||||
}
|
||||
|
||||
void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
|
||||
{
|
||||
uint8_t data[4];
|
||||
|
||||
data[0] = (uint8_t)(x1 >> 8);
|
||||
data[1] = (uint8_t)(x1);
|
||||
data[2] = (uint8_t)(x2 >> 8);
|
||||
data[3] = (uint8_t)(x2);
|
||||
tft_write_command(HORIZONTAL_ADDRESS_SET);
|
||||
tft_write_byte(data, 4);
|
||||
data[0] = (uint8_t)(y1 >> 8);
|
||||
data[1] = (uint8_t)(y1);
|
||||
data[2] = (uint8_t)(y2 >> 8);
|
||||
data[3] = (uint8_t)(y2);
|
||||
tft_write_command(VERTICAL_ADDRESS_SET);
|
||||
tft_write_byte(data, 4);
|
||||
tft_write_command(MEMORY_WRITE);
|
||||
}
|
||||
|
||||
void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t *ptr)
|
||||
{
|
||||
lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
|
||||
tft_write_half(ptr, width * height);
|
||||
}
|
||||
|
||||
private:
|
||||
object_ptr<spi_driver> spi_driver_;
|
||||
object_ptr<gpio_driver> dcx_gpio_driver_;
|
||||
uint32_t dcx_gpio_pin_;
|
||||
|
||||
object_accessor<gpio_driver> dcx_gpio_;
|
||||
object_accessor<spi_device_driver> spi8_dev_;
|
||||
object_accessor<spi_device_driver> spi16_dev_;
|
||||
object_accessor<spi_device_driver> spi32_dev_;
|
||||
};
|
||||
|
||||
handle_t ili9341_driver_install(handle_t spi_handle, handle_t dcx_gpio_handle, uint32_t dcx_gpio_pin)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto driver = make_object<ili9341_driver>(spi_handle, dcx_gpio_handle, dcx_gpio_pin);
|
||||
driver->install();
|
||||
return system_alloc_handle(make_accessor(driver));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return NULL_HANDLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _FREERTOS_DISPLAY_CONTEXT_H
|
||||
#define _FREERTOS_DISPLAY_CONTEXT_H
|
||||
|
||||
#include <osdefs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/* clang-format off */
|
||||
#define LCD_X_MAX 240
|
||||
#define LCD_Y_MAX 320
|
||||
|
||||
#define BLACK {0, 0, 0, 0} //0x0000
|
||||
#define NAVY {0, 0, 0.48, 0} //0x000F
|
||||
#define DARKGREEN {0, 0.49, 0, 0} //0x03E0
|
||||
#define DARKCYAN {0, 0.49, 0.48, 0} //0x03EF
|
||||
#define MAROON {0.48, 0, 0, 0} //0x7800
|
||||
#define PURPLE {0.48, 0, 0.48, 0} //0x780F
|
||||
#define OLIVE {0.48, 0.49, 0, 0} //0x7BE0
|
||||
#define LIGHTGREY {0.77, 0.76, 0.77, 0} //0xC618
|
||||
#define DARKGREY {0.48, 0.49, 0.48, 0} //0x7BEF
|
||||
#define BLUE {0, 0, 1, 0} //0x001F
|
||||
#define GREEN {0, 1, 0, 0} //0x07E0
|
||||
#define CYAN {0, 1, 1, 0} //0x07FF
|
||||
#define RED {1, 0, 0, 0} //0xF800
|
||||
#define MAGENTA {1, 0, 1, 0} //0xF81F
|
||||
#define YELLOW {1, 1, 0, 0} //0xFFE0
|
||||
#define WHITE {1, 1, 1, 0} //0xFFFF
|
||||
#define ORANGE {1, 0.65, 0, 0} //0xFD20
|
||||
#define GREENYELLOW {0.68, 1, 0.16, 0} //0xAFE5
|
||||
#define PINK {1, 0, 1, 0} //0xF81F
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* @brief Create a display context
|
||||
*
|
||||
* @param[in] lcd_handle The LCD controller handle
|
||||
*
|
||||
* @return result
|
||||
* - 0 Fail
|
||||
* - other The display context handle
|
||||
*/
|
||||
handle_t create_display_context(handle_t lcd_handle);
|
||||
|
||||
int display_screen(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, const uint8_t *picture);
|
||||
int capture_picture(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, uint8_t *picture);
|
||||
int clear_screen(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, const color_value_t *color);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVERS_SDCARD_H */
|
|
@ -425,6 +425,71 @@ public:
|
|||
virtual size_t write(gsl::span<const uint8_t> buffer) = 0;
|
||||
};
|
||||
|
||||
template <color_format_t>
|
||||
struct color;
|
||||
|
||||
template <>
|
||||
struct color<color_format_t::COLOR_FORMAT_B5G6R5_UNORM>
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
static color from(color_value_t value) noexcept
|
||||
{
|
||||
auto r = value.r * 31;
|
||||
auto g = value.g * 63;
|
||||
auto b = value.b * 31;
|
||||
return { static_cast<uint16_t>((uint16_t(r) << 11) | (uint16_t(g) << 5) | uint16_t(b)) };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct color<color_format_t::COLOR_FORMAT_R32G32B32A32_FLOAT>
|
||||
{
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
using rgb565 = color<color_format_t::COLOR_FORMAT_B5G6R5_UNORM>;
|
||||
|
||||
struct rect_u_t
|
||||
{
|
||||
uint32_t left;
|
||||
uint32_t top;
|
||||
uint32_t right;
|
||||
uint32_t bottom;
|
||||
rect_u_t() = default;
|
||||
rect_u_t(const point_u_t &position, const size_u_t &size) noexcept
|
||||
: left(position.x), top(position.y), right(position.x + size.width), bottom(position.y + size.height)
|
||||
{
|
||||
}
|
||||
size_u_t get_size() const noexcept { return { right - left, bottom - top }; }
|
||||
};
|
||||
|
||||
typedef struct _surface_data
|
||||
{
|
||||
gsl::span<uint8_t> data;
|
||||
size_t stride;
|
||||
rect_u_t rect;
|
||||
} surface_data_t;
|
||||
|
||||
class surface : public virtual object_access
|
||||
{
|
||||
public:
|
||||
virtual size_u_t get_pixel_size() = 0;
|
||||
virtual color_format_t get_format() = 0;
|
||||
virtual surface_location_t get_location() noexcept = 0;
|
||||
|
||||
virtual surface_data_t lock(const rect_u_t &rect) = 0;
|
||||
virtual void unlock(surface_data_t &data) = 0;
|
||||
};
|
||||
|
||||
class display_driver : public driver
|
||||
{
|
||||
public:
|
||||
virtual object_ptr<surface> get_primary_surface() = 0;
|
||||
virtual void clear(object_ptr<surface> surface, const rect_u_t &rect, const color_value_t &color) = 0;
|
||||
virtual void copy_subresource(object_ptr<surface> src, object_ptr<surface> dest, const rect_u_t &src_rect, const point_u_t &dest_position) = 0;
|
||||
};
|
||||
|
||||
extern driver_registry_t g_hal_drivers[];
|
||||
extern driver_registry_t g_dma_drivers[];
|
||||
extern driver_registry_t g_system_drivers[];
|
||||
|
|
|
@ -322,6 +322,37 @@ typedef enum _dhcp_state
|
|||
DHCP_FAIL
|
||||
} dhcp_state_t;
|
||||
|
||||
typedef struct _size_u
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} size_u_t;
|
||||
|
||||
typedef enum _color_format
|
||||
{
|
||||
COLOR_FORMAT_B5G6R5_UNORM,
|
||||
COLOR_FORMAT_R32G32B32A32_FLOAT,
|
||||
} color_format_t;
|
||||
|
||||
typedef struct _color_value
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
} color_value_t;
|
||||
|
||||
typedef struct _point_u
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
} point_u_t;
|
||||
|
||||
typedef enum _surface_location
|
||||
{
|
||||
SYSTEM_MEMORY,
|
||||
DEVICE_MEMORY,
|
||||
} surface_location_t;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* 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 "display_context.h"
|
||||
#include <gsl/span>
|
||||
#include <hal.h>
|
||||
#include <kernel/driver_impl.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace sys;
|
||||
|
||||
size_t get_pixel_bytes(color_format_t format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case color_format_t::COLOR_FORMAT_B5G6R5_UNORM:
|
||||
return 2;
|
||||
case color_format_t::COLOR_FORMAT_R32G32B32A32_FLOAT:
|
||||
return 16;
|
||||
default:
|
||||
throw std::invalid_argument("Invalid format.");
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_bits(const uint8_t *src, size_t src_stride, uint8_t *dest, size_t dest_stride, size_t line_size, size_t height)
|
||||
{
|
||||
for (size_t y = 0; y < height; y++)
|
||||
{
|
||||
auto begin = src + y * src_stride;
|
||||
std::copy(begin, begin + line_size, dest + y * dest_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_bits(const surface_data_t &surface_data, color_format_t format, const color_value_t &color)
|
||||
{
|
||||
if (format == color_format_t::COLOR_FORMAT_B5G6R5_UNORM)
|
||||
{
|
||||
gsl::span<uint16_t> span = { reinterpret_cast<uint16_t *>(surface_data.data.data()), surface_data.data.size() / 2 };
|
||||
|
||||
auto src = span.data();
|
||||
auto value = rgb565::from(color).value;
|
||||
for (size_t y = 0; y < surface_data.rect.bottom - surface_data.rect.top; y++)
|
||||
{
|
||||
for (size_t x = 0; x < surface_data.rect.right - surface_data.rect.left; x++)
|
||||
src[x] = value;
|
||||
|
||||
src += surface_data.stride / 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
class software_surface : public surface, public heap_object, public free_object_access
|
||||
{
|
||||
public:
|
||||
software_surface(color_format_t format, const size_u_t &size)
|
||||
: format_(format), size_(size), stride_(size.width * get_pixel_bytes(format))
|
||||
{
|
||||
auto bytes = stride_ * size.height;
|
||||
storage_ = std::make_unique<uint8_t[]>(bytes);
|
||||
data_ = { storage_.get(), ptrdiff_t(bytes) };
|
||||
}
|
||||
|
||||
software_surface(color_format_t format, const size_u_t &size, const surface_data_t &surface_data, bool copy)
|
||||
: format_(format), size_(size)
|
||||
{
|
||||
if (!copy)
|
||||
{
|
||||
stride_ = surface_data.stride;
|
||||
data_ = surface_data.data;
|
||||
|
||||
auto bytes = stride_ * size.height;
|
||||
configASSERT(bytes == data_.size_bytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
stride_ = size.width * get_pixel_bytes(format);
|
||||
auto bytes = stride_ * size.height;
|
||||
storage_ = std::make_unique<uint8_t[]>(bytes);
|
||||
data_ = { storage_.get(), ptrdiff_t(bytes) };
|
||||
copy_bits(surface_data.data.data(), surface_data.stride, data_.data(), stride_, stride_, size.height);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_first_open() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_last_close() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual size_u_t get_pixel_size() noexcept override
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
virtual color_format_t get_format() noexcept override
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
virtual surface_location_t get_location() noexcept override
|
||||
{
|
||||
return surface_location_t::SYSTEM_MEMORY;
|
||||
;
|
||||
}
|
||||
|
||||
virtual surface_data_t lock(const rect_u_t &rect) override
|
||||
{
|
||||
auto begin = rect.top * stride_ + get_pixel_bytes(format_) * rect.left;
|
||||
auto end = (int32_t(rect.bottom - 1)) * stride_ + get_pixel_bytes(format_) * rect.right;
|
||||
|
||||
if (begin > data_.size_bytes() || end > data_.size_bytes())
|
||||
throw std::out_of_range("Lock rect is out of range.");
|
||||
|
||||
return { { data_.data() + begin, data_.data() + end }, stride_, rect };
|
||||
}
|
||||
|
||||
virtual void unlock(surface_data_t &data) override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
color_format_t format_;
|
||||
size_u_t size_;
|
||||
surface_location_t location_;
|
||||
size_t stride_;
|
||||
|
||||
gsl::span<uint8_t> data_;
|
||||
std::unique_ptr<uint8_t[]> storage_;
|
||||
};
|
||||
|
||||
class k_display_context : public display_driver, public heap_object, public free_object_access
|
||||
{
|
||||
public:
|
||||
k_display_context(object_accessor<display_driver> &&device)
|
||||
: device_(std::move(device))
|
||||
{
|
||||
primary_surface_ = device_->get_primary_surface();
|
||||
offscreen_surface_ = get_software_surface(primary_surface_->get_format(), primary_surface_->get_pixel_size());
|
||||
}
|
||||
|
||||
virtual object_ptr<surface> get_primary_surface() override
|
||||
{
|
||||
return primary_surface_;
|
||||
}
|
||||
|
||||
virtual object_ptr<surface> get_software_surface(color_format_t format, const size_u_t &size)
|
||||
{
|
||||
return make_object<software_surface>(format, size);
|
||||
}
|
||||
|
||||
virtual object_ptr<surface> get_software_surface(color_format_t format, const size_u_t &size, const surface_data_t &data, bool copy)
|
||||
{
|
||||
return make_object<software_surface>(format, size, data, copy);
|
||||
}
|
||||
|
||||
virtual void install() override
|
||||
{
|
||||
}
|
||||
virtual void on_first_open() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_last_close() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void clear(object_ptr<surface> surface, const rect_u_t &rect, const color_value_t &color) override
|
||||
{
|
||||
if (surface->get_location() == surface_location_t::DEVICE_MEMORY)
|
||||
{
|
||||
device_->clear(surface, rect, color);
|
||||
auto src_locker = offscreen_surface_->lock(rect);
|
||||
fill_bits(src_locker, offscreen_surface_->get_format(), color);
|
||||
offscreen_surface_->unlock(src_locker);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto src_locker = surface->lock(rect);
|
||||
fill_bits(src_locker, surface->get_format(), color);
|
||||
surface->unlock(src_locker);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void copy_subresource(object_ptr<surface> src, object_ptr<surface> dest, const rect_u_t &src_rect, const point_u_t &dest_position) override
|
||||
{
|
||||
if (src->get_format() != dest->get_format())
|
||||
throw std::invalid_argument("Src and dest must have same format.");
|
||||
|
||||
if (src->get_location() == surface_location_t::SYSTEM_MEMORY && dest->get_location() == surface_location_t::SYSTEM_MEMORY)
|
||||
{
|
||||
auto src_locker = src->lock(src_rect);
|
||||
auto dest_locker = dest->lock({ dest_position, src_rect.get_size() });
|
||||
auto line_size = src_rect.get_size().width * get_pixel_bytes(src->get_format());
|
||||
copy_bits(src_locker.data.data(), src_locker.stride, dest_locker.data.data(), dest_locker.stride, line_size, src_rect.get_size().height);
|
||||
dest->unlock(dest_locker);
|
||||
src->unlock(src_locker);
|
||||
}
|
||||
else if (dest->get_location() == surface_location_t::SYSTEM_MEMORY)
|
||||
{
|
||||
auto src_locker = offscreen_surface_->lock(src_rect);
|
||||
auto dest_locker = dest->lock({ dest_position, src_rect.get_size() });
|
||||
auto line_size = src_rect.get_size().width * get_pixel_bytes(offscreen_surface_->get_format());
|
||||
copy_bits(src_locker.data.data(), src_locker.stride, dest_locker.data.data(), dest_locker.stride, line_size, src_rect.get_size().height);
|
||||
dest->unlock(dest_locker);
|
||||
offscreen_surface_->unlock(src_locker);
|
||||
}
|
||||
else if (src->get_location() == surface_location_t::SYSTEM_MEMORY)
|
||||
{
|
||||
device_->copy_subresource(src, dest, src_rect, dest_position);
|
||||
auto src_locker = src->lock(src_rect);
|
||||
auto dest_locker = offscreen_surface_->lock({ dest_position, src_rect.get_size() });
|
||||
auto line_size = src_rect.get_size().width * get_pixel_bytes(src->get_format());
|
||||
copy_bits(src_locker.data.data(), src_locker.stride, dest_locker.data.data(), dest_locker.stride, line_size, src_rect.get_size().height);
|
||||
offscreen_surface_->unlock(dest_locker);
|
||||
src->unlock(src_locker);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
object_accessor<display_driver> device_;
|
||||
object_ptr<surface> primary_surface_;
|
||||
object_ptr<surface> offscreen_surface_;
|
||||
};
|
||||
|
||||
#define DISPLAY_ENTRY \
|
||||
auto &obj = system_handle_to_object(display_handle); \
|
||||
configASSERT(obj.is<k_display_context>()); \
|
||||
auto f = obj.as<k_display_context>();
|
||||
|
||||
#define CATCH_ALL \
|
||||
catch (...) { return -1; }
|
||||
|
||||
handle_t create_display_context(handle_t lcd_handle)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto display_context = make_object<k_display_context>(system_handle_to_object(lcd_handle).move_as<display_driver>());
|
||||
|
||||
return system_alloc_handle(make_accessor(display_context));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
int clear_screen(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, const color_value_t *color)
|
||||
{
|
||||
try
|
||||
{
|
||||
DISPLAY_ENTRY;
|
||||
auto surf = f->get_primary_surface();
|
||||
rect_u_t rect = { *position, { width, height } };
|
||||
f->clear(surf, rect, *color);
|
||||
|
||||
return 0;
|
||||
}
|
||||
CATCH_ALL;
|
||||
}
|
||||
|
||||
int display_screen(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, const uint8_t *picture)
|
||||
{
|
||||
try
|
||||
{
|
||||
DISPLAY_ENTRY;
|
||||
|
||||
rect_u_t src_rect = { { 0, 0 }, { width, height } };
|
||||
|
||||
auto src_surface = f->get_software_surface(color_format_t::COLOR_FORMAT_B5G6R5_UNORM, { width, height });
|
||||
auto dst_surface = f->get_primary_surface();
|
||||
|
||||
auto src_locker = src_surface->lock(src_rect);
|
||||
auto line_size = src_rect.get_size().width * get_pixel_bytes(src_surface->get_format());
|
||||
copy_bits(picture, src_locker.stride, src_locker.data.data(), src_locker.stride, line_size, src_rect.get_size().height);
|
||||
src_surface->unlock(src_locker);
|
||||
|
||||
f->copy_subresource(src_surface, dst_surface, src_rect, *position);
|
||||
return 0;
|
||||
}
|
||||
CATCH_ALL;
|
||||
}
|
||||
|
||||
int capture_picture(handle_t display_handle, const point_u_t *position, uint32_t width, uint32_t height, uint8_t *picture)
|
||||
{
|
||||
try
|
||||
{
|
||||
DISPLAY_ENTRY;
|
||||
|
||||
rect_u_t src_rect = { *position, { width, height } };
|
||||
auto src_surface = f->get_primary_surface();
|
||||
auto dst_surface = f->get_software_surface(color_format_t::COLOR_FORMAT_B5G6R5_UNORM, { width, height });
|
||||
f->copy_subresource(src_surface, dst_surface, src_rect, {0, 0});
|
||||
|
||||
rect_u_t dst_rect = { {0, 0}, { width, height } };
|
||||
auto dst_locker = dst_surface->lock(dst_rect);
|
||||
auto line_size = dst_rect.get_size().width * get_pixel_bytes(dst_surface->get_format());
|
||||
copy_bits(dst_locker.data.data(), dst_locker.stride, picture, dst_locker.stride, line_size, dst_rect.get_size().height);
|
||||
dst_surface->unlock(dst_locker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
CATCH_ALL;
|
||||
}
|
Loading…
Reference in New Issue