VxKernel 0.6.0-9 : Add line API + circle API

@add
<> include/vhex/display/draw
  | add circle drawing primitive
  | add line drawing primitives
<> src/drivers/screen/r61524
  | add assembly version of the "frame_frag_send" (WIP)
<> src/modules/display/draw
  | add filled circle algorithm
  | add line algorithm

@update
<> include/vhex/display
  | use "dsurface_t" instead of "struct dshader_surface"
  | rename pixel dstack primitives
<> src/drivers/screen/r61524
  | clear proper zone of the surface
  | avoid unused area wiping
  | remove (temporary) surface merging
<> src/module/display/dclear
  | clear proper zone of the surface
  | rename internal primitives
This commit is contained in:
Yann MAGNIN 2022-06-15 20:40:43 +02:00
parent 392925ac3e
commit 221dacae2e
12 changed files with 414 additions and 118 deletions

View File

@ -1 +1,3 @@
#include <vhex/display/draw/circle.h>
#include <vhex/display/draw/pixel.h>
#include <vhex/display/draw/line.h>

View File

@ -18,11 +18,21 @@
Return:
> the "draw ID", which can be used to apply shader afterward */
extern did_t dcircle(int x, int y, size_t size, int mode, dshader_t *list);
//extern did_t dcircle(int x, int y, size_t size, int mode, dshader_t *list);
//TODO: shader
//TODO: doc
//TODO: mode
enum {
/* Horizontal settings: default in dcircle*() is DCIRCLE_LEFT */
DCIRCLE_LEFT = 0x00,
DCIRCLE_CENTER = 0x01,
DCIRCLE_RIGHT = 0x02,
/* Vertical settings: default in dcircle() is DCIRCLE_TOP */
DCIRCLE_TOP = 0x00,
DCIRCLE_MIDDLE = 0x10,
DCIRCLE_BOTTOM = 0x20,
};
/* dcircle_filled() : draw a filled circle */
extern void dcircle_filled(int x, int y, size_t radius, int mode, int color);

View File

@ -0,0 +1,45 @@
#ifndef __VHEX_DISPLAY_DRAW_LINE__
# define __VHEX_DISPLAY_DRAW_LINE__
#include <vhex/defs/types.h>
#include <vhex/display/shader.h>
//---
// User-level API
//---
/* dline(): Render a straight line
This function draws a line using a Bresenham-style algorithm and dline() has
optimizations for horizontal and vertical lines.
dline() is currently not able to clip arbitrary lines without calculating
all the pixels, so drawing a line from (-1e6,0) to (1e6,395) will work but
will be very slow.
@x1 @y1 @x2 @y2 Endpoints of the line (both included).
@color Line color (same values as dpixel() are allowed) */
extern void dline(int x1, int y1, int x2, int y2, int color);
/* dhline() : render an horizontal line */
extern void dhline(int y, int x1, int x2, int color);
/* dvline() : render an vertical line */
extern void dvline(int x, int y1, int y2, int color);
//---
// Kernel-level API
//---
/* dline_render() : real drawing function */
extern void dline_render(dsurface_t *s, int x1, int y1, int x2, int y2, int c);
/* dhline_render() : optimized drawing function for horizontal line */
extern void dhline_render(dsurface_t *s, int y, int x1, int x2, int color);
/* dvline_render() : optimized drawing function for vertical line */
extern void dvline_render(dsurface_t *s, int x, int y1, int y2, int color);
#endif /* __VHEX_DISPLAY_DRAW_LINE__ */

View File

@ -15,10 +15,7 @@ extern void dpixel(int x, int y, int color);
// Kernel-level API
//---
/* dpixel_render_dstack() : dstack-API compatible render */
extern void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg);
/* dpixel_render() : drawing algorithm */
extern void dpixel_render(struct dshader_surface *surface, int x, int y, int c);
extern void dpixel_render(dsurface_t *surface, int x, int y, int c);
#endif /* __VHEX_DISPLAY_DRAW_PIXEL__ */

View File

