|
5 | 5 | #include "GS/GSGL.h" |
6 | 6 | #include "GS/GS.h" |
7 | 7 | #include "GS/GSUtil.h" |
| 8 | +#include "GS/GSState.h" |
8 | 9 |
|
9 | | -static int findmax(int tl, int br, int limit, int wm, int minuv, int maxuv) |
| 10 | +// SIZE: TW or TW |
| 11 | +// WM, MIN, MAX : Correspondng field of TEX0 |
| 12 | +// min, max: Range that U or V coordintes take on. |
| 13 | +static int GetMaxUV(int SIZE, int WM, int MIN, int MAX, int min, int max) |
10 | 14 | { |
11 | | - // return max possible texcoord. |
12 | | - int uv = br; |
| 15 | + // Confirmed on hardware if SIZE > 10 (or pixel size > 1024), |
| 16 | + // it basically gets masked so you end up with a 1x1 pixel (Except Region Clamp). |
| 17 | + if (SIZE > 10 && (WM != CLAMP_REGION_CLAMP)) |
| 18 | + return 0; |
13 | 19 |
|
14 | | - // Confirmed on hardware if the size exceeds 1024, it basically gets masked so you end up with a 1x1 pixel (Except Region Clamp). |
15 | | - if (limit > 1024) |
16 | | - limit = 0; |
| 20 | + int min_out, max_out; // ignore min_out |
| 21 | + bool min_boundary, max_boundary; // ignore both |
| 22 | + |
| 23 | + GSState::GetClampWrapMinMaxUV(SIZE, WM, MIN, MAX, min, max, &min_out, &max_out, &min_boundary, &max_boundary); |
17 | 24 |
|
18 | | - if (wm == CLAMP_CLAMP) |
19 | | - { |
20 | | - if (uv > limit) |
21 | | - uv = limit; |
22 | | - } |
23 | | - else if (wm == CLAMP_REPEAT) |
24 | | - { |
25 | | - if (tl < 0) |
26 | | - uv = limit; // wrap around |
27 | | - else if (uv > limit) |
28 | | - uv = limit; |
29 | | - } |
30 | | - else if (wm == CLAMP_REGION_CLAMP) |
31 | | - { |
32 | | - if (uv < minuv) |
33 | | - uv = minuv; |
34 | | - if (uv > maxuv) |
35 | | - uv = maxuv; |
36 | | - } |
37 | | - else if (wm == CLAMP_REGION_REPEAT) |
38 | | - { |
39 | | - // REGION_REPEAT adhears to the original texture size, even if offset outside the texture (with MAXUV). |
40 | | - minuv &= limit; |
41 | | - if (tl < 0) |
42 | | - uv = minuv | maxuv; // wrap around, just use (any & mask) | fix. |
43 | | - else |
44 | | - uv = std::min(uv, minuv) | maxuv; // (any & mask) cannot be larger than mask, select br if that is smaller (not br & mask because there might be a larger value between tl and br when &'ed with the mask). |
45 | | - } |
46 | | - |
47 | | - return uv; |
48 | | -} |
49 | | - |
50 | | -static int reduce(int uv, int size) |
51 | | -{ |
52 | | - while (size > 3 && (1 << (size - 1)) >= uv) |
53 | | - { |
54 | | - size--; |
55 | | - } |
56 | | - |
57 | | - return size; |
58 | | -} |
59 | | - |
60 | | -static int extend(int uv, int size) |
61 | | -{ |
62 | | - while (size < 10 && (1 << size) < uv) |
63 | | - { |
64 | | - size++; |
65 | | - } |
66 | | - |
67 | | - return size; |
| 25 | + return max_out; |
68 | 26 | } |
69 | 27 |
|
70 | 28 | void GSDrawingContext::Reset() |
@@ -98,65 +56,69 @@ void GSDrawingContext::UpdateScissor() |
98 | 56 | scissor.xyof = GSVector4i::loadl(&XYOFFSET.U64).xyxy().sub32(GSVector4i::cxpr(0, 0, 15, 15)); |
99 | 57 | } |
100 | 58 |
|
101 | | -GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(const GSVector4& st, bool linear, bool mipmap) const |
| 59 | +// Find the optimal value for TW/TH by analyzing vertex trace and clamping values, |
| 60 | +// extending only for region modes where uv may be outside. |
| 61 | +// uv_rect has rectangle bounding effecive UV coordinate (u0, v0, u1, v1) (u1 v1 endpoints exclusive) |
| 62 | +GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(GSVector4i uv_rect, bool linear, bool mipmap) const |
102 | 63 | { |
103 | 64 | if (mipmap) |
104 | 65 | return TEX0; // no mipmaping allowed |
105 | 66 |
|
106 | | - // find the optimal value for TW/TH by analyzing vertex trace and clamping values, extending only for region modes where uv may be outside |
107 | | - |
108 | | - int tw = TEX0.TW; |
109 | | - int th = TEX0.TH; |
| 67 | + const int WMS = (int)CLAMP.WMS; |
| 68 | + const int WMT = (int)CLAMP.WMT; |
110 | 69 |
|
111 | | - int wms = (int)CLAMP.WMS; |
112 | | - int wmt = (int)CLAMP.WMT; |
| 70 | + const int MINU = (int)CLAMP.MINU; |
| 71 | + const int MINV = (int)CLAMP.MINV; |
| 72 | + const int MAXU = (int)CLAMP.MAXU; |
| 73 | + const int MAXV = (int)CLAMP.MAXV; |
113 | 74 |
|
114 | | - int minu = (int)CLAMP.MINU; |
115 | | - int minv = (int)CLAMP.MINV; |
116 | | - int maxu = (int)CLAMP.MAXU; |
117 | | - int maxv = (int)CLAMP.MAXV; |
| 75 | + int TW = TEX0.TW; |
| 76 | + int TH = TEX0.TH; |
118 | 77 |
|
119 | | - GSVector4 uvf = st; |
120 | | - |
121 | | - if (linear) |
122 | | - { |
123 | | - uvf += GSVector4(-0.5f, 0.5f).xxyy(); |
124 | | - } |
| 78 | + const int min_width = uv_rect.right; |
| 79 | + const int min_height = uv_rect.bottom; |
125 | 80 |
|
126 | | - GSVector4i uv = GSVector4i(uvf.floor().xyzw(uvf.ceil())); |
| 81 | + auto ExtendLog2Size = [](int min_size, int log2_size) { |
| 82 | + while (log2_size < 10 && (1 << log2_size) < min_size) |
| 83 | + log2_size++; |
| 84 | + return log2_size; |
| 85 | + }; |
127 | 86 |
|
128 | | - uv.x = findmax(uv.x, uv.z, (1 << tw) - 1, wms, minu, maxu); |
129 | | - uv.y = findmax(uv.y, uv.w, (1 << th) - 1, wmt, minv, maxv); |
| 87 | + auto ReduceLog2Size = [](int min_size, int log2_size) { |
| 88 | + while (log2_size > 3 && (1 << (log2_size - 1)) >= min_size) |
| 89 | + log2_size--; |
| 90 | + return log2_size; |
| 91 | + }; |
130 | 92 |
|
131 | | - if (tw + th >= 19) // smaller sizes aren't worth, they just create multiple entries in the textue cache and the saved memory is less |
| 93 | + if (TW + TH >= 19) // smaller sizes aren't worth, they just create multiple entries in the textue cache and the saved memory is less |
132 | 94 | { |
133 | | - tw = reduce(uv.x, tw); |
134 | | - th = reduce(uv.y, th); |
| 95 | + TW = ReduceLog2Size(min_width, TW); |
| 96 | + TH = ReduceLog2Size(min_height, TH); |
135 | 97 | } |
136 | 98 |
|
137 | | - if (wms == CLAMP_REGION_CLAMP || wms == CLAMP_REGION_REPEAT) |
| 99 | + if (WMS == CLAMP_REGION_CLAMP || WMS == CLAMP_REGION_REPEAT) |
138 | 100 | { |
139 | | - tw = extend(uv.x, tw); |
| 101 | + TW = ExtendLog2Size(min_width, TW); |
140 | 102 | } |
141 | 103 |
|
142 | | - if (wmt == CLAMP_REGION_CLAMP || wmt == CLAMP_REGION_REPEAT) |
| 104 | + if (WMT == CLAMP_REGION_CLAMP || WMT == CLAMP_REGION_REPEAT) |
143 | 105 | { |
144 | | - th = extend(uv.y, th); |
| 106 | + TH = ExtendLog2Size(min_height, TH); |
145 | 107 | } |
146 | 108 |
|
147 | 109 | GIFRegTEX0 res = TEX0; |
148 | 110 |
|
149 | | - res.TW = tw > 10 ? 0 : tw; |
150 | | - res.TH = th > 10 ? 0 : th; |
| 111 | + res.TW = TW > 10 ? 0 : TW; |
| 112 | + res.TH = TH > 10 ? 0 : TH; |
151 | 113 |
|
152 | 114 | if (TEX0.TW != res.TW || TEX0.TH != res.TH) |
153 | 115 | { |
154 | | - GL_DBG("FixedTEX0 %05x %d %d tw %d=>%d th %d=>%d st (%.0f,%.0f,%.0f,%.0f) uvmax %d,%d wm %d,%d (%d,%d,%d,%d)", |
| 116 | + GL_DBG("FixedTEX0 %05x %d %d tw %d=>%d th %d=>%d uv (%d,%d,%d,%d) uvmax %d,%d wm %d,%d (%d,%d,%d,%d)", |
155 | 117 | (int)TEX0.TBP0, (int)TEX0.TBW, (int)TEX0.PSM, |
156 | | - (int)TEX0.TW, tw, (int)TEX0.TH, th, |
157 | | - uvf.x, uvf.y, uvf.z, uvf.w, |
158 | | - uv.x, uv.y, |
159 | | - wms, wmt, minu, maxu, minv, maxv); |
| 118 | + (int)TEX0.TW, TW, (int)TEX0.TH, TH, |
| 119 | + uv_rect.left, uv_rect.top, uv_rect.right, uv_rect.bottom, |
| 120 | + min_width - 1, min_height - 1, |
| 121 | + WMS, WMT, MINU, MAXU, MINV, MAXV); |
160 | 122 | } |
161 | 123 |
|
162 | 124 | return res; |
|
0 commit comments