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
Mach64_ReduceRatio(int * numerator,int * denominator)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
Mach64_Divide(int numerator,int denominator,int shift,const int roundingKind)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