xref: /haiku/src/add-ons/accelerants/ati/mach64_util.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 /*
2 	Haiku ATI video driver adapted from the X.org ATI driver.
3 
4 	Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
5 
6 	Copyright 2009 Haiku, Inc.  All rights reserved.
7 	Distributed under the terms of the MIT license.
8 
9 	Authors:
10 	Gerald Zajac 2009
11 */
12 
13 #include "accelerant.h"
14 #include "mach64.h"
15 
16 
17 #define MAX_INT	((int)((unsigned int)(-1) >> 2))
18 
19 
20 
21 void
22 Mach64_ReduceRatio(int *numerator, int *denominator)
23 {
24 	// Reduce a fraction by factoring out the largest common divider of the
25 	// fraction's numerator and denominator.
26 
27 	int multiplier = *numerator;
28 	int divider = *denominator;
29 	int remainder;
30 
31 	while ((remainder = multiplier % divider)) {
32 		multiplier = divider;
33 		divider = remainder;
34 	}
35 
36 	*numerator /= divider;
37 	*denominator /= divider;
38 }
39 
40 
41 
42 int
43 Mach64_Divide(int numerator, int denominator, int shift, const int roundingKind)
44 {
45 	// Using integer arithmetic and avoiding overflows, this function finds the
46 	// rounded integer that best approximates
47 	//
48 	//		numerator      shift
49 	//		----------- * 2
50 	//		denominator
51 	//
52 	// using the specified rounding (floor (<0), nearest (=0) or ceiling (>0)).
53 
54 	Mach64_ReduceRatio(&numerator, &denominator);
55 
56 	// Deal with left shifts but try to keep the denominator even.
57 	if (denominator & 1) {
58 		if (denominator <= MAX_INT) {
59 			denominator <<= 1;
60 			shift++;
61 		}
62 	} else {
63 		while ((shift > 0) && !(denominator & 3)) {
64 			denominator >>= 1;
65 			shift--;
66 		}
67 	}
68 
69 	// Deal with right shifts.
70 	while (shift < 0) {
71 		if ((numerator & 1) && (denominator <= MAX_INT))
72 			denominator <<= 1;
73 		else
74 			numerator >>= 1;
75 
76 		shift++;
77 	}
78 
79 	int rounding = 0;					// Default to floor
80 
81 	if (!roundingKind)					// nearest
82 		rounding = denominator >> 1;
83 	else if (roundingKind > 0)			// ceiling
84 		rounding = denominator - 1;
85 
86 	return ((numerator / denominator) << shift) +
87 		   ((((numerator % denominator) << shift) + rounding) / denominator);
88 }
89