/contrib/sdk/samples/freetype/txview/pxdraw/context.c |
---|
0,0 → 1,339 |
#include <stdlib.h> |
#include <kos32sys.h> |
#include "pxdraw.h" |
#include "internal.h" |
ctx_t* create_context(int x, int y, int width, int height) |
{ |
ctx_t *ctx; |
ctx = malloc(sizeof(ctx_t)); |
if (ctx == NULL) |
goto err_0; |
ctx->pitch = ALIGN(width * sizeof(color_t), 16); |
ctx->size = ALIGN(ctx->pitch * height, 4096); |
ctx->buffer = user_alloc(ctx->size+4096); |
if (ctx->buffer == NULL) |
goto err_1; |
ctx->x = x; |
ctx->y = y; |
ctx->width = width; |
ctx->height = height; |
ctx->rc.l = 0; |
ctx->rc.t = 0; |
ctx->rc.r = width; |
ctx->rc.b = height; |
ctx->rcu.l = 0; |
ctx->rcu.t = 0; |
ctx->rcu.r = ctx->width; |
ctx->rcu.b = ctx->height; |
ctx->dirty = 1; |
__builtin_cpu_init (); |
if (__builtin_cpu_supports ("sse2")) |
ctx->px_rect_simd = px_rect_xmm; |
else if (__builtin_cpu_supports ("mmx")) |
ctx->px_rect_simd = px_rect_mmx; |
else |
ctx->px_rect_simd = px_rect_alu; |
if (__builtin_cpu_supports ("sse2")) |
ctx->px_glyph = px_glyph_sse; |
else |
ctx->px_glyph = px_glyph_alu; |
return ctx; |
err_1: |
free(ctx); |
err_0: |
return NULL; |
}; |
int resize_context(ctx_t *ctx, int width, int height) |
{ |
int size; |
int pitch; |
pitch = ALIGN(width * sizeof(color_t), 16); |
size = ALIGN(pitch * height, 4096); |
if (size > ctx->size) |
{ |
ctx->buffer = user_realloc(ctx->buffer, size); /* grow buffer */ |
if (ctx->buffer == NULL) |
return -1; |
ctx->size = size; |
} |
else if (size < ctx->size) |
user_unmap(ctx->buffer, size, ctx->size - size); /* unmap unused pages */ |
ctx->width = width; |
ctx->height = height; |
ctx->pitch = pitch; |
ctx->rc.l = 0; |
ctx->rc.t = 0; |
ctx->rc.r = width; |
ctx->rc.b = height; |
ctx->rcu.l = ctx->rcu.t = 0; |
ctx->rcu.r = ctx->rcu.b = 0; |
return 0; |
}; |
void clear_context(ctx_t *ctx, color_t color) |
{ |
size_t size; |
size = ctx->pitch * ctx->height; |
if (size >= 1024) |
ctx->px_rect_simd(ctx->buffer, ctx->pitch, ctx->width, ctx->height, color); |
else |
px_rect_alu(ctx->buffer, ctx->pitch, ctx->width, ctx->height, color); |
ctx->rcu.l = 0; |
ctx->rcu.t = 0; |
ctx->rcu.r = ctx->width; |
ctx->rcu.b = ctx->height; |
ctx->dirty = 1; |
}; |
void show_context(ctx_t *ctx) |
{ |
struct blit_call bc; |
int ret; |
bc.dstx = ctx->x; |
bc.dsty = ctx->y; |
bc.w = ctx->width; |
bc.h = ctx->height; |
bc.srcx = 0; |
bc.srcy = 0; |
bc.srcw = ctx->width; |
bc.srch = ctx->height; |
bc.stride = ctx->pitch; |
bc.bitmap = ctx->buffer; |
__asm__ __volatile__( |
"int $0x40":"=a"(ret):"a"(73), "b"(0x00), |
"c"(&bc):"memory"); |
ctx->dirty = 0; |
}; |
void scroll_context(ctx_t *ctx, int dst_y, int src_y, int rows) |
{ |
char *dst; |
char *src; |
dst = ctx->buffer + dst_y * ctx->pitch; |
src = ctx->buffer + src_y * ctx->pitch; |
__builtin_memmove(dst, src, rows * ctx->pitch); |
ctx->dirty = 1; |
} |
static int clip_rect(const rect_t *clip, rect_t *rc) |
{ |
if (rc->l > rc->r) |
return 1; |
if (rc->t > rc->b) |
return 1; |
if (rc->l < clip->l) |
rc->l = clip->l; |
else if (rc->l >= clip->r) |
return 1; |
if (rc->t < clip->t) |
rc->t = clip->t; |
else if (rc->t >= clip->b) |
return 1; |
if (rc->r < clip->l) |
return 1; |
else if (rc->r > clip->r) |
rc->r = clip->r; |
if (rc->b < clip->t) |
return 1; |
else if (rc->b > clip->b) |
rc->b = clip->b; |
if ((rc->l == rc->r) || |
(rc->t == rc->b)) |
return 1; |
return 0; |
} |
int px_hline(ctx_t*ctx, int x, int y, int width, color_t color) |
{ |
char *dst_addr; |
int xr = x + width; |
if(y < ctx->rc.t) |
return 0; |
else if(y >= ctx->rc.b) |
return 0; |
if(x < ctx->rc.l) |
x = ctx->rc.l; |
else if(x >= ctx->rc.r) |
return 0; |
if(xr <= ctx->rc.l) |
return 0; |
else if(xr > ctx->rc.r) |
xr = ctx->rc.r; |
dst_addr = ctx->buffer; |
dst_addr+= ctx->pitch * y + x * sizeof(color_t); |
__asm__ __volatile__ |
(" cld; rep stosl\n\t" |
:: "D" (dst_addr),"c" (xr-x), "a" (color) |
: "flags"); |
}; |
void px_vline(ctx_t*ctx, int x, int y, int height, color_t color) |
{ |
char *dst_addr; |
int yb = y + height; |
if(x < ctx->rc.l) |
return; |
else if(x >= ctx->rc.r) |
return; |
if(y < ctx->rc.t) |
y = ctx->rc.t; |
else if(y >= ctx->rc.b) |
return; |
if(yb <= ctx->rc.t) |
return; |
else if(yb > ctx->rc.b) |
yb = ctx->rc.b; |
dst_addr = ctx->buffer; |
dst_addr+= ctx->pitch * y + x * sizeof(color_t); |
while(y < yb) |
{ |
color_t *t = (color_t*)dst_addr; |
*t = color; |
y++; |
dst_addr+= ctx->pitch; |
}; |
}; |
static int do_fill_rect(ctx_t *ctx, rect_t *rc, color_t color) |
{ |
if (!clip_rect(&ctx->rc, rc)) |
{ |
int w, h; |
char *dst_addr; |
w = rc->r - rc->l; |
h = rc->b - rc->t; |
dst_addr = ctx->buffer; |
dst_addr += ctx->pitch * rc->t + rc->l * sizeof(color_t); |
if (w * h >= 256) |
ctx->px_rect_simd(dst_addr, ctx->pitch, w, h, color); |
else |
px_rect_alu(dst_addr, ctx->pitch, w, h, color); |
return 1; |
}; |
return 0; |
}; |
void px_fill_rect(ctx_t *ctx, const rect_t *src, color_t color) |
{ |
rect_t rc = *src; |
int update; |
update = do_fill_rect(ctx, &rc, color); |
if(update) |
{ |
if (rc.l < ctx->rcu.l) |
ctx->rcu.l = rc.l; |
if (rc.t < ctx->rcu.t) |
ctx->rcu.t = rc.t; |
if (rc.r > ctx->rcu.r) |
ctx->rcu.r = rc.r; |
if (rc.b > ctx->rcu.b) |
ctx->rcu.b = rc.b; |
ctx->dirty = 1; |
}; |
} |
void px_fill_region(ctx_t *ctx, const rgn_t *rgn, color_t color) |
{ |
int update = 0; |
for (int i = 0; i < rgn->num_rects; i++) |
{ |
rect_t rc = rgn->rects[i]; |
update |= do_fill_rect(ctx, &rc, color); |
} |
if (update) |
{ |
if (rgn->extents.l < ctx->rcu.l) |
ctx->rcu.l = rgn->extents.l; |
if (rgn->extents.t < ctx->rcu.t) |
ctx->rcu.t = rgn->extents.t; |
if (rgn->extents.r > ctx->rcu.r) |
ctx->rcu.r = rgn->extents.r; |
if (rgn->extents.b > ctx->rcu.b) |
ctx->rcu.b = rgn->extents.b; |
ctx->dirty = 1; |
}; |
} |
void px_draw_glyph(ctx_t *ctx, const void *buffer, int pitch, const rect_t *rc, color_t color) |
{ |
rect_t rc_dst = *rc; |
int srcx, srcy; |
if (!clip_rect(&ctx->rc, &rc_dst)) |
{ |
int width; |
int height; |
unsigned char *dst = ctx->buffer; |
const unsigned char *src = buffer; |
width = rc_dst.r - rc_dst.l; |
height = rc_dst.b - rc_dst.t; |
srcx = rc_dst.l - rc->l; |
srcy = rc_dst.t - rc->t; |
dst += ctx->pitch * rc_dst.t + rc_dst.l * sizeof(color_t); |
src += pitch * srcy + srcx; |
ctx->px_glyph(dst, ctx->pitch, src, pitch, width, height, color); |
if (rc_dst.l < ctx->rcu.l) |
ctx->rcu.l = rc_dst.l; |
if (rc_dst.t < ctx->rcu.t) |
ctx->rcu.t = rc_dst.t; |
if (rc_dst.r > ctx->rcu.r) |
ctx->rcu.r = rc_dst.r; |
if (rc_dst.b > ctx->rcu.b) |
ctx->rcu.b = rc_dst.b; |
ctx->dirty = 1; |
}; |
}; |
/contrib/sdk/samples/freetype/txview/pxdraw/dutils.c |
---|
0,0 → 1,226 |
#include <mmintrin.h> |
#include <xmmintrin.h> |
#include <emmintrin.h> |
typedef unsigned int color_t; |
void px_rect_alu(void *dst_addr, int pitch, int w, int h, color_t src_color) |
{ |
while (h--) |
{ |
char *tmp = dst_addr; |
dst_addr = tmp + pitch; |
__asm__ __volatile__( |
"cld; rep stosl\n\t" |
:: "D"(tmp), "a"(src_color), "c"(w) |
: "flags"); |
}; |
}; |
void px_rect_mmx(void *dst_addr, int pitch, int w, int h, color_t src_color) |
{ |
register __m64 color; |
color = _mm_cvtsi32_si64(src_color); |
color = _mm_unpacklo_pi32(color, color); |
while (h--) |
{ |
char *tmp = dst_addr; |
char *end = tmp + w * sizeof(color_t); |
dst_addr = tmp + pitch; |
int t = (int)tmp; |
if (t & 4) |
{ |
*(color_t*)tmp = src_color; |
tmp += 4; |
}; |
while (tmp + 64 <= end) |
{ |
__m64 *_tmp = (__m64*)tmp; |
_tmp[0] = color; |
_tmp[1] = color; |
_tmp[2] = color; |
_tmp[3] = color; |
_tmp[4] = color; |
_tmp[5] = color; |
_tmp[6] = color; |
_tmp[7] = color; |
tmp += 64; |
}; |
if (tmp + 32 <= end) |
{ |
__m64 *_tmp = (__m64*)tmp; |
_tmp[0] = color; |
_tmp[1] = color; |
_tmp[2] = color; |
_tmp[3] = color; |
tmp += 32; |
}; |
if (tmp + 16 <= end) |
{ |
__m64 *_tmp = (__m64*)tmp; |
_tmp[0] = color; |
_tmp[1] = color; |
tmp += 16; |
}; |
if (tmp + 8 <= end) |
{ |
__m64 *_tmp = (__m64*)tmp; |
_tmp[0] = color; |
tmp += 8; |
}; |
if (tmp < end) |
*(color_t*)tmp = src_color; |
}; |
_mm_empty(); |
}; |
void px_rect_xmm(void *dst_addr, int pitch, int w, int h, color_t dst_color) |
{ |
__m128i color; |
color = _mm_set_epi32(dst_color, dst_color, dst_color, dst_color); |
while (h--) |
{ |
char *tmp = dst_addr; |
char *end = tmp + w * sizeof(color_t); |
dst_addr = tmp + pitch; |
if ((int)tmp & 4) |
{ |
*(color_t*)tmp = dst_color; |
tmp += 4; |
}; |
if ((int)tmp & 8) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_storel_epi64(_tmp, color); |
tmp += 8; |
}; |
while (tmp + 128 <= end) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_store_si128(&_tmp[0], color); |
_mm_store_si128(&_tmp[1], color); |
_mm_store_si128(&_tmp[2], color); |
_mm_store_si128(&_tmp[3], color); |
_mm_store_si128(&_tmp[4], color); |
_mm_store_si128(&_tmp[5], color); |
_mm_store_si128(&_tmp[6], color); |
_mm_store_si128(&_tmp[7], color); |
tmp += 128; |
}; |
if (tmp + 64 <= end) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_store_si128(&_tmp[0], color); |
_mm_store_si128(&_tmp[1], color); |
_mm_store_si128(&_tmp[2], color); |
_mm_store_si128(&_tmp[3], color); |
tmp += 64; |
}; |
if (tmp + 32 <= end) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_store_si128(&_tmp[0], color); |
_mm_store_si128(&_tmp[1], color); |
tmp += 32; |
}; |
if (tmp + 16 <= end) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_store_si128(&_tmp[0], color); |
tmp += 16; |
}; |
if (tmp + 8 <= end) |
{ |
__m128i *_tmp = (__m128i*)tmp; |
_mm_storel_epi64(_tmp, color); |
tmp += 8; |
}; |
if (tmp < end) |
*(color_t*)tmp = dst_color; |
}; |
} |
void px_glyph_alu(void *dst_addr, int dst_pitch,const void *src_addr, int src_pitch, |
int width, int height, color_t src_color) |
{ |
while (height-- > 0) |
{ |
int w = width; |
const unsigned char *src = src_addr; |
color_t *dst = dst_addr; |
dst_addr = (char*)dst + dst_pitch; |
src_addr = src + src_pitch; |
while (w-- > 0) |
{ |
unsigned char a = *src++; |
color_t dst_color = *(color_t*)dst; |
unsigned int rb = dst_color & 0xff00ff; |
unsigned int g = dst_color & 0x00ff00; |
rb += ((src_color & 0xff00ff) - rb) * a >> 8; |
g += ((src_color & 0x00ff00) - g) * a >> 8; |
*dst++ = (src_color & 0xFF000000) | (rb & 0xff00ff) | (g & 0xff00); |
}; |
} |
} |
__m64 m_4x0080 = { 0x00800080, 0x00800080 }; |
__m64 m_4x0101 = { 0x01010101, 0x01010101 }; |
__m64 m_4x00FF = { 0x00FF00FF, 0x00FF00FF }; |
__m64 m_zero = { 0 }; |
void px_glyph_sse(void *dst_addr, int dst_pitch, const void *src_addr, int src_pitch, |
int width, int height, color_t src_color) |
{ |
static __m64 m_4x0080 = { 0x00800080, 0x00800080 }; |
static __m64 m_4x0101 = { 0x01010101, 0x01010101 }; |
static __m64 m_4x00FF = { 0x00FF00FF, 0x00FF00FF }; |
static __m64 m_zero = { 0 }; |
__m64 color; |
color = _mm_cvtsi32_si64(src_color); |
color = _m_punpcklbw(color, m_zero); |
while (height-- > 0) |
{ |
int w = width; |
const unsigned char *tmpsrc = src_addr; |
color_t *tmpdst = dst_addr; |
dst_addr = (char*)tmpdst + dst_pitch; |
src_addr = tmpsrc + src_pitch; |
while (w-- > 0) |
{ |
__m64 m_alpha, m_1_minus_alpha; |
__m64 src_alpha, dst_color; |
unsigned int alpha = *tmpsrc++; |
m_alpha = _mm_cvtsi32_si64((alpha << 16) | alpha); |
dst_color = _mm_cvtsi32_si64(*(int*)tmpdst); |
m_alpha = _mm_unpacklo_pi32(m_alpha, m_alpha); |
m_1_minus_alpha = _m_psubb(m_4x00FF, m_alpha); |
dst_color = _m_punpcklbw(dst_color, m_zero); |
src_alpha = _m_pmullw(color, m_alpha); |
dst_color = _m_pmullw(dst_color, m_1_minus_alpha); |
dst_color = _m_paddw(src_alpha, dst_color); |
dst_color = _m_paddw(dst_color, m_4x0080); |
dst_color = _mm_mulhi_pu16(dst_color, m_4x0101); |
dst_color = _mm_packs_pu16(dst_color, dst_color); |
*tmpdst++ = _mm_cvtsi64_si32(dst_color); |
}; |
} |
_mm_empty(); |
}; |
/contrib/sdk/samples/freetype/txview/pxdraw/internal.h |
---|
0,0 → 1,31 |
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) |
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) |
struct context |
{ |
int x; |
int y; |
int width; |
int height; |
rect_t rc; |
rect_t rcu; |
void *buffer; |
size_t pitch; |
size_t size; |
int dirty; |
void (*px_rect_simd)(void *dst_addr, int pitch, int w, int h, color_t dst_color); |
void (*px_glyph)(void *dst_addr, int dst_pitch, const void *src_addr, int src_pitch, |
int width, int height, color_t src_color); |
}; |
void px_rect_alu(void *dst_addr, int pitch, int w, int h, color_t src_color); |
void px_rect_mmx(void *dst_addr, int pitch, int w, int h, color_t src_color); |
void px_rect_xmm(void *dst_addr, int pitch, int w, int h, color_t dst_color); |
void px_glyph_alu(void *dst_addr, int dst_pitch,const void *src_addr, |
int src_pitch, int width, int height, color_t src_color); |
void px_glyph_sse(void *dst_addr, int dst_pitch, const void *src_addr, |
int src_pitch, int width, int height, color_t src_color); |
/contrib/sdk/samples/freetype/txview/pxdraw/pxdraw.h |
---|
0,0 → 1,46 |
#ifndef __PXDRAW_H__ |
#define __PXDRAW_H__ |
#include <stdint.h> |
#if defined __cplusplus |
extern "C" { |
#endif |
typedef unsigned int color_t; |
typedef struct context ctx_t; |
typedef struct |
{ |
int l; |
int t; |
int r; |
int b; |
}rect_t; |
typedef struct |
{ |
int num_rects; |
rect_t *rects; |
rect_t extents; |
}rgn_t; |
rgn_t* create_round_rect_rgn(int left, int top, int right, int bottom, |
int ellipse_width, int ellipse_height); |
void destroy_region(rgn_t *rgn); |
ctx_t* create_context(int x, int y, int width, int height); |
int resize_context(ctx_t *ctx, int width, int height); |
void clear_context(ctx_t *ctx, color_t color); |
void show_context(ctx_t *ctx); |
void scroll_context(ctx_t *ctx, int dst_y, int src_y, int rows); |
int px_hline(ctx_t*ctx, int x, int y, int width, color_t color); |
void px_vline(ctx_t*ctx, int x, int y, int height, color_t color); |
void px_fill_rect(ctx_t *ctx, const rect_t *src, color_t color); |
void px_draw_glyph(ctx_t *ctx, const void *buffer, int pitch, const rect_t *rc, color_t color); |
#if defined __cplusplus |
} |
#endif |
#endif /* __PXDRAW_H__ */ |
/contrib/sdk/samples/freetype/txview/pxdraw/region.c |
---|
0,0 → 1,93 |
#include <stdlib.h> |
#include "pxdraw.h" |
#define max(a,b) (((a) > (b)) ? (a) : (b)) |
#define min(a,b) (((a) < (b)) ? (a) : (b)) |
rgn_t* create_round_rect_rgn(int left, int top, int right, int bottom, |
int ellipse_width, int ellipse_height) |
{ |
rgn_t *obj; |
rect_t *rects; |
int a, b, i, x, y; |
int64_t asq, bsq, dx, dy, err; |
right--; |
bottom--; |
ellipse_width = min(right - left, abs(ellipse_width)); |
ellipse_height = min(bottom - top, abs(ellipse_height)); |
obj = malloc(sizeof(rgn_t)); |
if (obj == NULL) |
return NULL; |
obj->num_rects = ellipse_height; |
obj->extents.l = left; |
obj->extents.t = top; |
obj->extents.r = right; |
obj->extents.b = bottom; |
obj->rects = rects = malloc(obj->num_rects * sizeof(rect_t)); |
if (rects == NULL) |
{ |
free(obj); |
return NULL; |
}; |
/* based on an algorithm by Alois Zingl */ |
a = ellipse_width - 1; |
b = ellipse_height - 1; |
asq = (int64_t)8 * a * a; |
bsq = (int64_t)8 * b * b; |
dx = (int64_t)4 * b * b * (1 - a); |
dy = (int64_t)4 * a * a * (1 + (b % 2)); |
err = dx + dy + a * a * (b % 2); |
x = 0; |
y = ellipse_height / 2; |
rects[y].l = left; |
rects[y].r = right; |
while (x <= ellipse_width / 2) |
{ |
int64_t e2 = 2 * err; |
if (e2 >= dx) |
{ |
x++; |
err += dx += bsq; |
} |
if (e2 <= dy) |
{ |
y++; |
err += dy += asq; |
rects[y].l = left + x; |
rects[y].r = right - x; |
} |
} |
for (i = 0; i < ellipse_height / 2; i++) |
{ |
rects[i].l = rects[b - i].l; |
rects[i].r = rects[b - i].r; |
rects[i].t = top + i; |
rects[i].b = rects[i].t + 1; |
} |
for (; i < ellipse_height; i++) |
{ |
rects[i].t = bottom - ellipse_height + i; |
rects[i].b = rects[i].t + 1; |
} |
rects[ellipse_height / 2].t = top + ellipse_height / 2; /* extend to top of rectangle */ |
return obj; |
}; |
void destroy_region(rgn_t *rgn) |
{ |
free(rgn->rects); |
free(rgn); |
}; |