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
68#define ROP_REV_POLISH(revPolish, x) \
69 static blit_scanline_t rop##revPolish(blit_scanline_t fetch, blit_scanline_t store); \
70 blit_scanline_t rop##revPolish(blit_scanline_t fetch, blit_scanline_t store) { return x; }
71
76
77/*
78 * Note that the macro ends with a semicolon. This is intentional to allow for
79 * better formatting, even though semantically it is not required. Without the
80 * trailing semicolon, the code would compile correctly, but automated
81 * formatting tools will indent the subsequent code incorrectly.
82 */
83
87ROP_REV_POLISH(DSon, ~(D | S));
88
92ROP_REV_POLISH(DSna, D & ~S);
93
98
103
108
113
117ROP_REV_POLISH(DSan, ~(D &S));
118
123
127ROP_REV_POLISH(DSxn, ~(D ^ S));
128
133
138
143
148
153
158
165static blit_rop2_func_t rop2_func[] = {&rop0, &ropDSon, &ropDSna, &ropSn, &ropSDna, &ropDn, &ropDSx, &ropDSan,
166 &ropDSa, &ropDSxn, &ropD, &ropDSno, &ropS, &ropSDno, &ropDSo, &rop1};
167
175static void fetch_logic_mask_store(struct blit_phase_align *align, enum blit_rop2 rop2, blit_scanline_t mask, blit_scanline_t *store);
176
183static void fetch_logic_store(struct blit_phase_align *align, enum blit_rop2 rop2, blit_scanline_t *store);
184
185int blit_rgn1_rop2(struct blit_scan *result, struct blit_rgn1 *x, struct blit_rgn1 *y, const struct blit_scan *source, enum blit_rop2 rop2) {
186 /*
187 * Normalise, move, and clip the x region. The regions are first normalised to
188 * ensure that their extents are non-negative. Then, they are moved to
189 * ensure that their origins are non-negative. Finally, they are clipped to
190 * ensure that they fit within the bounds of the destination and source scan
191 * structures.
192 */
193 blit_rgn1_norm(x);
194 if (!blit_rgn1_move(x) || !blit_rgn1_clip(x, result->width - x->origin) || !blit_rgn1_clip(x, source->width - x->origin_source))
195 return 0;
196
197 /*
198 * Normalise, move, and clip the y region.
199 */
200 blit_rgn1_norm(y);
201 if (!blit_rgn1_move(y) || !blit_rgn1_clip(y, result->height - y->origin) || !blit_rgn1_clip(y, source->height - y->origin_source))
202 return 0;
203
204 /*
205 * Compute some important values up front to avoid doing it inside the bit
206 * block transfer loops. The x_max constant represents the maximum x
207 * coordinate of the region to be processed. The extra_scan_count constant
208 * calculates how many additional bytes (beyond the first byte) are needed to
209 * cover the width of the region in bytes. The scan_origin_mask and
210 * scan_extent_mask constants are used to mask the bits at the start and end
211 * of each scanline, ensuring that only the relevant bits are processed. The
212 * offset and offset_source constants are used to calculate the stride offsets
213 * for the destination and source scanlines, respectively, allowing for
214 * efficient traversal of the scanline buffers.
215 */
216 const int x_max = x->origin + x->extent - 1;
217 const int extra_scan_count = (x_max >> 3) - (x->origin >> 3);
218 const blit_scanline_t scan_origin_mask = 0xffU >> (x->origin & 7);
219 const blit_scanline_t scan_extent_mask = 0xffU << (7 - (x_max & 7));
220 const int offset = result->stride - 1 - extra_scan_count;
221 const int offset_source = source->stride - 1 - extra_scan_count;
222 blit_scanline_t *store = blit_scan_find(result, x->origin, y->origin);
223
224 /*
225 * Set up phase alignment for source fetches. The source x position is given
226 * by x->origin_source. The destination x position is given by x->origin. The
227 * shift is the difference between these two positions modulo 8. The phase
228 * alignment structure handles the bit shifts required to align the source
229 * data with the destination data based on the bit positions. Each fetch from
230 * the phase alignment structure returns a byte (8 bits) aligned according to
231 * the specified bit positions.
232 *
233 * The & 7 operation here ensures that we are working within the bounds of a
234 * byte (0-7 bits). This is important because the phase alignment also
235 * corrects for source byte offsets, ensuring that the fetched data is
236 * correctly aligned with respect to the destination, regardless of the
237 * starting bit positions. Do not let the phase alignment and the scan find
238 * get out of sync! Keep them in step!
239 */
240 struct blit_phase_align align;
241 blit_phase_align_start(&align, x->origin, x->origin_source & 7, blit_scan_find(source, x->origin_source, y->origin_source));
242
243 /*
244 * Perform the bit block transfer using the specified raster operation. The
245 * transfer is done scanline by scanline, processing each byte in the scanline
246 * according to the raster operation defined by rop2. The function handles the
247 * masking of the first and last bytes in each scanline to ensure that only
248 * the relevant bits are modified. If there are no extra bytes beyond the
249 * first byte, it processes the scanline in a single pass. If there are extra
250 * bytes, it processes the first byte with the origin mask, then processes the
251 * middle bytes without masking, and finally processes the last byte with the
252 * extent mask.
253 *
254 * This approach ensures that the bit block transfer is efficient and
255 * correctly applies the raster operation across the specified region. The use
256 * of the phase alignment structure ensures that the source data is correctly
257 * aligned with the destination data during the transfer.
258 */
259 int extent = y->extent, logic_count = 0;
260 if (extra_scan_count == 0) {
261 const blit_scanline_t scan_mask = scan_origin_mask & scan_extent_mask;
262 while (extent--) {
264 fetch_logic_mask_store(&align, rop2, scan_mask, store++);
265 logic_count++;
266 store += offset;
267 align.store += offset_source;
268 }
269 } else {
270 while (extent--) {
272 fetch_logic_mask_store(&align, rop2, scan_origin_mask, store++);
273 logic_count++;
274 int extra = extra_scan_count;
275 while (--extra) {
276 fetch_logic_store(&align, rop2, store++);
277 logic_count++;
278 }
279 fetch_logic_mask_store(&align, rop2, scan_extent_mask, store++);
280 logic_count++;
281 store += offset;
282 align.store += offset_source;
283 }
284 }
285 return logic_count;
286}
287
288int blit_rop2(struct blit_scan *result,
289 /* destination region */
290 const int x, const int y, const int x_extent, const int y_extent,
291 /* source region */
292 const struct blit_scan *source, const int x_source, const int y_source,
293 /* raster operation */
294 enum blit_rop2 rop2) {
295 /*
296 * Build the one-dimensional region structures for x and y axes from the
297 * arguments. These structures define the origin and extent of the region to
298 * be processed in both the result and source scan structures. Throw them
299 * away after the raster operation because the caller does not want them.
300 */
301 struct blit_rgn1 x_rgn1 = {
302 .origin = x,
303 .extent = x_extent,
304 .origin_source = x_source,
305 };
306 struct blit_rgn1 y_rgn1 = {
307 .origin = y,
308 .extent = y_extent,
309 .origin_source = y_source,
310 };
312}
313
314void fetch_logic_mask_store(struct blit_phase_align *align, enum blit_rop2 rop2, blit_scanline_t mask, blit_scanline_t *store) {
315 *store = (*store & ~mask) | (mask & rop2_func[rop2](blit_phase_align_fetch(align), *store));
316}
317
318void fetch_logic_store(struct blit_phase_align *align, enum blit_rop2 rop2, blit_scanline_t *store) {
319 *store = rop2_func[rop2](blit_phase_align_fetch(align), *store);
320}
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
#define ROP_REV_POLISH(revPolish, x)
Macro to define a raster operation function.
Definition rop2.c:68
int 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:185
#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