3#if defined(ESP_PLATFORM)
11#if CONFIG_IDF_TARGET_ESP32S3
13#include "esp_async_memcpy.h"
15#include "esp_memory_utils.h"
16#include "freertos/FreeRTOS.h"
17#include "freertos/semphr.h"
18#include "roo_logging.h"
20#ifndef ROO_DISPLAY_DMA_MIN_BYTES
21#define ROO_DISPLAY_DMA_MIN_BYTES 256
27constexpr size_t kDmaAlign = 16;
28constexpr size_t kExtDmaAlign = 32;
29constexpr size_t kDmaThresholdBytes = ROO_DISPLAY_DMA_MIN_BYTES;
33 : done(xSemaphoreCreateBinaryStatic(&done_buf)),
34 lock(xSemaphoreCreateMutexStatic(&lock_buf)) {}
36 async_memcpy_handle_t handle =
nullptr;
37 StaticSemaphore_t done_buf;
38 SemaphoreHandle_t done =
nullptr;
39 StaticSemaphore_t lock_buf;
40 SemaphoreHandle_t lock =
nullptr;
42 const roo::byte* src_row =
nullptr;
43 roo::byte* dst_row =
nullptr;
44 size_t src_stride = 0;
45 size_t dst_stride = 0;
47 size_t remaining_rows = 0;
48 bool transfer_failed =
false;
49 bool install_attempted =
false;
57void copy_sync(
const roo::byte* src_ptr,
size_t src_stride, roo::byte* dst_ptr,
58 size_t dst_stride,
size_t width,
size_t height) {
59 if (src_stride == width && dst_stride == width) {
60 std::memcpy(dst_ptr, src_ptr, width * height);
64 const roo::byte* src_row = src_ptr;
65 roo::byte* dst_row = dst_ptr;
66 for (
size_t row = 0; row < height; ++row) {
67 std::memcpy(dst_row, src_row, width);
68 src_row += src_stride;
69 dst_row += dst_stride;
73inline bool is_aligned(
const void* ptr,
size_t align) {
74 return (
reinterpret_cast<uintptr_t
>(ptr) % align) == 0;
77inline size_t dma_align_for_ptr(
const void* ptr) {
78 return esp_ptr_external_ram(ptr) ? kExtDmaAlign : kDmaAlign;
81inline bool can_dma_copy_rows(
const void* src,
const void* dst,
82 size_t row_bytes,
size_t src_stride,
84 const bool src_dma_capable =
85 esp_ptr_dma_capable(src) || esp_ptr_dma_ext_capable(src);
86 const bool dst_dma_capable =
87 esp_ptr_dma_capable(dst) || esp_ptr_dma_ext_capable(dst);
88 const size_t required_align =
89 std::max(dma_align_for_ptr(src), dma_align_for_ptr(dst));
90 return row_bytes > 0 && is_aligned(src, required_align) &&
91 is_aligned(dst, required_align) && (row_bytes % required_align) == 0 &&
92 (src_stride % required_align) == 0 &&
93 (dst_stride % required_align) == 0 && src_dma_capable &&
97bool on_copy_done(async_memcpy_handle_t handle, async_memcpy_event_t*,
99 auto* st =
static_cast<BlitState*
>(ctx);
100 if (st->remaining_rows > 0) {
101 st->src_row += st->src_stride;
102 st->dst_row += st->dst_stride;
103 --st->remaining_rows;
106 if (st->remaining_rows == 0 || st->transfer_failed) {
107 BaseType_t high_wakeup = pdFALSE;
108 xSemaphoreGiveFromISR(st->done, &high_wakeup);
109 return high_wakeup == pdTRUE;
113 esp_async_memcpy(handle, st->dst_row,
const_cast<roo::byte*
>(st->src_row),
114 st->row_bytes, on_copy_done, st);
116 st->transfer_failed =
true;
117 BaseType_t high_wakeup = pdFALSE;
118 xSemaphoreGiveFromISR(st->done, &high_wakeup);
119 return high_wakeup == pdTRUE;
124bool dma_copy_rows_and_wait(BlitState& st,
const roo::byte* src, roo::byte* dst,
125 size_t src_stride,
size_t dst_stride,
126 size_t row_bytes,
size_t row_count) {
127 while (xSemaphoreTake(st.done, 0) == pdTRUE) {
132 st.src_stride = src_stride;
133 st.dst_stride = dst_stride;
134 st.row_bytes = row_bytes;
135 st.remaining_rows = row_count;
136 st.transfer_failed =
false;
138 esp_err_t err = esp_async_memcpy(st.handle, st.dst_row,
139 const_cast<roo::byte*
>(st.src_row),
140 st.row_bytes, on_copy_done, &st);
141 CHECK_EQ(err, ESP_OK) << esp_err_to_name(err);
143 CHECK_EQ(xSemaphoreTake(st.done, portMAX_DELAY), pdTRUE);
144 return !st.transfer_failed;
148 BlitState& st = state();
149 if (st.handle !=
nullptr || st.install_attempted)
return;
150 CHECK_NOTNULL(st.done);
151 CHECK_NOTNULL(st.lock);
153 st.install_attempted =
true;
154 async_memcpy_config_t cfg = ASYNC_MEMCPY_DEFAULT_CONFIG();
156 async_memcpy_handle_t handle =
nullptr;
157 if (esp_async_memcpy_install(&cfg, &handle) == ESP_OK) {
167 BlitState& st = state();
168 if (st.handle ==
nullptr || st.lock ==
nullptr)
return;
169 if (xSemaphoreTake(st.lock, 0) != pdTRUE)
return;
170 esp_async_memcpy_uninstall(st.handle);
172 st.install_attempted =
false;
173 xSemaphoreGive(st.lock);
176void blit(
const roo::byte* src_ptr,
size_t src_stride, roo::byte* dst_ptr,
177 size_t dst_stride,
size_t width,
size_t height) {
178 if (src_ptr ==
nullptr || dst_ptr ==
nullptr || width == 0 || height == 0) {
184 size_t dma_row_bytes = width;
185 size_t dma_row_count = height;
186 size_t dma_src_stride = src_stride;
187 size_t dma_dst_stride = dst_stride;
188 if (src_stride == width && dst_stride == width) {
189 dma_row_bytes = width * height;
191 dma_src_stride = dma_row_bytes;
192 dma_dst_stride = dma_row_bytes;
195 if (dma_row_bytes < kDmaThresholdBytes ||
196 !can_dma_copy_rows(src_ptr, dst_ptr, dma_row_bytes, dma_src_stride,
198 copy_sync(src_ptr, src_stride, dst_ptr, dst_stride, width, height);
203 BlitState& st = state();
204 CHECK_EQ(xSemaphoreTake(st.lock, portMAX_DELAY), pdTRUE);
207 dma_copy_rows_and_wait(st, src_ptr, dst_ptr, dma_src_stride,
208 dma_dst_stride, dma_row_bytes, dma_row_count);
210 xSemaphoreGive(st.lock);
213 copy_sync(src_ptr, src_stride, dst_ptr, dst_stride, width, height);
227void blit(
const roo::byte* src_ptr,
size_t src_stride, roo::byte* dst_ptr,
228 size_t dst_stride,
size_t width,
size_t height) {
229 if (src_ptr ==
nullptr || dst_ptr ==
nullptr || width == 0 || height == 0) {
233 if (src_stride == width && dst_stride == width) {
234 std::memcpy(dst_ptr, src_ptr, width * height);
238 const roo::byte* src_row = src_ptr;
239 roo::byte* dst_row = dst_ptr;
240 for (
size_t row = 0; row < height; ++row) {
241 std::memcpy(dst_row, src_row, width);
242 src_row += src_stride;
243 dst_row += dst_stride;
Defines 140 opaque HTML named colors.
void blit(const roo::byte *src_ptr, size_t src_stride, roo::byte *dst_ptr, size_t dst_stride, size_t width, size_t height)