ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_gfx_dither.c
Go to the documentation of this file.
1
24
25#include "ra8_gfx_dither.h"
26
27#include <stddef.h>
28#include <stdint.h>
29
30#include "ra8_attributes.h"
31#include "ra8_check.h"
32#include "ra8_err.h"
34#include "ra8_gfx_internal.h"
35#include "ra8_log.h"
36
37/* The runtime index arithmetic assumes the generated mask is exactly one
38 * mask_dim x mask_dim texture; assert it here so a regenerate that changed the
39 * geometry cannot silently mis-index. */
40static_assert(sizeof(s_ra8_gfx_dither_mask) == (size_t)k_ra8_gfx_dither_mask_len,
41 "blue-noise mask must be mask_dim * mask_dim bytes");
43 "toroidal index bitmask must be mask_dim - 1");
44
66static uint32_t internal_mask_index(int32_t x, int32_t y)
67{
68 const uint32_t mx = (uint32_t)x & (uint32_t)k_ra8_gfx_dither_mask_index_mask;
69 const uint32_t my = (uint32_t)y & (uint32_t)k_ra8_gfx_dither_mask_index_mask;
70 return (my * (uint32_t)k_ra8_gfx_dither_mask_dim) + mx;
71}
72
99static uint8_t internal_quantise(uint8_t gray8, uint8_t thr)
100{
101 const uint8_t base = (uint8_t)(gray8 / (uint8_t)k_ra8_gfx_dither_step);
102 const uint8_t rem = (uint8_t)(gray8 - (uint8_t)(base * (uint8_t)k_ra8_gfx_dither_step));
103 uint8_t level = base;
104 if (((uint32_t)thr * (uint32_t)k_ra8_gfx_dither_step) <
105 ((uint32_t)rem * (uint32_t)k_ra8_gfx_dither_byte_levels)) {
106 level = (uint8_t)(level + 1U);
107 }
108 return level;
109}
110
133static uint32_t internal_level_to_color(uint8_t level)
134{
135 const uint32_t g = (uint32_t)level;
136 const uint32_t gray = (g << (uint32_t)k_ra8_gfx_dither_nib_shift) | g;
137 return (gray << (uint32_t)k_ra8_gfx_dither_rgb_r_shift) |
138 (gray << (uint32_t)k_ra8_gfx_dither_rgb_g_shift) | gray;
139}
140
165static void
166internal_pack_tile(const uint8_t* src, int32_t w, int32_t h, int32_t ox, int32_t oy, uint8_t* out)
167{
168 for (int32_t row = 0; row < h; ++row) {
169 for (int32_t col = 0; col < w; ++col) {
170 const uint32_t i = ((uint32_t)row * (uint32_t)w) + (uint32_t)col;
171 const uint8_t level =
172 internal_quantise(src[i], s_ra8_gfx_dither_mask[internal_mask_index(ox + col, oy + row)]);
173 const uint32_t byte_idx = i / (uint32_t)k_ra8_gfx_dither_ppb;
174 if ((i & 1U) == 0U) {
175 out[byte_idx] = (uint8_t)(level << (uint8_t)k_ra8_gfx_dither_nib_shift);
176 } else {
177 out[byte_idx] = (uint8_t)(out[byte_idx] | level);
178 }
179 }
180 }
181}
182
183uint8_t ra8_gfx_dither_gray4_level(uint8_t gray8, int32_t x, int32_t y)
184{
186}
187
189 int32_t w,
190 int32_t h,
191 int32_t origin_x,
192 int32_t origin_y,
193 uint8_t* out,
194 uint32_t out_cap,
195 uint32_t* out_size)
196{
197 static const char* const k_tag = "ra8_gfx_dither";
198 RA8_CHECK_NULL_PTR(src, k_tag, "src");
199 RA8_CHECK_NULL_PTR(out, k_tag, "out");
200 RA8_CHECK_NULL_PTR(out_size, k_tag, "out_size");
201
202 if ((w <= 0) || (h <= 0)) {
203 ra8_log_error(k_tag, "w or h is non-positive");
205 }
206
207 const uint32_t n_pixels = (uint32_t)w * (uint32_t)h;
208 const uint32_t n_bytes = (n_pixels + 1U) / (uint32_t)k_ra8_gfx_dither_ppb;
209 if (out_cap < n_bytes) {
210 ra8_log_error(k_tag, "output buffer too small");
211 return k_ra8_err_no_mem;
212 }
213
214 internal_pack_tile(src, w, h, origin_x, origin_y, out);
215 *out_size = n_bytes;
216 return k_ra8_ok;
217}
218
220ra8_gfx_blit_gray8_dither(const uint8_t* src, int32_t w, int32_t h, int32_t dst_x, int32_t dst_y)
221{
222 if (!g_gfx_text_state.initialized) {
224 }
225 if ((src == nullptr) || (w <= 0) || (h <= 0)) {
227 }
228
229 for (int32_t row = 0; row < h; ++row) {
230 for (int32_t col = 0; col < w; ++col) {
231 const uint8_t level =
232 internal_quantise(src[((size_t)row * (size_t)w) + (size_t)col],
233 s_ra8_gfx_dither_mask[internal_mask_index(dst_x + col, dst_y + row)]);
234 priv_gfx_text_plot(dst_x + col, dst_y + row, internal_level_to_color(level));
235 }
236 }
237 return k_ra8_ok;
238}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_err_t ra8_gfx_blit_gray8_dither(const uint8_t *src, int32_t w, int32_t h, int32_t dst_x, int32_t dst_y)
Blit a gray8 image into the bound framebuffer, blue-noise dithered.
static void internal_pack_tile(const uint8_t *src, int32_t w, int32_t h, int32_t ox, int32_t oy, uint8_t *out)
Dither a gray8 tile to packed 4-bpp nibbles, mask-phased at (ox, oy).
static uint32_t internal_mask_index(int32_t x, int32_t y)
Toroidal blue-noise mask index for absolute panel coordinate (x, y).
static uint8_t internal_quantise(uint8_t gray8, uint8_t thr)
Quantise a gray8 sample to a 4-bit level given its blue-noise threshold.
static uint32_t internal_level_to_color(uint8_t level)
Expand a 4-bit panel level to a 0x00RRGGBB gray colour.
uint8_t ra8_gfx_dither_gray4_level(uint8_t gray8, int32_t x, int32_t y)
Quantise one gray8 sample to a 4-bit panel level via the blue-noise mask.
ra8_err_t ra8_gfx_dither_gray8_to_gray4(const uint8_t *src, int32_t w, int32_t h, int32_t origin_x, int32_t origin_y, uint8_t *out, uint32_t out_cap, uint32_t *out_size)
Dither a gray8 tile to packed 4-bpp nibbles (panel-native), seamlessly.
Void-and-cluster blue-noise dithering: continuous-tone gray8 -> 16-level panel (#477).
@ k_ra8_gfx_dither_mask_len
Mask entry count (mask_dim * mask_dim).
@ k_ra8_gfx_dither_byte_levels
Threshold texture depth (mask range +1).
@ k_ra8_gfx_dither_nib_shift
High-nibble shift (packing + gray8 expand).
@ k_ra8_gfx_dither_ppb
Pixels packed per output byte.
@ k_ra8_gfx_dither_step
Palette step 255/15; also the 4->8 replicate.
@ k_ra8_gfx_dither_mask_index_mask
Toroidal index bitmask (mask_dim - 1).
@ k_ra8_gfx_dither_mask_dim
Blue-noise mask edge (power of two).
@ k_ra8_gfx_dither_rgb_r_shift
Red shift of the 0x00RRGGBB gray expand.
@ k_ra8_gfx_dither_rgb_g_shift
Green shift of the 0x00RRGGBB gray expand.
Void-and-cluster blue-noise threshold mask for the e-ink dither (#477).
static const uint8_t s_ra8_gfx_dither_mask[]
64x64 row-major blue-noise threshold texture (4096 bytes).
Module-private declarations shared across the ra8_gfx software rasteriser TUs.
ra8_gfx_state_t g_gfx_text_state
Single module-wide framebuffer binding shared by every ra8_gfx TU.
void priv_gfx_text_plot(int32_t x, int32_t y, uint32_t color)
Plot a single pixel with bounds checking against the active clip.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335