@ -13,6 +13,7 @@ struct dshader_surface {
int x;
int y;
};
typedef struct dshader_surface dsurface_t;
/* dshader - display shader definition */
struct dshader_call {

View File

@ -0,0 +1,42 @@
#if 0
.text
.global _r61524_frame_frag_send
.align 4
! r61524_frame_frag_send() : send fragment in screen
_r61524_frame_frag_send:
! check number of word to be send
mov.l @(20, r4), r0 ! LS
cmp/eq #220, r0 ! EX (1)
mov.w long_frag, r1 ! LS
bf prepare_loop ! BR (2)
mov.w short_frag, r1 ! LS
nop ! MT (3)
prepare_loop:
mov.l @(4, r4), r0 ! LS (4)
mov.l r61524_interface, r3 ! LS (5)
send_loop:
mov.w @r0+, r2 ! LS
dt r1 ! EX (6)
mov.w r2, @r3 ! LS
bf send_loop ! BR (7)
send_epilogue:
rts
xor r0, r0
long_frag:
.word 3960
short_frag:
.word 1584
r61524_interface:
.long 0xb4000000
#endif

View File

@ -16,11 +16,13 @@ VINLINE void r61524_clear_surface(struct dshader_surface *surface)
// > xram and yram
// > yram and xram
// > restrict / non-restrict
uint32_t * restrict xram = surface->draw;
uint32_t * restrict yram = surface->frag;
for (int i = 0; i < 1980; ++i) {
uint32_t *xram = surface->draw;
int size = (surface->y == 220) ? 792 : 1980;
// uint32_t * restrict yram = surface->frag;
for (int i = 0; i < size; ++i) {
xram[i] = 0x00010001;
yram[i] = 0x00000000;
// yram[i] = 0x00000000;
}
}
@ -68,26 +70,15 @@ int r61524_frame_frag_next(struct dshader_surface *surface)
}
//TODO: wipe only the YRAM
//TODO: move this in dclear() ?
r61524_clear_surface(surface);
// r61524_clear_surface(surface);
return (0);
}
int r61524_frame_frag_send(struct dshader_surface *surface)
VWEAK int r61524_frame_frag_send(struct dshader_surface *surface)
{
uint16_t pixel;
uint16_t * restrict xram = surface->draw;
uint16_t * restrict yram = surface->frag;
int size = (surface->y == 220) ? 1584 : 3960;
/* merge the two fragment */
for (int i = 0; i < size; ++i) {
pixel = xram[i];
if ((pixel & 0x0001) == 0) {
yram[i] = (pixel & 0xffc0) | ((pixel & 0x003e) >> 1);
}
}
//TODO: assembly
//TODO: check cache behaviour:
// > full xram then yram

View File

@ -2,21 +2,35 @@
#include <vhex/display.h>
#include <vhex/display/stack.h>
//---
// kernel-level API
//---
/* dclear_draw() : real drawing algorithm */
void dclear_render(struct dshader_surface *surface, uint32_t color)
{
uint32_t * restrict vram;
uint32_t *vram;
int size = (surface->y == 220) ? 792 : 1980;
vram = surface->frag;
for (int i = 0; i < 2048; ++i)
for (int i = 0; i < size; ++i)
vram[i] = color;
}
void dclear_dstack_render(struct dshader_surface *surface, uint32_t *arg)
//---
// Dstack-level API
//---
/* dclear_dstack() : dstack rwrapper primitive */
void dclear_dstack(struct dshader_surface *surface, uint32_t *arg)
{
dclear_render(surface, arg[0]);
}
//---
// User-level API
//---
/* dclear(): Fill the screen with a single color */
did_t dclear(int color)
{
@ -30,7 +44,7 @@ did_t dclear(int color)
color = color & 0xffff;
copti = (color << 16) | (color << 0);
return dstack_add_action(
&DSTACK_CALL(&dclear_dstack_render, copti),
&DSTACK_CALL(&dclear_dstack, copti),
NULL,
NULL
);

View File

@ -0,0 +1,78 @@
#include <vhex/display/draw/circle.h>
#include <vhex/display/draw/line.h>
#include <vhex/display.h>
//---
// Kernel-level API
//---
/* dcircle_render() : real drawing algorithm */
void dcircle_filled_render(
dsurface_t *surface,
int x, int y,
int radius,
int color
) {
int px;
int py;
int d;
px = 0;
py = radius;
d = 1 - radius;
dhline(y, x - py, x + py, color);
while(py > px)
{
if(d < 0) {
d += (2 * px) + 3;
} else {
d += (2 * (px - py)) + 5;
py--;
dhline_render(surface, y + py + 1, x - px, x + px, color);
dhline_render(surface, y - py - 1, x - px, x + px, color);
}
px++;
if(py >= px) {
dhline_render(surface, y + px, x - py, x + py, color);
dhline_render(surface, y - px, x - py, x + py, color);
}
}
}
//---
// Dstack-level API
//---
/* dcircle_filled_dstack() : dstack wrapper primitive */
void dcircle_filled_dstack(dsurface_t *surface, uint32_t *args)
{
dcircle_filled_render(
surface,
(int)args[0],
(int)args[1],
(size_t)args[2],
(int)args[3]
);
}
//---
// User-level API
//---
/* dcircle_filled() : draw a filled circle */
void dcircle_filled(int x, int y, size_t radius, int mode, int color)
{
if (color == C_NONE) return;
if (mode & DCIRCLE_CENTER) x -= radius;
if (mode & DCIRCLE_RIGHT) x -= radius << 1;
if (mode & DCIRCLE_MIDDLE) y -= radius;
if (mode & DCIRCLE_BOTTOM) y -= radius << 1;
dstack_add_action(
&DSTACK_CALL(&dcircle_filled_dstack, x, y, radius, color),
NULL,
NULL
);
}

View File

@ -1,52 +0,0 @@
#if 0
#include <vhex/display.h>
#include <vhex/defs/utils.h>
#include <vhex/defs/types.h>
/* Vhex vram */
extern uint16_t vhex_vram[];
/* dhline(): Optimized horizontal line */
void dhline(int x1, int x2, int y, int color)
{
/* Order and bounds */
if((uint)y >= 224) return;
if(x1 > x2) swap(x1, x2);
if(x1 >= 396 || x2 < 0) return;
if(x1 < 0) x1 = 0;
if(x2 >= 396) x2 = 395;
int offset = 396 * y;
/* Use longwords to do the copy, but first paint the endpoints to heed
for odd x1 and x2. Checking the parity may be a waste of time. */
vhex_vram[offset + x1] = color;
vhex_vram[offset + x2] = color;
/* Now round to longword boundaries and copy everything in-between with
longwords */
x1 = x1 + (x1 & 1);
x2 = (x2 + 1) & ~1;
uint32_t *start = (void *)(vhex_vram + offset + x1);
uint32_t *end = (void *)(vhex_vram + offset + x2);
uint32_t op = (color << 16) | color;
while(end > start) *--end = op;
}
/* dvline(): Optimized vertical line */
void dvline(int y1, int y2, int x, int color)
{
/* Order and bounds */
if((uint)x >= 396) return;
if(y1 > y2) swap(y1, y2);
if(y1 < 0) y1 = 0;
if(y2 >= 224) y2 = 223;
uint16_t *v = vhex_vram + 396 * y1 + x;
int height = y2 - y1 + 1;
while(height-- > 0) *v = color, v += 396;
}
#endif

View File

@ -1,40 +1,34 @@
#if 0
#include <vhex/display/draw/line.h>
#include <vhex/display/draw/pixel.h>
#include <vhex/display.h>
#include <vhex/defs/utils.h>
//---
// kernel-level API
//---
/* dline(): Bresenham line drawing algorithm
Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall.
Relies on platform-dependent dhline() and dvline() for optimized situations.
@x1 @y1 @x2 @y2 Coordinates of endpoints of line (included)
@color Any color accepted by dpixel() on the platform */
void dline(int x1, int y1, int x2, int y2, int color)
void dline_render(dsurface_t *s, int x1, int y1, int x2, int y2, int color)
{
if(color == C_NONE) return;
int i;
int x = x1;
int y = y1;
int cumul;
int dx = x2 - x1;
int dy = y2 - y1;
int sx = sgn(dx);
int sy = sgn(dy);
/* Possible optimizations */
if(y1 == y2)
{
dhline(x1, x2, y1, color);
return;
}
if(x1 == x2)
{
dvline(y1, y2, x1, color);
return;
}
dx = (dx >= 0 ? dx : -dx);
dy = (dy >= 0 ? dy : -dy);
/* Brensenham line drawing algorithm */
dpixel_render(s, x1, y1, color);
int i, x = x1, y = y1, cumul;
int dx = x2 - x1, dy = y2 - y1;
int sx = sgn(dx), sy = sgn(dy);
dx = (dx >= 0 ? dx : -dx), dy = (dy >= 0 ? dy : -dy);
dpixel(x1, y1, color);
if(dx >= dy)
{
if(dx >= dy) {
/* Start with a non-zero cumul to even the overdue between the
two ends of the line (for more regularity) */
cumul = dx >> 1;
@ -42,22 +36,196 @@ void dline(int x1, int y1, int x2, int y2, int color)
{
x += sx;
cumul += dy;
if(cumul > dx) cumul -= dx, y += sy;
dpixel(x, y, color);
if(cumul > dx) {
cumul -= dx;
y += sy;
}
dpixel_render(s, x, y, color);
}
}
else
{
} else {
cumul = dy >> 1;
for(i = 1; i < dy; i++)
{
y += sy;
cumul += dx;
if(cumul > dy) cumul -= dy, x += sx;
dpixel(x, y, color);
if(cumul > dy) {
cumul -= dy;
x += sx;
}
dpixel_render(s, x, y, color);
}
}
dpixel(x2, y2, color);
dpixel_render(s, x2, y2, color);
}
/* dhline_render() : optimized horizontal line */
void dhline_render(dsurface_t *surface, int y, int x1, int x2, int color)
{
/* Order and bounds */
y -= surface->y;
if(y < 0 || y >= (int)surface->height) return;
if(x1 > x2) swap(x1, x2);
x1 -= surface->x;
x2 -= surface->x;
if(x1 >= (int)surface->width || x2 < 0) return;
if(x2 >= (int)surface->width) x2 = surface->width;
if(x1 < 0) x1 = surface->x;
int offset = surface->width * y;
/* Use longwords to do the copy, but first paint the endpoints to heed
for odd x1 and x2. Checking the parity may be a waste of time. */
uint16_t *vram = surface->frag;
if (color != C_INVERT) {
vram[offset + x1] = color;
vram[offset + x2] = color;
} else {
vram[offset + x1] ^= 0xffff;
vram[offset + x2] ^= 0xffff;
}
/* Now round to longword boundaries and copy everything in-between with
longwords */
x1 = x1 + (x1 & 1);
x2 = (x2 + 1) & ~1;
uint32_t *start = (void *)(vram + offset + x1);
uint32_t *end = (void *)(vram + offset + x2);
if (color != C_INVERT) {
uint32_t op = (color << 16) | color;
while(end > start) {
*--end = op;
}
} else {
while(end > start) {
*--end ^= 0xffff;
}
}
}
/* dvline_render() : optimized drawing function for vertical line */
void dvline_render(dsurface_t *surface, int x, int y1, int y2, int color)
{
/* Order and bounds */
x -= surface->x;
if(x < 0 || x >= (int)surface->width) return;
if(y1 > y2) swap(y1, y2);
y1 -= surface->y;
y2 -= surface->y;
if (y1 >= (int)surface->height || y2 < 0) return;
if(y1 < 0) y1 = 0;
if(y2 >= (int)surface->height) y2 = surface->height;
uint16_t *vram = surface->frag;
uint16_t *v = &vram[(surface->width * y1) + x];
int height = y2 - y1 + 1;
if (color != C_INVERT) {
while(height-- > 0) {
*v = color;
v += surface->width;
}
} else {
while(height-- > 0) {
*v ^= 0xffff;
v += surface->width;
}
}
}
//---
// Dstack-level API
//---
/* dline_dstack() : dstack wrapper line primitive */
void dline_dstack(dsurface_t *surface, uint32_t *args)
{
dline_render(
surface,
(int)args[0],
(int)args[1],
(int)args[2],
(int)args[3],
(int)args[4]
);
}
/* dhline_dstack() : dstack wrapper horizontal line primitive */
void dhline_dstack(dsurface_t *surface, uint32_t *args)
{
dhline_render(
surface,
(int)args[0],
(int)args[1],
(int)args[2],
(int)args[3]
);
}
/* dvline_dstack() : dstack wrapper vertical line primitive */
void dvline_dstack(dsurface_t *surface, uint32_t *args)
{
dvline_render(
surface,
(int)args[0],
(int)args[1],
(int)args[2],
(int)args[3]
);
}
//---
// User-level API
//---
/* dline(): Render a straight line */
void dline(int x1, int y1, int x2, int y2, int color)
{
if(color == C_NONE) return;
/* Possible optimizations */
if(y1 == y2)
{
dstack_add_action(
&DSTACK_CALL(&dhline_dstack, y1, x1, x2, color),
NULL,
NULL
);
return;
}
if(x1 == x2)
{
dstack_add_action(
&DSTACK_CALL(&dvline_dstack, x1, y1, y2, color),
NULL,
NULL
);
return;
}
dstack_add_action(
&DSTACK_CALL(&dline_dstack, x1, y1, x2, y2, color),
NULL,
NULL
);
}
/* dhline() : render an horizontal line */
void dhline(int y, int x1, int x2, int color)
{
dstack_add_action(
&DSTACK_CALL(&dhline_dstack, y, x1, x2, color),
NULL,
NULL
);
}
/* dvline() : render an vertical line */
void dvline(int x, int y1, int y2, int color)
{
dstack_add_action(
&DSTACK_CALL(&dvline_dstack, x, y1, y2, color),
NULL,
NULL
);
}
#endif

View File

@ -7,7 +7,7 @@
//---
/* dpixel_render() : drawing algorithm */
void dpixel_render(struct dshader_surface *surface, int x, int y, int color)
void dpixel_render(dsurface_t *surface, int x, int y, int color)
{
if (color == C_NONE)
return;
@ -36,7 +36,7 @@ void dpixel_render(struct dshader_surface *surface, int x, int y, int color)
}
/* dpixel_render_dstack() : dstack-API compatible render */
void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg)
void dpixel_dstack(struct dshader_surface *surface, uint32_t *arg)
{
dpixel_render(surface, arg[0], arg[1], arg[2]);
}
@ -49,7 +49,7 @@ void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg)
void dpixel(int x, int y, int color)
{
dstack_add_action(
&DSTACK_CALL(&dpixel_render_dstack, x, y, color),
&DSTACK_CALL(&dpixel_dstack, x, y, color),
NULL,
NULL
);