1 /***************************************************************************
2 * Copyright (C) 2010 PCSX4ALL Team *
3 * Copyright (C) 2010 Unai *
4 * Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com) *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
20 ***************************************************************************/
22 ///////////////////////////////////////////////////////////////////////////////
23 // GPU internal line drawing functions
25 // Rewritten October 2016 by senquack:
26 // Instead of one pixel at a time, lines are now drawn in runs of pixels,
27 // whether vertical, horizontal, or diagonal. A new inner driver
28 // 'gpuPixelSpanFn' is used, as well as an enhanced Bresenham run-slice
29 // algorithm. For more information, see the following:
31 // Michael Abrash - Graphics Programming Black Book
32 // Chapters 35 - 36 (does not implement diagonal runs)
33 // http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919
34 // http://www.jagregory.com/abrash-black-book/
36 // Article by Andrew Delong (does not implement diagonal runs)
37 // http://timetraces.ca/nw/drawline.htm
39 // 'Run-Based Multi-Point Line Drawing' by Eun Jae Lee & Larry F. Hodges
40 // https://smartech.gatech.edu/bitstream/handle/1853/3632/93-22.pdf
41 // Provided the idea of doing a half-octant transform allowing lines with
42 // slopes between 0.5 and 2.0 (diagonal runs of pixels) to be handled
43 // identically to the traditional horizontal/vertical run-slice method.
45 // Use 16.16 fixed point precision for line math.
46 // NOTE: Gouraud colors used by gpuPixelSpanFn can use a different precision.
47 #define GPU_LINE_FIXED_BITS 16
49 // If defined, Gouraud lines will use fixed-point multiply-by-inverse to
50 // do most divisions. With enough accuracy, this should be OK.
51 #define USE_LINES_ALL_FIXED_PT_MATH
53 //////////////////////
54 // Flat-shaded line //
55 //////////////////////
56 void gpuDrawLineF(PtrUnion packet, const PSD gpuPixelSpanDriver)
61 // All three of these variables should be signed (so multiplication works)
62 ptrdiff_t sx; // Sign of x delta, positive when x0 < x1
63 const ptrdiff_t dst_depth = FRAME_BYTES_PER_PIXEL; // PSX: 2 bytes per pixel
64 const ptrdiff_t dst_stride = FRAME_BYTE_STRIDE; // PSX: 2048 bytes per framebuffer line
66 // Clip region: xmax/ymax seem to normally be one *past* the rightmost/
67 // bottommost pixels of the draw area. Since we render every pixel between
68 // and including both line endpoints, subtract one from xmax/ymax.
69 const int xmin = gpu_unai.DrawingArea[0];
70 const int ymin = gpu_unai.DrawingArea[1];
71 const int xmax = gpu_unai.DrawingArea[2] - 1;
72 const int ymax = gpu_unai.DrawingArea[3] - 1;
74 x0 = GPU_EXPANDSIGN(packet.S2[2]) + gpu_unai.DrawingOffset[0];
75 y0 = GPU_EXPANDSIGN(packet.S2[3]) + gpu_unai.DrawingOffset[1];
76 x1 = GPU_EXPANDSIGN(packet.S2[4]) + gpu_unai.DrawingOffset[0];
77 y1 = GPU_EXPANDSIGN(packet.S2[5]) + gpu_unai.DrawingOffset[1];
79 // Always draw top to bottom, so ensure y0 <= y1
85 // Is line totally outside Y clipping range?
86 if (y0 > ymax || y1 < ymin) return;
91 // X-axis range check : max distance between any two X coords is 1023
92 // (PSX hardware will not render anything violating this rule)
93 // NOTE: We'll check y coord range further below
94 if (dx >= CHKMAX_X || dx <= -CHKMAX_X)
97 // Y-axis range check and clipping
99 // Y-axis range check : max distance between any two Y coords is 511
100 // (PSX hardware will not render anything violating this rule)
104 // We already know y0 < y1
106 x0 += GPU_FAST_DIV(((ymin - y0) * dx), dy);
110 x1 += GPU_FAST_DIV(((ymax - y1) * dx), dy);
114 // Recompute in case clipping occurred:
119 // Check X clipping range, set 'sx' x-direction variable
121 // Is vertical line totally outside X clipping range?
122 if (x0 < xmin || x0 > xmax)
127 // x0 is leftmost coordinate
128 if (x0 > xmax) return; // Both points outside X clip range
131 if (x1 < xmin) return; // Both points outside X clip range
132 y0 += GPU_FAST_DIV(((xmin - x0) * dy), dx);
137 y1 += GPU_FAST_DIV(((xmax - x1) * dy), dx);
142 dx = x1 - x0; // Get final value, which should also be absolute value
144 // x1 is leftmost coordinate
145 if (x1 > xmax) return; // Both points outside X clip range
148 if (x0 < xmin) return; // Both points outside X clip range
150 y1 += GPU_FAST_DIV(((xmin - x1) * dy), dx);
155 y0 += GPU_FAST_DIV(((xmax - x0) * dy), dx);
160 dx = x0 - x1; // Get final value, which should also be absolute value
163 // Recompute in case clipping occurred:
167 // IMPORTANT: dx,dy should now contain their absolute values
169 int min_length, // Minimum length of a pixel run
170 start_length, // Length of first run
171 end_length, // Length of last run
172 err_term, // Cumulative error to determine when to draw longer run
173 err_adjup, // Increment to err_term for each run drawn
174 err_adjdown; // Subract this from err_term after drawing longer run
176 // Color to draw with (16 bits, highest of which is unset mask bit)
177 uintptr_t col16 = GPU_RGB16(packet.U4[0]);
179 // We use u8 pointers even though PS1 has u16 framebuffer.
180 // This allows pixel-drawing functions to increment dst pointer
181 // directly by the passed 'incr' value, not having to shift it first.
182 u8 *dst = (u8*)gpu_unai.vram + y0 * dst_stride + x0 * dst_depth;
184 // SPECIAL CASE: Vertical line
186 gpuPixelSpanDriver(dst, col16, dst_stride, dy+1);
190 // SPECIAL CASE: Horizontal line
192 gpuPixelSpanDriver(dst, col16, sx * dst_depth, dx+1);
196 // SPECIAL CASE: Diagonal line
198 gpuPixelSpanDriver(dst, col16, dst_stride + (sx * dst_depth), dy+1);
202 int major, minor; // Major axis, minor axis
203 ptrdiff_t incr_major, incr_minor; // Ptr increment for each step along axis
213 // Determine if diagonal or horizontal runs
214 if (major < (2 * minor)) {
215 // Diagonal runs, so perform half-octant transformation
216 minor = major - minor;
218 // Advance diagonally when drawing runs
219 incr_major = dst_stride + (sx * dst_depth);
221 // After drawing each run, correct for over-advance along minor axis
223 incr_minor = -dst_stride;
225 incr_minor = -sx * dst_depth;
227 // Horizontal or vertical runs
229 incr_major = sx * dst_depth;
230 incr_minor = dst_stride;
232 incr_major = dst_stride;
233 incr_minor = sx * dst_depth;
238 // Minimum number of pixels each run
239 min_length = major / minor;
241 // Initial error term; reflects an initial step of 0.5 along minor axis
242 err_term = (major % minor) - (minor * 2);
244 // Increment err_term this much each step along minor axis; when
245 // err_term crosses zero, draw longer pixel run.
246 err_adjup = (major % minor) * 2;
253 // Error term adjustment when err_term turns over; used to factor
254 // out the major-axis step made at that time
255 err_adjdown = minor * 2;
257 // The initial and last runs are partial, because minor axis advances
258 // only 0.5 for these runs, rather than 1. Each is half a full run,
259 // plus the initial pixel.
260 start_length = end_length = (min_length / 2) + 1;
262 if (min_length & 1) {
263 // If there're an odd number of pixels per run, we have 1 pixel that
264 // can't be allocated to either the initial or last partial run, so
265 // we'll add 0.5 to err_term so that this pixel will be handled
266 // by the normal full-run loop
269 // If the minimum run length is even and there's no fractional advance,
270 // we have one pixel that could go to either the initial or last
271 // partial run, which we arbitrarily allocate to the last run
273 start_length--; // Leave out the extra pixel at the start
276 // First run of pixels
277 dst = gpuPixelSpanDriver(dst, col16, incr_major, start_length);
280 // Middle runs of pixels
281 while (--minor > 0) {
282 int run_length = min_length;
283 err_term += err_adjup;
285 // If err_term passed 0, reset it and draw longer run
287 err_term -= err_adjdown;
291 dst = gpuPixelSpanDriver(dst, col16, incr_major, run_length);
295 // Final run of pixels
296 gpuPixelSpanDriver(dst, col16, incr_major, end_length);
299 /////////////////////////
300 // Gouraud-shaded line //
301 /////////////////////////
302 void gpuDrawLineG(PtrUnion packet, const PSD gpuPixelSpanDriver)
305 int dx, dy, dr, dg, db;
306 u32 r0, g0, b0, r1, g1, b1;
308 // All three of these variables should be signed (so multiplication works)
309 ptrdiff_t sx; // Sign of x delta, positive when x0 < x1
310 const ptrdiff_t dst_depth = FRAME_BYTES_PER_PIXEL; // PSX: 2 bytes per pixel
311 const ptrdiff_t dst_stride = FRAME_BYTE_STRIDE; // PSX: 2048 bytes per framebuffer line
313 // Clip region: xmax/ymax seem to normally be one *past* the rightmost/
314 // bottommost pixels of the draw area. We'll render every pixel between
315 // and including both line endpoints, so subtract one from xmax/ymax.
316 const int xmin = gpu_unai.DrawingArea[0];
317 const int ymin = gpu_unai.DrawingArea[1];
318 const int xmax = gpu_unai.DrawingArea[2] - 1;
319 const int ymax = gpu_unai.DrawingArea[3] - 1;
321 x0 = GPU_EXPANDSIGN(packet.S2[2]) + gpu_unai.DrawingOffset[0];
322 y0 = GPU_EXPANDSIGN(packet.S2[3]) + gpu_unai.DrawingOffset[1];
323 x1 = GPU_EXPANDSIGN(packet.S2[6]) + gpu_unai.DrawingOffset[0];
324 y1 = GPU_EXPANDSIGN(packet.S2[7]) + gpu_unai.DrawingOffset[1];
326 u32 col0 = packet.U4[0];
327 u32 col1 = packet.U4[2];
329 // Always draw top to bottom, so ensure y0 <= y1
333 SwapValues(col0, col1);
336 // Is line totally outside Y clipping range?
337 if (y0 > ymax || y1 < ymin) return;
339 // If defined, Gouraud colors are fixed-point 5.11, otherwise they are 8.16
340 // (This is only beneficial if using SIMD-optimized pixel driver)
341 #ifdef GPU_GOURAUD_LOW_PRECISION
342 r0 = (col0 >> 3) & 0x1f; g0 = (col0 >> 11) & 0x1f; b0 = (col0 >> 19) & 0x1f;
343 r1 = (col1 >> 3) & 0x1f; g1 = (col1 >> 11) & 0x1f; b1 = (col1 >> 19) & 0x1f;
345 r0 = col0 & 0xff; g0 = (col0 >> 8) & 0xff; b0 = (col0 >> 16) & 0xff;
346 r1 = col1 & 0xff; g1 = (col1 >> 8) & 0xff; b1 = (col1 >> 16) & 0xff;
355 // X-axis range check : max distance between any two X coords is 1023
356 // (PSX hardware will not render anything violating this rule)
357 // NOTE: We'll check y coord range further below
358 if (dx >= CHKMAX_X || dx <= -CHKMAX_X)
361 // Y-axis range check and clipping
363 // Y-axis range check : max distance between any two Y coords is 511
364 // (PSX hardware will not render anything violating this rule)
368 // We already know y0 < y1
370 #ifdef USE_LINES_ALL_FIXED_PT_MATH
371 s32 factor = GPU_FAST_DIV(((ymin - y0) << GPU_LINE_FIXED_BITS), dy);
372 x0 += (dx * factor) >> GPU_LINE_FIXED_BITS;
373 r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
374 g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
375 b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
377 x0 += (ymin - y0) * dx / dy;
378 r0 += (ymin - y0) * dr / dy;
379 g0 += (ymin - y0) * dg / dy;
380 b0 += (ymin - y0) * db / dy;
386 #ifdef USE_LINES_ALL_FIXED_PT_MATH
387 s32 factor = GPU_FAST_DIV(((ymax - y1) << GPU_LINE_FIXED_BITS), dy);
388 x1 += (dx * factor) >> GPU_LINE_FIXED_BITS;
389 r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
390 g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
391 b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
393 x1 += (ymax - y1) * dx / dy;
394 r1 += (ymax - y1) * dr / dy;
395 g1 += (ymax - y1) * dg / dy;
396 b1 += (ymax - y1) * db / dy;
401 // Recompute in case clipping occurred:
409 // Check X clipping range, set 'sx' x-direction variable
411 // Is vertical line totally outside X clipping range?
412 if (x0 < xmin || x0 > xmax)
417 // x0 is leftmost coordinate
418 if (x0 > xmax) return; // Both points outside X clip range
421 if (x1 < xmin) return; // Both points outside X clip range
423 #ifdef USE_LINES_ALL_FIXED_PT_MATH
424 s32 factor = GPU_FAST_DIV(((xmin - x0) << GPU_LINE_FIXED_BITS), dx);
425 y0 += (dy * factor) >> GPU_LINE_FIXED_BITS;
426 r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
427 g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
428 b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
430 y0 += (xmin - x0) * dy / dx;
431 r0 += (xmin - x0) * dr / dx;
432 g0 += (xmin - x0) * dg / dx;
433 b0 += (xmin - x0) * db / dx;
439 #ifdef USE_LINES_ALL_FIXED_PT_MATH
440 s32 factor = GPU_FAST_DIV(((xmax - x1) << GPU_LINE_FIXED_BITS), dx);
441 y1 += (dy * factor) >> GPU_LINE_FIXED_BITS;
442 r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
443 g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
444 b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
446 y1 += (xmax - x1) * dy / dx;
447 r1 += (xmax - x1) * dr / dx;
448 g1 += (xmax - x1) * dg / dx;
449 b1 += (xmax - x1) * db / dx;
455 dx = x1 - x0; // Get final value, which should also be absolute value
457 // x1 is leftmost coordinate
458 if (x1 > xmax) return; // Both points outside X clip range
461 if (x0 < xmin) return; // Both points outside X clip range
463 #ifdef USE_LINES_ALL_FIXED_PT_MATH
464 s32 factor = GPU_FAST_DIV(((xmin - x1) << GPU_LINE_FIXED_BITS), dx);
465 y1 += (dy * factor) >> GPU_LINE_FIXED_BITS;
466 r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
467 g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
468 b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
470 y1 += (xmin - x1) * dy / dx;
471 r1 += (xmin - x1) * dr / dx;
472 g1 += (xmin - x1) * dg / dx;
473 b1 += (xmin - x1) * db / dx;
479 #ifdef USE_LINES_ALL_FIXED_PT_MATH
480 s32 factor = GPU_FAST_DIV(((xmax - x0) << GPU_LINE_FIXED_BITS), dx);
481 y0 += (dy * factor) >> GPU_LINE_FIXED_BITS;
482 r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
483 g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
484 b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
486 y0 += (xmax - x0) * dy / dx;
487 r0 += (xmax - x0) * dr / dx;
488 g0 += (xmax - x0) * dg / dx;
489 b0 += (xmax - x0) * db / dx;
495 dx = x0 - x1; // Get final value, which should also be absolute value
498 // Recompute in case clipping occurred:
505 // IMPORTANT: dx,dy should now contain their absolute values
507 int min_length, // Minimum length of a pixel run
508 start_length, // Length of first run
509 end_length, // Length of last run
510 err_term, // Cumulative error to determine when to draw longer run
511 err_adjup, // Increment to err_term for each run drawn
512 err_adjdown; // Subract this from err_term after drawing longer run
515 gcol.r = r0 << GPU_GOURAUD_FIXED_BITS;
516 gcol.g = g0 << GPU_GOURAUD_FIXED_BITS;
517 gcol.b = b0 << GPU_GOURAUD_FIXED_BITS;
519 // We use u8 pointers even though PS1 has u16 framebuffer.
520 // This allows pixel-drawing functions to increment dst pointer
521 // directly by the passed 'incr' value, not having to shift it first.
522 u8 *dst = (u8*)gpu_unai.vram + y0 * dst_stride + x0 * dst_depth;
524 // SPECIAL CASE: Vertical line
526 #ifdef USE_LINES_ALL_FIXED_PT_MATH
527 // Get dy fixed-point inverse
528 s32 inv_factor = 1 << GPU_GOURAUD_FIXED_BITS;
529 if (dy > 1) inv_factor = GPU_FAST_DIV(inv_factor, dy);
531 // Simultaneously divide and convert integer to Gouraud fixed point:
532 gcol.r_incr = dr * inv_factor;
533 gcol.g_incr = dg * inv_factor;
534 gcol.b_incr = db * inv_factor;
536 // First, convert to Gouraud fixed point
537 gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
538 gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
539 gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
542 if (dr) gcol.r_incr /= dy;
543 if (dg) gcol.g_incr /= dy;
544 if (db) gcol.b_incr /= dy;
548 gpuPixelSpanDriver(dst, (uintptr_t)&gcol, dst_stride, dy+1);
552 // SPECIAL CASE: Horizontal line
554 #ifdef USE_LINES_ALL_FIXED_PT_MATH
555 // Get dx fixed-point inverse
556 s32 inv_factor = (1 << GPU_GOURAUD_FIXED_BITS);
557 if (dx > 1) inv_factor = GPU_FAST_DIV(inv_factor, dx);
559 // Simultaneously divide and convert integer to Gouraud fixed point:
560 gcol.r_incr = dr * inv_factor;
561 gcol.g_incr = dg * inv_factor;
562 gcol.b_incr = db * inv_factor;
564 gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
565 gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
566 gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
569 if (dr) gcol.r_incr /= dx;
570 if (dg) gcol.g_incr /= dx;
571 if (db) gcol.b_incr /= dx;
575 gpuPixelSpanDriver(dst, (uintptr_t)&gcol, sx * dst_depth, dx+1);
579 // SPECIAL CASE: Diagonal line
581 #ifdef USE_LINES_ALL_FIXED_PT_MATH
582 // Get dx fixed-point inverse
583 s32 inv_factor = (1 << GPU_GOURAUD_FIXED_BITS);
584 if (dx > 1) inv_factor = GPU_FAST_DIV(inv_factor, dx);
586 // Simultaneously divide and convert integer to Gouraud fixed point:
587 gcol.r_incr = dr * inv_factor;
588 gcol.g_incr = dg * inv_factor;
589 gcol.b_incr = db * inv_factor;
591 // First, convert to Gouraud fixed point
592 gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
593 gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
594 gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
597 if (dr) gcol.r_incr /= dx;
598 if (dg) gcol.g_incr /= dx;
599 if (db) gcol.b_incr /= dx;
603 gpuPixelSpanDriver(dst, (uintptr_t)&gcol, dst_stride + (sx * dst_depth), dy+1);
607 int major, minor; // Absolute val of major,minor axis delta
608 ptrdiff_t incr_major, incr_minor; // Ptr increment for each step along axis
618 // Determine if diagonal or horizontal runs
619 if (major < (2 * minor)) {
620 // Diagonal runs, so perform half-octant transformation
621 minor = major - minor;
623 // Advance diagonally when drawing runs
624 incr_major = dst_stride + (sx * dst_depth);
626 // After drawing each run, correct for over-advance along minor axis
628 incr_minor = -dst_stride;
630 incr_minor = -sx * dst_depth;
632 // Horizontal or vertical runs
634 incr_major = sx * dst_depth;
635 incr_minor = dst_stride;
637 incr_major = dst_stride;
638 incr_minor = sx * dst_depth;
642 #ifdef USE_LINES_ALL_FIXED_PT_MATH
643 s32 major_inv = GPU_FAST_DIV((1 << GPU_GOURAUD_FIXED_BITS), major);
645 // Simultaneously divide and convert from integer to Gouraud fixed point:
646 gcol.r_incr = dr * major_inv;
647 gcol.g_incr = dg * major_inv;
648 gcol.b_incr = db * major_inv;
650 gcol.r_incr = dr ? ((dr << GPU_GOURAUD_FIXED_BITS) / major) : 0;
651 gcol.g_incr = dg ? ((dg << GPU_GOURAUD_FIXED_BITS) / major) : 0;
652 gcol.b_incr = db ? ((db << GPU_GOURAUD_FIXED_BITS) / major) : 0;
656 // Minimum number of pixels each run
657 min_length = major / minor;
659 // Initial error term; reflects an initial step of 0.5 along minor axis
660 err_term = (major % minor) - (minor * 2);
662 // Increment err_term this much each step along minor axis; when
663 // err_term crosses zero, draw longer pixel run.
664 err_adjup = (major % minor) * 2;
671 // Error term adjustment when err_term turns over; used to factor
672 // out the major-axis step made at that time
673 err_adjdown = minor * 2;
675 // The initial and last runs are partial, because minor axis advances
676 // only 0.5 for these runs, rather than 1. Each is half a full run,
677 // plus the initial pixel.
678 start_length = end_length = (min_length / 2) + 1;
680 if (min_length & 1) {
681 // If there're an odd number of pixels per run, we have 1 pixel that
682 // can't be allocated to either the initial or last partial run, so
683 // we'll add 0.5 to err_term so that this pixel will be handled
684 // by the normal full-run loop
687 // If the minimum run length is even and there's no fractional advance,
688 // we have one pixel that could go to either the initial or last
689 // partial run, which we'll arbitrarily allocate to the last run
691 start_length--; // Leave out the extra pixel at the start
694 // First run of pixels
695 dst = gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, start_length);
698 // Middle runs of pixels
699 while (--minor > 0) {
700 int run_length = min_length;
701 err_term += err_adjup;
703 // If err_term passed 0, reset it and draw longer run
705 err_term -= err_adjdown;
709 dst = gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, run_length);
713 // Final run of pixels
714 gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, end_length);