blit
Loading...
Searching...
No Matches
rop2.c
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025, Roy Ratcliffe, Northumberland, United Kingdom
3 * SPDX-License-Identifier: MIT
4 */
15#include <blit/phase_align.h>
16#include <blit/rop2.h>
17
21#define S (fetch)
22
26#define D (store)
27
36 blit_scanline_t store);
37
69#define ROP_REV_POLISH(revPolish, x) \
70 static blit_scanline_t rop##revPolish(blit_scanline_t fetch, \
71 blit_scanline_t store); \
72 blit_scanline_t rop##revPolish(blit_scanline_t fetch, \
73 blit_scanline_t store) { \
74 return x; \
75 }
76
81
82/*
83 * Note that the macro ends with a semicolon. This is intentional to allow for
84 * better formatting, even though semantically it is not required. Without the
85 * trailing semicolon, the code would compile correctly, but automated
86 * formatting tools will indent the subsequent code incorrectly.
87 */
88
92ROP_REV_POLISH(DSon, ~(D | S));
93
97ROP_REV_POLISH(DSna, D & ~S);
98
103
108
113
118
122ROP_REV_POLISH(DSan, ~(D &S));
123
128
132ROP_REV_POLISH(DSxn, ~(D ^ S));
133
138
143
148
153
158
163
170static blit_rop2_func_t rop2_func[] = {&rop0, &ropDSon, &ropDSna, &ropSn,
171 &ropSDna, &ropDn, &ropDSx, &ropDSan,
172 &ropDSa, &ropDSxn, &ropD, &ropDSno,
173 &ropS, &ropSDno, &ropDSo, &rop1};
174
182static void fetch_logic_mask_store(struct blit_phase_align *align,
183 enum blit_rop2 rop2, blit_scanline_t mask,
184 blit_scanline_t *store);
185
192static void fetch_logic_store(struct blit_phase_align *align,
193 enum blit_rop2 rop2, blit_scanline_t *store);
194
195bool blit_rgn1_rop2(struct blit_scan *result, struct blit_rgn1 *x,
196 struct blit_rgn1 *y, const struct blit_scan *source,
197 enum blit_rop2 rop2) {
198 /*
199 * Normalise, slip, and clip the x region. The regions are first normalised to
200 * ensure that their extents are non-negative. Then, they are slipped to
201 * ensure that their origins are non-negative. Finally, they are clipped to
202 * ensure that they fit within the bounds of the destination and source scan
203 * structures.
204 */
205 blit_rgn1_norm(x);
206 if (!blit_rgn1_slip(x) || !blit_rgn1_clip(x, result->width - x->origin) ||
207 !blit_rgn1_clip(x, source->width - x->origin_source))
208 return false;
209
210 /*
211 * Normalise, slip, and clip the y region.
212 */
213 blit_rgn1_norm(y);
214 if (!blit_rgn1_slip(y) || !blit_rgn1_clip(y, result->height - y->origin) ||
215 !blit_rgn1_clip(y, source->height - y->origin_source))
216 return false;
217
218 /*
219 * Compute some important values up front to avoid doing it inside the bit
220 * block transfer loops. The x_max constant represents the maximum x
221 * coordinate of the region to be processed. The extra_scan_count constant
222 * calculates how many additional bytes (beyond the first byte) are needed to
223 * cover the width of the region in bytes. The scan_origin_mask and
224 * scan_extent_mask constants are used to mask the bits at the start and end
225 * of each scanline, ensuring that only the relevant bits are processed. The
226 * offset and offset_source constants are used to calculate the stride offsets
227 * for the destination and source scanlines, respectively, allowing for
228 * efficient traversal of the scanline buffers.
229 */
230 const int x_max = x->origin + x->extent - 1;
231 const int extra_scan_count = (x_max >> 3) - (x->origin >> 3);
232 const blit_scanline_t scan_origin_mask = 0xffU >> (x->origin & 7);
233 const blit_scanline_t scan_extent_mask = 0xffU << (7 - (x_max & 7));
234 const int offset = result->stride - 1 - extra_scan_count;
235 const int offset_source = source->stride - 1 - extra_scan_count;
236 blit_scanline_t *store = blit_scan_find(result, x->origin, y->origin);
237
238 /*
239 * Set up phase alignment for source fetches. The source x position is given
240 * by x->origin_source. The destination x position is given by x->origin. The
241 * shift is the difference between these two positions modulo 8. The phase
242 * alignment structure handles the bit shifts required to align the source
243 * data with the destination data based on the bit positions. Each fetch from
244 * the phase alignment structure returns a byte (8 bits) aligned according to
245 * the specified bit positions.
246 *
247 * The & 7 operation here ensures that we are working within the bounds of a
248 * byte (0-7 bits). This is important because the phase alignment also
249 * corrects for source byte offsets, ensuring that the fetched data is
250 * correctly aligned with respect to the destination, regardless of the
251 * starting bit positions. Do not let the phase alignment and the scan find
252 * get out of sync! Keep them in step!
253 */
254 struct blit_phase_align align;
256 &align, x->origin, x->origin_source & 7,
257 blit_scan_find(source, x->origin_source, y->origin_source));
258
259 /*
260 * Perform the bit block transfer using the specified raster operation. The
261 * transfer is done scanline by scanline, processing each byte in the scanline
262 * according to the raster operation defined by rop2. The function handles the
263 * masking of the first and last bytes in each scanline to ensure that only
264 * the relevant bits are modified. If there are no extra bytes beyond the
265 * first byte, it processes the scanline in a single pass. If there are extra
266 * bytes, it processes the first byte with the origin mask, then processes the
267 * middle bytes without masking, and finally processes the last byte with the
268 * extent mask.
269 *
270 * This approach ensures that the bit block transfer is efficient and
271 * correctly applies the raster operation across the specified region. The use
272 * of the phase alignment structure ensures that the source data is correctly
273 * aligned with the destination data during the transfer.
274 */
275 int extent = y->extent;
276 if (extra_scan_count == 0) {
277 const blit_scanline_t scan_mask = scan_origin_mask & scan_extent_mask;
278 while (extent--) {
280 fetch_logic_mask_store(&align, rop2, scan_mask, store++);
281 store += offset;
282 align.store += offset_source;
283 }
284 } else {
285 while (extent--) {
287 fetch_logic_mask_store(&align, rop2, scan_origin_mask, store++);
288 int extra = extra_scan_count;
289 while (--extra) {
290 fetch_logic_store(&align, rop2, store++);
291 }
292 fetch_logic_mask_store(&align, rop2, scan_extent_mask, store++);
293 store += offset;
294 align.store += offset_source;
295 }
296 }
297 return true;
298}
299
300bool blit_rop2(struct blit_scan *result, const int x, const int y,
301 const int x_extent, const int y_extent,
302 const struct blit_scan *source, const int x_source,
303 const int y_source, enum blit_rop2 rop2) {
304 /*
305 * Build the one-dimensional region structures for x and y axes from the
306 * arguments. These structures define the origin and extent of the region to
307 * be processed in both the result and source scan structures. Throw them
308 * away after the raster operation because the caller does not want them.
309 */
310 struct blit_rgn1 x_rgn1 = {
311 .origin = x,
312 .extent = x_extent,
313 .origin_source = x_source,
314 };
315 struct blit_rgn1 y_rgn1 = {
316 .origin = y,
317 .extent = y_extent,
318 .origin_source = y_source,
319 };
321}
322
323void fetch_logic_mask_store(struct blit_phase_align *align, enum blit_rop2 rop2,
325 *store = (*store & ~mask) |
326 (mask & rop2_func[rop2](blit_phase_align_fetch(align), *store));
327}
328
329void fetch_logic_store(struct blit_phase_align *align, enum blit_rop2 rop2,
330 blit_scanline_t *store) {
331 *store = rop2_func[rop2](blit_phase_align_fetch(align), *store);
332}
Phase alignment for 8-bit bytes.
void blit_phase_align_prefetch(struct blit_phase_align *align)
Prefetches the next byte into the alignment structure.
Definition phase_align.c:79
void blit_phase_align_start(struct blit_phase_align *align, int x, int x_store, const blit_scanline_t *store)
Initialises the phase alignment structure.
Definition phase_align.c:48
blit_scanline_t blit_phase_align_fetch(struct blit_phase_align *align)
Fetches the next byte from the phase alignment structure.
Definition phase_align.c:83
blit_scanline_t(* blit_rop2_func_t)(blit_scanline_t fetch, blit_scanline_t store)
Type definition for raster operation function pointer.
Definition rop2.c:35
bool blit_rgn1_rop2(struct blit_scan *result, struct blit_rgn1 *x, struct blit_rgn1 *y, const struct blit_scan *source, enum blit_rop2 rop2)
Perform raster operation with masking and store the result.
Definition rop2.c:195
#define ROP_REV_POLISH(revPolish, x)
Macro to define a raster operation function.
Definition rop2.c:69
#define D
8-bit destination operand.
Definition rop2.c:26
#define S
8-bit source operand.
Definition rop2.c:21
Binary raster operations.
blit_rop2
Enumeration of binary raster operation codes.
Definition rop2.h:27
uint8_t blit_scanline_t
Type definition for a scanline element.
Definition scan.h:24
Phase alignment structure.
Definition phase_align.h:32
const blit_scanline_t * store
Pointer to the data being processed.
Definition phase_align.h:44
One-dimensional region structure.
Definition rgn1.h:26
int origin
Origin of the region.
Definition rgn1.h:30
int origin_source
Source origin of the region.
Definition rgn1.h:38
int extent
Extent of the region.
Definition rgn1.h:34
Scanline structure.
Definition scan.h:32
int height
Height of the scanline buffer in pixels.
Definition scan.h:50
int stride
Stride of the scanline buffer.
Definition scan.h:57
int width
Width of the scanline buffer in pixels.
Definition scan.h:45