Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "modules/c/tlsf"]
path = modules/c/psram/tlsf
url = git@github.com:espressif/tlsf.git
3 changes: 3 additions & 0 deletions board/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ int mp_hal_is_pin_reserved(int n);
#define MICROPY_HW_ENABLE_PSRAM (1)
#define MICROPY_GC_SPLIT_HEAP (0)

// First 3MB of PSRAM for GC heap, next 4MB for PicoVector, last 1MB for tmp FS
#define MICROPY_HW_PSRAM_MAX_HEAP_SIZE (3 * 1024 * 1024)

// Alias the chip select pin specified by presto.h
#define MICROPY_HW_PSRAM_CS_PIN BW_PSRAM_CS

Expand Down
6 changes: 5 additions & 1 deletion modules/c/picovector/micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ add_library(usermod_picovector INTERFACE)
find_package(PNGDEC CONFIG REQUIRED)
find_package(JPEGDEC CONFIG REQUIRED)

include(modules/c/psram/psram)

list(APPEND SOURCES
${CMAKE_CURRENT_LIST_DIR}/micropython/picovector_bindings.c
${CMAKE_CURRENT_LIST_DIR}/micropython/picovector.cpp
Expand Down Expand Up @@ -46,7 +48,9 @@ target_include_directories(usermod_picovector INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)

target_link_libraries(usermod INTERFACE usermod_picovector pngdec jpegdec)
target_compile_definitions(usermod_picovector INTERFACE PICO=1)

target_link_libraries(usermod INTERFACE usermod_picovector pngdec jpegdec psram)

set_source_files_properties(
${SOURCES}
Expand Down
5 changes: 5 additions & 0 deletions modules/c/picovector/micropython/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern "C" {
#include "py/reader.h"
#include "py/runtime.h"
#include "py/objstr.h"
#include "psram_ops.h"


mp_obj_t image__del__(mp_obj_t self_in) {
Expand All @@ -31,6 +32,10 @@ MPY_BIND_NEW(image, {
self->image = new(m_malloc(sizeof(image_t))) image_t(bufinfo.buf, w, h);
} else {
self->image = new(m_malloc(sizeof(image_t))) image_t(w, h);

// Clear new image to black, fully transparent. This should potentially
// be removed once we have a copy brush or other way to clear alpha.
psram_memset32(self->image->ptr(0, 0), 0, self->image->buffer_size() >> 2);
}

return MP_OBJ_FROM_PTR(self);
Expand Down
2 changes: 1 addition & 1 deletion modules/c/picovector/micropython/shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern "C" {

mp_obj_t shape__del__(mp_obj_t self_in) {
self(self_in, shape_obj_t);
m_del_class(shape_t, self->shape);
PV_DELETE(shape_t, self->shape);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(shape__del___obj, shape__del__);
Expand Down
27 changes: 7 additions & 20 deletions modules/c/picovector/picovector.config.hpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
#include "micropython/mp_tracked_allocator.hpp"
#include "psram_allocator.hpp"

#ifdef __cplusplus
extern "C" {
#endif
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
void *m_malloc(size_t num_bytes);
void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes);
void m_free(void *ptr, size_t num_bytes);
#else
void *m_malloc(size_t num_bytes);
void *m_realloc(void *ptr, size_t new_num_bytes);
void m_free(void *ptr);
#endif
#ifdef __cplusplus
}
#endif
#define PV_STD_ALLOCATOR PSRAMAllocator
#define PV_MALLOC psram_malloc
#define PV_MALLOC0 psram_malloc0
#define PV_FREE psram_free
#define PV_REALLOC psram_realloc

#define PV_STD_ALLOCATOR MPAllocator
#define PV_MALLOC m_malloc
#define PV_FREE m_free
#define PV_REALLOC m_realloc
#define PV_DELETE(cls, ptr) ptr->~cls(); PV_FREE(ptr)
10 changes: 5 additions & 5 deletions modules/c/picovector/picovector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace picovector {
}
}

void build_nodes(path_t *path, rect_t *tb, mat3_t *transform, uint aa) {
void build_nodes(path_t *path, rect_t *tb, mat3_t *transform, uint32_t aa) {
vec2_t offset = tb->tl();
// start with the last point to close the loop, transform it, scale for antialiasing, and offset to tile origin
vec2_t last = path->points[path->points.size() - 1];
Expand All @@ -108,7 +108,7 @@ namespace picovector {
uint8_t alpha_map_x4[5] = {0, 63, 127, 190, 255};
uint8_t alpha_map_x16[17] = {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};

rect_t render_nodes(rect_t *tb, uint aa) {
rect_t render_nodes(rect_t *tb, uint32_t aa) {
int minx = tb->w;
int miny = tb->h;
int maxx = 0;
Expand Down Expand Up @@ -170,7 +170,7 @@ namespace picovector {
if(shape->paths.empty()) return;

// antialias level of target image
uint aa = (uint)target->antialias();
uint32_t aa = (uint32_t)target->antialias();

uint8_t *p_alpha_map = alpha_map_none;
if(aa == 1) p_alpha_map = alpha_map_x4;
Expand Down Expand Up @@ -279,7 +279,7 @@ namespace picovector {



void build_glyph_nodes(glyph_path_t *path, rect_t *tb, mat3_t *transform, uint aa) {
void build_glyph_nodes(glyph_path_t *path, rect_t *tb, mat3_t *transform, uint32_t aa) {
vec2_t offset = tb->tl();
// start with the last point to close the loop, transform it, scale for antialiasing, and offset to tile origin
glyph_path_point_t *p = &path->points[path->point_count - 1];
Expand All @@ -306,7 +306,7 @@ namespace picovector {
if(!glyph->path_count) return;

// antialias level of target image
uint aa = (uint)target->antialias();
uint32_t aa = (uint32_t)target->antialias();


uint8_t *p_alpha_map = alpha_map_none;
Expand Down
21 changes: 21 additions & 0 deletions modules/c/psram/psram.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
add_library(psram INTERFACE)

target_sources(psram INTERFACE
${CMAKE_CURRENT_LIST_DIR}/psram_alloc.c
${CMAKE_CURRENT_LIST_DIR}/psram_ops.c
${CMAKE_CURRENT_LIST_DIR}/tlsf/tlsf.c
)

target_include_directories(psram INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/tlsf
${CMAKE_CURRENT_LIST_DIR}/tlsf/include
)

target_link_libraries(psram INTERFACE pico_platform)

set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/tlsf/tlsf.c
PROPERTIES COMPILE_OPTIONS
"-O2;-fgcse-after-reload;-floop-interchange;-fpeel-loops;-fpredictive-commoning;-fsplit-paths;-ftree-loop-distribute-patterns;-ftree-loop-distribution;-ftree-vectorize;-ftree-partial-pre;-funswitch-loops"
)
70 changes: 70 additions & 0 deletions modules/c/psram/psram_alloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <string.h>
#include "pico.h"

#include "tlsf.h"
#include "psram_ops.h"

#ifdef MICROPY_BUILD_TYPE
#include "py/runtime.h"
#include "py/gc.h"
#endif

// Start 3MB in and use 4MB, leaving 1MB for a RAMFS
#define PSRAM_MALLOC_BASE 0x11300000
#define PSRAM_MALLOC_SIZE 0x00400000

static tlsf_t allocator;

void *psram_malloc(size_t num_bytes) {
if (!allocator) {
allocator = tlsf_create_with_pool((void*)PSRAM_MALLOC_BASE, PSRAM_MALLOC_SIZE, PSRAM_MALLOC_SIZE);
}

void* ptr = tlsf_malloc(allocator, num_bytes);

#ifdef MICROPY_BUILD_TYPE
if (!ptr) {
gc_collect();
ptr = tlsf_malloc(allocator, num_bytes);

if (!ptr) {
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("PSRAM: Failed to allocate %lu bytes!"), num_bytes);
}
}
#endif

return ptr;
}

void *psram_malloc0(size_t num_bytes) {
// Round up to be 32-bit aligned
num_bytes = (num_bytes + 3) & ~3u;
void* ptr = psram_malloc(num_bytes);

if (ptr) psram_memset32(ptr, 0, num_bytes >> 2);

return ptr;
}

void *psram_realloc(void *ptr, size_t new_num_bytes) {
if (ptr < (void*)PSRAM_MALLOC_BASE || ptr >= (void*)(PSRAM_MALLOC_BASE + PSRAM_MALLOC_SIZE)) __breakpoint();
void* new_ptr = tlsf_realloc(allocator, ptr, new_num_bytes);

#ifdef MICROPY_BUILD_TYPE
if (!new_ptr) {
gc_collect();
new_ptr = tlsf_realloc(allocator, ptr, new_num_bytes);

if (!new_ptr) {
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("PSRAM: Failed to allocate %lu bytes!"), new_num_bytes);
}
}
#endif

return new_ptr;
}

void psram_free(void *ptr) {
if (ptr < (void*)PSRAM_MALLOC_BASE || ptr >= (void*)(PSRAM_MALLOC_BASE + PSRAM_MALLOC_SIZE)) __breakpoint();
tlsf_free(allocator, ptr);
}
8 changes: 8 additions & 0 deletions modules/c/psram/psram_alloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <stddef.h>

void *psram_malloc(size_t num_bytes);
void *psram_malloc0(size_t num_bytes);
void *psram_realloc(void *ptr, size_t new_num_bytes);
void psram_free(void *ptr);
38 changes: 38 additions & 0 deletions modules/c/psram/psram_allocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <cstddef>

extern "C" {
#include "psram_alloc.h"
}

template<class T>
struct PSRAMAllocator
{
typedef T value_type;

PSRAMAllocator() = default;

template<class U>
constexpr PSRAMAllocator(const PSRAMAllocator <U>&) noexcept {}

[[nodiscard]] T* allocate(std::size_t n)
{
if (auto p = static_cast<T*>(psram_malloc(n * sizeof(T))))
{
return p;
}
return NULL;
}

void deallocate(T* p, std::size_t n) noexcept
{
psram_free(p);
}
};

template<class T, class U>
bool operator==(const PSRAMAllocator <T>&, const PSRAMAllocator <U>&) { return true; }

template<class T, class U>
bool operator!=(const PSRAMAllocator <T>&, const PSRAMAllocator <U>&) { return false; }
29 changes: 29 additions & 0 deletions modules/c/psram/psram_ops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "psram_ops.h"

#include <string.h>

void psram_memset32(void* ptr, uint32_t val, uint32_t num_words) {
uint32_t* ptr32 = (uint32_t*)ptr;

// Align to 64-bit cache line
if ((uintptr_t)ptr & 4) {
*ptr32++ = val;
--num_words;
}

// Align end to cache line
if (num_words & 1) {
ptr32[--num_words] = val;
}

// Bulk of memset through non-cached alias, invalidating the cache
uint64_t* addr = (uint64_t*)((uint8_t*)ptr32 + 0x4000000);
const uint64_t* end = addr + (num_words >> 1);
uint8_t* cache_clean = (uint8_t*)ptr32 + 0x8000002;
uint64_t val64 = ((uint64_t)val << 32) | val;
while (addr < end) {
*addr++ = val64;
*cache_clean = 0;
cache_clean += 8;
}
}
6 changes: 6 additions & 0 deletions modules/c/psram/psram_ops.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include <stdint.h>

// Fast memset of 32-bit aligned memory with a 32-bit constant for large blocks of PSRAM.
void psram_memset32(void* ptr, uint32_t val, uint32_t num_words);
1 change: 1 addition & 0 deletions modules/c/psram/tlsf
Submodule tlsf added at 19d937
5 changes: 4 additions & 1 deletion modules/common/_boot_fat.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import rp2
import vfs
import ramfs
import machine # noqa: F401


Expand Down Expand Up @@ -28,5 +29,7 @@
except: # noqa: E722
pass

ramfs.mkramfs()

del os, vfs, bdev, bdev_lfs, fat, lfs

del os, vfs, ramfs, bdev, bdev_lfs, fat, lfs
1 change: 1 addition & 0 deletions modules/common/badgeware/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __call__(self, update):
return

display.update()
gc.collect()
badge.poll()

if self.duration is not None and self.ticks >= self.duration:
Expand Down
Loading