add display driver

feature/graphics
jiangxiangbing 2019-02-14 20:06:49 +08:00
parent 4b522dc9e2
commit 9e33f90e34
6 changed files with 930 additions and 0 deletions

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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[];

View File

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

View File

@ -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;
}