summaryrefslogtreecommitdiff
path: root/src/til_fb.h
blob: a9636e497729e5160aad5b28eb8ad2d102e0861f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#ifndef _TIL_FB_H
#define _TIL_FB_H

#include <assert.h>
#include <stdint.h>
#include <string.h>

#include "til_settings.h"
#include "til_setup.h"
#include "til_util.h"

typedef struct til_fb_fragment_t til_fb_fragment_t;

#define TIL_FB_DRAW_FLAG_TEXTURABLE	0x1

/* All renderers should target fb_fragment_t, which may or may not represent
 * a full-screen mmap.  Helpers are provided for subdividing fragments for
 * concurrent renderers.
 */
typedef struct til_fb_fragment_t {
	til_fb_fragment_t	*texture;	/* optional source texture when drawing to this fragment */
	uint32_t		*buf;		/* pointer to the first pixel in the fragment */
	unsigned		x, y;		/* absolute coordinates of the upper left corner of this fragment */
	unsigned		width, height;	/* width and height of this fragment */
	unsigned		frame_width;	/* width of the frame this fragment is part of */
	unsigned		frame_height;	/* height of the frame this fragment is part of */
	unsigned		stride;		/* number of 32-bit words from the end of one row to the start of the next */
	unsigned		pitch;		/* number of 32-bit words separating y from y + 1, including any padding */
	unsigned		number;		/* this fragment's number as produced by fragmenting */
	unsigned		cleared:1;	/* if this fragment has been cleared since last flip */
} til_fb_fragment_t;

/* This is a page handle object for page flip submission/life-cycle.
 * Outside of fb_page_get()/fb_page_put(), you're going to be interested in
 * fb_fragment_t.  The fragment included here describes the whole page,
 * it may be divided via fb_fragment_divide().
 */
typedef struct til_fb_page_t {
	til_fb_fragment_t	fragment;
} til_fb_page_t;

typedef struct til_fb_t til_fb_t;

/* Supply this struct to fb_new() with the appropriate context */
typedef struct til_fb_ops_t {
	int	(*setup)(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup);
	int	(*init)(const til_settings_t *settings, void **res_context);
	void	(*shutdown)(til_fb_t *fb, void *context);
	int	(*acquire)(til_fb_t *fb, void *context, void *page);
	void	(*release)(til_fb_t *fb, void *context);
	void *	(*page_alloc)(til_fb_t *fb, void *context, til_fb_page_t *res_page);
	int	(*page_free)(til_fb_t *fb, void *context, void *page);
	int	(*page_flip)(til_fb_t *fb, void *context, void *page);
} til_fb_ops_t;

til_fb_page_t * til_fb_page_get(til_fb_t *fb);
void til_fb_page_put(til_fb_t *fb, til_fb_page_t *page);
til_fb_t * til_fb_free(til_fb_t *fb);
void til_fb_get_put_pages_count(til_fb_t *fb, unsigned *count);
int til_fb_new(const til_fb_ops_t *ops, til_settings_t *settings, int n_pages, til_fb_t **res_fb);
void til_fb_rebuild(til_fb_t *fb);
void * til_fb_context(til_fb_t *fb);
int til_fb_flip(til_fb_t *fb);
void til_fb_fragment_divide(til_fb_fragment_t *fragment, unsigned n_fragments, til_fb_fragment_t fragments[]);
int til_fb_fragment_slice_single(const til_fb_fragment_t *fragment, unsigned n_fragments, unsigned num, til_fb_fragment_t *res_fragment);
int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile_size, unsigned num, til_fb_fragment_t *res_fragment);


/* checks if a coordinate is contained within a fragment */
static inline int til_fb_fragment_contains(til_fb_fragment_t *fragment, int x, int y)
{
	if (x < fragment->x || x >= fragment->x + fragment->width ||
	    y < fragment->y || y >= fragment->y + fragment->height)
		return 0;

	return 1;
}


/* gets a pixel from the fragment, no bounds checking is performed. */
static inline uint32_t til_fb_fragment_get_pixel_unchecked(til_fb_fragment_t *fragment, int x, int y)
{
	return fragment->buf[(y - fragment->y) * fragment->pitch + x - fragment->x];
}


/* puts a pixel into the fragment, no bounds checking is performed. */
static inline void til_fb_fragment_put_pixel_unchecked(til_fb_fragment_t *fragment, uint32_t flags, int x, int y, uint32_t pixel)
{
	if (fragment->texture && (flags & TIL_FB_DRAW_FLAG_TEXTURABLE))
		pixel = til_fb_fragment_get_pixel_unchecked(fragment->texture, x, y);

	fragment->buf[(y - fragment->y) * fragment->pitch + x - fragment->x] = pixel;
}


/* puts a pixel into the fragment, bounds checking is performed with a draw performed return status */
static inline int til_fb_fragment_put_pixel_checked(til_fb_fragment_t *fragment, uint32_t flags, int x, int y, uint32_t pixel)
{
	if (!til_fb_fragment_contains(fragment, x, y))
		return 0;

	til_fb_fragment_put_pixel_unchecked(fragment, flags, x, y, pixel);

	return 1;
}


/* copy a fragment, x,y,width,height are absolute coordinates within the frames, and will be clipped to the overlapping fragment areas */
static inline void til_fb_fragment_copy(til_fb_fragment_t *dest, uint32_t flags, int x, int y, int width, int height, til_fb_fragment_t *src)
{
	int	X = MAX(dest->x, src->x);
	int	Y = MAX(dest->y, src->y);
	int	W = MIN(dest->x + dest->width, src->x + src->width) - X;
	int	H = MIN(dest->y + dest->height, src->y + src->height) - Y;

	assert(W >= 0 && H >= 0);

	/* XXX FIXME TODO */
	/* XXX FIXME TODO */
	/* XXX FIXME TODO */
	/* this is PoC fast and nasty code, optimize this to at least bulk copy rows of pixels */
	/* XXX FIXME TODO */
	/* XXX FIXME TODO */
	/* XXX FIXME TODO */
	for (int v = 0; v < H; v++) {
		for (int u = 0; u < W; u++)
			til_fb_fragment_put_pixel_unchecked(dest, flags, X + u, Y + v, til_fb_fragment_get_pixel_unchecked(src, X + u, Y + v));
	}
}


static inline void _til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t pixel)
{
	uint32_t	*buf = fragment->buf;

	/* TODO: there should be a fast-path for non-divided fragments where there's no stride to skip */
	for (int y = 0; y < fragment->height; y++, buf += fragment->pitch) {
		/* TODO: this should use something memset-like for perf */
		for (int x = 0; x < fragment->width; x++)
			buf[x] = pixel;
	}
}


/* fill a fragment with an arbitrary pixel */
static inline void til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t flags, uint32_t pixel)
{
	if (!(fragment->texture && (flags & TIL_FB_DRAW_FLAG_TEXTURABLE)))
		return _til_fb_fragment_fill(fragment, pixel);

	/* when a texture is present, pixel is ignored and instead sourced from fragment->texture->buf[y*pitch+x] */
	til_fb_fragment_copy(fragment, flags, fragment->x, fragment->y, fragment->width, fragment->height, fragment->texture);
}


/* clear a fragment */
static inline void til_fb_fragment_clear(til_fb_fragment_t *fragment)
{
	if (fragment->cleared)
		return;

	_til_fb_fragment_fill(fragment, 0);

	fragment->cleared = 1;
}

#endif
© All Rights Reserved