blob: 1c97628da93aac5e7d199cbfdac39d6182ffad8d [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
John Bauman89401822014-05-06 15:04:28 -04002//
Nicolas Capens0bac2852016-05-07 06:09:58 -04003// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
John Bauman89401822014-05-06 15:04:28 -04006//
Nicolas Capens0bac2852016-05-07 06:09:58 -04007// http://www.apache.org/licenses/LICENSE-2.0
John Bauman89401822014-05-06 15:04:28 -04008//
Nicolas Capens0bac2852016-05-07 06:09:58 -04009// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
John Bauman89401822014-05-06 15:04:28 -040014
15#include "SamplerCore.hpp"
16
17#include "Constants.hpp"
Nicolas Capens708c24b2017-10-26 13:07:10 -040018#include "Common/Debug.hpp"
John Bauman89401822014-05-06 15:04:28 -040019
Alexis Hetu1d01aa32015-09-29 11:50:05 -040020namespace
21{
22 void applySwizzle(sw::SwizzleType swizzle, sw::Short4& s, const sw::Vector4s& c)
23 {
24 switch(swizzle)
25 {
26 case sw::SWIZZLE_RED: s = c.x; break;
27 case sw::SWIZZLE_GREEN: s = c.y; break;
28 case sw::SWIZZLE_BLUE: s = c.z; break;
29 case sw::SWIZZLE_ALPHA: s = c.w; break;
Alexis Hetu90c7ad62016-06-27 11:50:40 -040030 case sw::SWIZZLE_ZERO: s = sw::Short4(0x0000); break;
31 case sw::SWIZZLE_ONE: s = sw::Short4(0x1000); break;
Alexis Hetu1d01aa32015-09-29 11:50:05 -040032 default: ASSERT(false);
33 }
34 }
35
36 void applySwizzle(sw::SwizzleType swizzle, sw::Float4& f, const sw::Vector4f& c)
37 {
38 switch(swizzle)
39 {
40 case sw::SWIZZLE_RED: f = c.x; break;
41 case sw::SWIZZLE_GREEN: f = c.y; break;
42 case sw::SWIZZLE_BLUE: f = c.z; break;
43 case sw::SWIZZLE_ALPHA: f = c.w; break;
44 case sw::SWIZZLE_ZERO: f = sw::Float4(0.0f, 0.0f, 0.0f, 0.0f); break;
45 case sw::SWIZZLE_ONE: f = sw::Float4(1.0f, 1.0f, 1.0f, 1.0f); break;
46 default: ASSERT(false);
47 }
48 }
49}
50
John Bauman89401822014-05-06 15:04:28 -040051namespace sw
52{
Alexis Hetu56f256e2017-07-21 11:41:13 -040053 extern bool colorsDefaultToZero;
54
John Bauman89401822014-05-06 15:04:28 -040055 SamplerCore::SamplerCore(Pointer<Byte> &constants, const Sampler::State &state) : constants(constants), state(state)
56 {
57 }
58
Nicolas Capensa0b57832017-11-07 13:07:53 -050059 Vector4s SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy)
Nicolas Capensc2534f42016-04-04 11:13:24 -040060 {
Nicolas Capensa0b57832017-11-07 13:07:53 -050061 return sampleTexture(texture, u, v, w, q, q, dsx, dsy, (dsx), Implicit, true);
Nicolas Capensc2534f42016-04-04 11:13:24 -040062 }
63
Nicolas Capensa0b57832017-11-07 13:07:53 -050064 Vector4s SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function, bool fixed12)
John Bauman89401822014-05-06 15:04:28 -040065 {
Nicolas Capens89a218b2017-11-07 13:05:20 -050066 Vector4s c;
67
John Bauman89401822014-05-06 15:04:28 -040068 #if PERF_PROFILE
John Bauman66b8ab22014-05-06 15:57:45 -040069 AddAtomic(Pointer<Long>(&profiler.texOperations), 4);
John Bauman89401822014-05-06 15:04:28 -040070
71 if(state.compressedFormat)
72 {
John Bauman66b8ab22014-05-06 15:57:45 -040073 AddAtomic(Pointer<Long>(&profiler.compressedTex), 4);
John Bauman89401822014-05-06 15:04:28 -040074 }
75 #endif
76
John Bauman89401822014-05-06 15:04:28 -040077 if(state.textureType == TEXTURE_NULL)
78 {
Alexis Hetu90c7ad62016-06-27 11:50:40 -040079 c.x = Short4(0x0000);
80 c.y = Short4(0x0000);
81 c.z = Short4(0x0000);
John Bauman89401822014-05-06 15:04:28 -040082
83 if(fixed12) // FIXME: Convert to fixed12 at higher level, when required
84 {
Alexis Hetu90c7ad62016-06-27 11:50:40 -040085 c.w = Short4(0x1000);
John Bauman89401822014-05-06 15:04:28 -040086 }
87 else
88 {
Alexis Hetu90c7ad62016-06-27 11:50:40 -040089 c.w = Short4(0xFFFFu); // FIXME
John Bauman89401822014-05-06 15:04:28 -040090 }
91 }
92 else
93 {
Nicolas Capens77f0b682017-11-07 13:25:09 -050094 Float4 uuuu = u;
95 Float4 vvvv = v;
96 Float4 wwww = w;
97 Float4 qqqq = q;
98
John Bauman89401822014-05-06 15:04:28 -040099 Int face[4];
John Bauman89401822014-05-06 15:04:28 -0400100 Float lod;
101 Float anisotropy;
102 Float4 uDelta;
103 Float4 vDelta;
104
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500105 if(state.textureType != TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -0400106 {
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500107 if(state.textureType != TEXTURE_CUBE)
John Bauman89401822014-05-06 15:04:28 -0400108 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500109 computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function);
John Bauman89401822014-05-06 15:04:28 -0400110 }
111 else
112 {
Nicolas Capens77f0b682017-11-07 13:25:09 -0500113 Float4 M;
114 cubeFace(face, uuuu, vvvv, u, v, w, M);
115 computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function);
John Bauman89401822014-05-06 15:04:28 -0400116 }
117 }
118 else
119 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500120 computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function);
John Bauman89401822014-05-06 15:04:28 -0400121 }
122
John Bauman89401822014-05-06 15:04:28 -0400123 if(!hasFloatTexture())
124 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500125 c = sampleFilter(texture, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
John Bauman89401822014-05-06 15:04:28 -0400126 }
127 else
128 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500129 Vector4f cf = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function);
John Bauman89401822014-05-06 15:04:28 -0400130
131 convertFixed12(c, cf);
132 }
133
134 if(fixed12 && !hasFloatTexture())
135 {
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400136 if(has16bitTextureFormat())
John Bauman89401822014-05-06 15:04:28 -0400137 {
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400138 switch(state.textureFormat)
John Bauman89401822014-05-06 15:04:28 -0400139 {
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400140 case FORMAT_R5G6B5:
141 if(state.sRGB)
John Bauman89401822014-05-06 15:04:28 -0400142 {
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400143 sRGBtoLinear16_5_12(c.x);
144 sRGBtoLinear16_6_12(c.y);
145 sRGBtoLinear16_5_12(c.z);
John Bauman89401822014-05-06 15:04:28 -0400146 }
147 else
148 {
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400149 c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800));
150 c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00));
151 c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800));
152 }
153 break;
154 default:
155 ASSERT(false);
156 }
157 }
158 else
159 {
160 for(int component = 0; component < textureComponentCount(); component++)
161 {
162 if(state.sRGB && isRGBComponent(component))
163 {
164 sRGBtoLinear16_8_12(c[component]); // FIXME: Perform linearization at surface level for read-only textures
165 }
166 else
167 {
168 if(hasUnsignedTextureComponent(component))
169 {
170 c[component] = As<UShort4>(c[component]) >> 4;
171 }
172 else
173 {
174 c[component] = c[component] >> 3;
175 }
John Bauman89401822014-05-06 15:04:28 -0400176 }
177 }
178 }
179 }
180
181 if(fixed12 && state.textureFilter != FILTER_GATHER)
182 {
183 int componentCount = textureComponentCount();
Alexis Hetu56f256e2017-07-21 11:41:13 -0400184 short defaultColorValue = colorsDefaultToZero ? 0x0000 : 0x1000;
John Bauman89401822014-05-06 15:04:28 -0400185
186 switch(state.textureFormat)
187 {
Alexis Hetu3412d872015-10-26 16:40:26 -0400188 case FORMAT_R8I_SNORM:
189 case FORMAT_G8R8I_SNORM:
190 case FORMAT_X8B8G8R8I_SNORM:
191 case FORMAT_A8B8G8R8I_SNORM:
John Bauman89401822014-05-06 15:04:28 -0400192 case FORMAT_R8:
Nicolas Capens27496312015-05-12 15:16:06 -0400193 case FORMAT_R5G6B5:
Alexis Hetu3412d872015-10-26 16:40:26 -0400194 case FORMAT_G8R8:
195 case FORMAT_R8I:
196 case FORMAT_R8UI:
197 case FORMAT_G8R8I:
198 case FORMAT_G8R8UI:
199 case FORMAT_X8B8G8R8I:
200 case FORMAT_X8B8G8R8UI:
201 case FORMAT_A8B8G8R8I:
202 case FORMAT_A8B8G8R8UI:
203 case FORMAT_R16I:
204 case FORMAT_R16UI:
205 case FORMAT_G16R16:
206 case FORMAT_G16R16I:
207 case FORMAT_G16R16UI:
208 case FORMAT_X16B16G16R16I:
209 case FORMAT_X16B16G16R16UI:
210 case FORMAT_A16B16G16R16:
211 case FORMAT_A16B16G16R16I:
212 case FORMAT_A16B16G16R16UI:
213 case FORMAT_R32I:
214 case FORMAT_R32UI:
215 case FORMAT_G32R32I:
216 case FORMAT_G32R32UI:
217 case FORMAT_X32B32G32R32I:
218 case FORMAT_X32B32G32R32UI:
219 case FORMAT_A32B32G32R32I:
220 case FORMAT_A32B32G32R32UI:
John Bauman89401822014-05-06 15:04:28 -0400221 case FORMAT_X8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -0400222 case FORMAT_X8B8G8R8:
John Bauman89401822014-05-06 15:04:28 -0400223 case FORMAT_A8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -0400224 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400225 case FORMAT_SRGB8_X8:
226 case FORMAT_SRGB8_A8:
John Bauman89401822014-05-06 15:04:28 -0400227 case FORMAT_V8U8:
228 case FORMAT_Q8W8V8U8:
229 case FORMAT_X8L8V8U8:
230 case FORMAT_V16U16:
231 case FORMAT_A16W16V16U16:
232 case FORMAT_Q16W16V16U16:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -0400233 case FORMAT_YV12_BT601:
234 case FORMAT_YV12_BT709:
235 case FORMAT_YV12_JFIF:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400236 if(componentCount < 2) c.y = Short4(defaultColorValue);
237 if(componentCount < 3) c.z = Short4(defaultColorValue);
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400238 if(componentCount < 4) c.w = Short4(0x1000);
John Bauman89401822014-05-06 15:04:28 -0400239 break;
240 case FORMAT_A8:
John Bauman19bac1e2014-05-06 15:23:49 -0400241 c.w = c.x;
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400242 c.x = Short4(0x0000);
243 c.y = Short4(0x0000);
244 c.z = Short4(0x0000);
John Bauman89401822014-05-06 15:04:28 -0400245 break;
246 case FORMAT_L8:
247 case FORMAT_L16:
John Bauman19bac1e2014-05-06 15:23:49 -0400248 c.y = c.x;
249 c.z = c.x;
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400250 c.w = Short4(0x1000);
John Bauman89401822014-05-06 15:04:28 -0400251 break;
252 case FORMAT_A8L8:
John Bauman19bac1e2014-05-06 15:23:49 -0400253 c.w = c.y;
254 c.y = c.x;
255 c.z = c.x;
John Bauman89401822014-05-06 15:04:28 -0400256 break;
257 case FORMAT_R32F:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400258 c.y = Short4(defaultColorValue);
John Bauman89401822014-05-06 15:04:28 -0400259 case FORMAT_G32R32F:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400260 c.z = Short4(defaultColorValue);
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400261 case FORMAT_X32B32G32R32F:
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400262 c.w = Short4(0x1000);
John Bauman89401822014-05-06 15:04:28 -0400263 case FORMAT_A32B32G32R32F:
264 break;
Alexis Hetu3412d872015-10-26 16:40:26 -0400265 case FORMAT_D32F:
John Bauman89401822014-05-06 15:04:28 -0400266 case FORMAT_D32F_LOCKABLE:
John Bauman66b8ab22014-05-06 15:57:45 -0400267 case FORMAT_D32FS8_TEXTURE:
268 case FORMAT_D32FS8_SHADOW:
John Bauman19bac1e2014-05-06 15:23:49 -0400269 c.y = c.x;
270 c.z = c.x;
271 c.w = c.x;
John Bauman89401822014-05-06 15:04:28 -0400272 break;
273 default:
274 ASSERT(false);
275 }
276 }
277 }
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400278
279 if(fixed12 &&
280 ((state.swizzleR != SWIZZLE_RED) ||
281 (state.swizzleG != SWIZZLE_GREEN) ||
282 (state.swizzleB != SWIZZLE_BLUE) ||
283 (state.swizzleA != SWIZZLE_ALPHA)))
284 {
285 const Vector4s col(c);
286 applySwizzle(state.swizzleR, c.x, col);
287 applySwizzle(state.swizzleG, c.y, col);
288 applySwizzle(state.swizzleB, c.z, col);
289 applySwizzle(state.swizzleA, c.w, col);
290 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500291
292 return c;
John Bauman89401822014-05-06 15:04:28 -0400293 }
294
Nicolas Capensa0b57832017-11-07 13:07:53 -0500295 Vector4f SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400296 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500297 Vector4f c;
298
John Bauman89401822014-05-06 15:04:28 -0400299 #if PERF_PROFILE
John Bauman66b8ab22014-05-06 15:57:45 -0400300 AddAtomic(Pointer<Long>(&profiler.texOperations), 4);
John Bauman89401822014-05-06 15:04:28 -0400301
302 if(state.compressedFormat)
303 {
John Bauman66b8ab22014-05-06 15:57:45 -0400304 AddAtomic(Pointer<Long>(&profiler.compressedTex), 4);
John Bauman89401822014-05-06 15:04:28 -0400305 }
306 #endif
307
John Bauman89401822014-05-06 15:04:28 -0400308 if(state.textureType == TEXTURE_NULL)
309 {
John Bauman19bac1e2014-05-06 15:23:49 -0400310 c.x = Float4(0.0f);
311 c.y = Float4(0.0f);
312 c.z = Float4(0.0f);
313 c.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -0400314 }
315 else
316 {
Alexis Hetufacada52017-07-20 16:56:30 -0400317 // FIXME: YUV and sRGB are not supported by the floating point path
318 bool forceFloatFiltering = state.highPrecisionFiltering && !state.sRGB && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
319 if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering) // FIXME: Mostly identical to integer sampling
John Bauman89401822014-05-06 15:04:28 -0400320 {
321 Float4 uuuu = u;
322 Float4 vvvv = v;
323 Float4 wwww = w;
Nicolas Capensa0b57832017-11-07 13:07:53 -0500324 Float4 qqqq = q;
John Bauman89401822014-05-06 15:04:28 -0400325
326 Int face[4];
John Bauman89401822014-05-06 15:04:28 -0400327 Float lod;
328 Float anisotropy;
329 Float4 uDelta;
330 Float4 vDelta;
331
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500332 if(state.textureType != TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -0400333 {
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500334 if(state.textureType != TEXTURE_CUBE)
John Bauman89401822014-05-06 15:04:28 -0400335 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500336 computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function);
John Bauman89401822014-05-06 15:04:28 -0400337 }
338 else
339 {
Nicolas Capens77f0b682017-11-07 13:25:09 -0500340 Float4 M;
341 cubeFace(face, uuuu, vvvv, u, v, w, M);
342 computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function);
John Bauman89401822014-05-06 15:04:28 -0400343 }
344 }
345 else
346 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500347 computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function);
John Bauman89401822014-05-06 15:04:28 -0400348 }
349
Nicolas Capensa0b57832017-11-07 13:07:53 -0500350 c = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function);
Alexis Hetufacada52017-07-20 16:56:30 -0400351
352 if(!hasFloatTexture() && !hasUnnormalizedIntegerTexture())
353 {
354 if(has16bitTextureFormat())
355 {
356 switch(state.textureFormat)
357 {
358 case FORMAT_R5G6B5:
359 c.x *= Float4(1.0f / 0xF800);
360 c.y *= Float4(1.0f / 0xFC00);
361 c.z *= Float4(1.0f / 0xF800);
362 break;
363 default:
364 ASSERT(false);
365 }
366 }
367 else
368 {
369 for(int component = 0; component < textureComponentCount(); component++)
370 {
371 c[component] *= Float4(hasUnsignedTextureComponent(component) ? 1.0f / 0xFFFF : 1.0f / 0x7FFF);
372 }
373 }
374 }
John Bauman89401822014-05-06 15:04:28 -0400375 }
376 else
377 {
Nicolas Capensa0b57832017-11-07 13:07:53 -0500378 Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false);
John Bauman89401822014-05-06 15:04:28 -0400379
Alexis Hetuab849ae2017-07-14 10:44:10 -0400380 if(has16bitTextureFormat())
John Bauman89401822014-05-06 15:04:28 -0400381 {
Alexis Hetuab849ae2017-07-14 10:44:10 -0400382 switch(state.textureFormat)
John Bauman89401822014-05-06 15:04:28 -0400383 {
Alexis Hetuab849ae2017-07-14 10:44:10 -0400384 case FORMAT_R5G6B5:
385 if(state.sRGB)
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400386 {
Alexis Hetuab849ae2017-07-14 10:44:10 -0400387 sRGBtoLinear16_5_12(cs.x);
388 sRGBtoLinear16_6_12(cs.y);
389 sRGBtoLinear16_5_12(cs.z);
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400390
Alexis Hetuab849ae2017-07-14 10:44:10 -0400391 convertSigned12(c.x, cs.x);
392 convertSigned12(c.y, cs.y);
393 convertSigned12(c.z, cs.z);
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400394 }
Alexis Hetuab849ae2017-07-14 10:44:10 -0400395 else
396 {
397 c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
398 c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
399 c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800);
400 }
401 break;
402 default:
403 ASSERT(false);
John Bauman89401822014-05-06 15:04:28 -0400404 }
Alexis Hetuab849ae2017-07-14 10:44:10 -0400405 }
406 else
407 {
408 for(int component = 0; component < textureComponentCount(); component++)
John Bauman89401822014-05-06 15:04:28 -0400409 {
Alexis Hetu91dd1c42017-07-18 13:03:42 -0400410 // Normalized integer formats
411 if(state.sRGB && isRGBComponent(component))
John Bauman89401822014-05-06 15:04:28 -0400412 {
Alexis Hetu91dd1c42017-07-18 13:03:42 -0400413 sRGBtoLinear16_8_12(cs[component]); // FIXME: Perform linearization at surface level for read-only textures
414 convertSigned12(c[component], cs[component]);
415 }
416 else
417 {
418 if(hasUnsignedTextureComponent(component))
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400419 {
Alexis Hetu91dd1c42017-07-18 13:03:42 -0400420 convertUnsigned16(c[component], cs[component]);
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400421 }
422 else
423 {
Alexis Hetu91dd1c42017-07-18 13:03:42 -0400424 convertSigned15(c[component], cs[component]);
Nicolas Capens3a014ff2015-05-26 14:05:36 -0400425 }
John Bauman89401822014-05-06 15:04:28 -0400426 }
427 }
428 }
429 }
430
431 int componentCount = textureComponentCount();
Alexis Hetu56f256e2017-07-21 11:41:13 -0400432 float defaultColorValue = colorsDefaultToZero ? 0.0f : 1.0f;
John Bauman89401822014-05-06 15:04:28 -0400433
434 if(state.textureFilter != FILTER_GATHER)
435 {
436 switch(state.textureFormat)
437 {
Alexis Hetu3412d872015-10-26 16:40:26 -0400438 case FORMAT_R8I:
439 case FORMAT_R8UI:
440 case FORMAT_R16I:
441 case FORMAT_R16UI:
442 case FORMAT_R32I:
443 case FORMAT_R32UI:
444 c.y = As<Float4>(UInt4(0));
445 case FORMAT_G8R8I:
446 case FORMAT_G8R8UI:
447 case FORMAT_G16R16I:
448 case FORMAT_G16R16UI:
449 case FORMAT_G32R32I:
450 case FORMAT_G32R32UI:
451 c.z = As<Float4>(UInt4(0));
452 case FORMAT_X8B8G8R8I:
453 case FORMAT_X8B8G8R8UI:
454 case FORMAT_X16B16G16R16I:
455 case FORMAT_X16B16G16R16UI:
456 case FORMAT_X32B32G32R32I:
457 case FORMAT_X32B32G32R32UI:
458 c.w = As<Float4>(UInt4(1));
459 case FORMAT_A8B8G8R8I:
460 case FORMAT_A8B8G8R8UI:
461 case FORMAT_A16B16G16R16I:
462 case FORMAT_A16B16G16R16UI:
463 case FORMAT_A32B32G32R32I:
464 case FORMAT_A32B32G32R32UI:
465 break;
466 case FORMAT_R8I_SNORM:
467 case FORMAT_G8R8I_SNORM:
468 case FORMAT_X8B8G8R8I_SNORM:
469 case FORMAT_A8B8G8R8I_SNORM:
John Bauman89401822014-05-06 15:04:28 -0400470 case FORMAT_R8:
Nicolas Capens27496312015-05-12 15:16:06 -0400471 case FORMAT_R5G6B5:
Alexis Hetu3412d872015-10-26 16:40:26 -0400472 case FORMAT_G8R8:
473 case FORMAT_G16R16:
474 case FORMAT_A16B16G16R16:
John Bauman89401822014-05-06 15:04:28 -0400475 case FORMAT_X8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -0400476 case FORMAT_X8B8G8R8:
John Bauman89401822014-05-06 15:04:28 -0400477 case FORMAT_A8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -0400478 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -0400479 case FORMAT_SRGB8_X8:
480 case FORMAT_SRGB8_A8:
John Bauman89401822014-05-06 15:04:28 -0400481 case FORMAT_V8U8:
482 case FORMAT_Q8W8V8U8:
483 case FORMAT_X8L8V8U8:
484 case FORMAT_V16U16:
485 case FORMAT_A16W16V16U16:
486 case FORMAT_Q16W16V16U16:
Nicolas Capens9ada3092017-05-24 17:39:49 -0400487 case FORMAT_YV12_BT601:
488 case FORMAT_YV12_BT709:
489 case FORMAT_YV12_JFIF:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400490 if(componentCount < 2) c.y = Float4(defaultColorValue);
491 if(componentCount < 3) c.z = Float4(defaultColorValue);
John Bauman19bac1e2014-05-06 15:23:49 -0400492 if(componentCount < 4) c.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -0400493 break;
494 case FORMAT_A8:
John Bauman19bac1e2014-05-06 15:23:49 -0400495 c.w = c.x;
496 c.x = Float4(0.0f);
497 c.y = Float4(0.0f);
498 c.z = Float4(0.0f);
John Bauman89401822014-05-06 15:04:28 -0400499 break;
500 case FORMAT_L8:
501 case FORMAT_L16:
John Bauman19bac1e2014-05-06 15:23:49 -0400502 c.y = c.x;
503 c.z = c.x;
504 c.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -0400505 break;
506 case FORMAT_A8L8:
John Bauman19bac1e2014-05-06 15:23:49 -0400507 c.w = c.y;
508 c.y = c.x;
509 c.z = c.x;
John Bauman89401822014-05-06 15:04:28 -0400510 break;
511 case FORMAT_R32F:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400512 c.y = Float4(defaultColorValue);
John Bauman89401822014-05-06 15:04:28 -0400513 case FORMAT_G32R32F:
Alexis Hetu56f256e2017-07-21 11:41:13 -0400514 c.z = Float4(defaultColorValue);
Alexis Hetudbd1a8e2016-04-13 11:40:30 -0400515 case FORMAT_X32B32G32R32F:
John Bauman19bac1e2014-05-06 15:23:49 -0400516 c.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -0400517 case FORMAT_A32B32G32R32F:
518 break;
Alexis Hetu3412d872015-10-26 16:40:26 -0400519 case FORMAT_D32F:
John Bauman89401822014-05-06 15:04:28 -0400520 case FORMAT_D32F_LOCKABLE:
John Bauman66b8ab22014-05-06 15:57:45 -0400521 case FORMAT_D32FS8_TEXTURE:
522 case FORMAT_D32FS8_SHADOW:
Alexis Hetuab2dd502017-11-16 15:35:59 -0500523 c.y = Float4(0.0f);
524 c.z = Float4(0.0f);
525 c.w = Float4(1.0f);
John Bauman89401822014-05-06 15:04:28 -0400526 break;
527 default:
528 ASSERT(false);
529 }
530 }
531 }
Alexis Hetu1d01aa32015-09-29 11:50:05 -0400532
533 if((state.swizzleR != SWIZZLE_RED) ||
534 (state.swizzleG != SWIZZLE_GREEN) ||
535 (state.swizzleB != SWIZZLE_BLUE) ||
536 (state.swizzleA != SWIZZLE_ALPHA))
537 {
538 const Vector4f col(c);
539 applySwizzle(state.swizzleR, c.x, col);
540 applySwizzle(state.swizzleG, c.y, col);
541 applySwizzle(state.swizzleB, c.z, col);
542 applySwizzle(state.swizzleA, c.w, col);
543 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500544
545 return c;
John Bauman89401822014-05-06 15:04:28 -0400546 }
547
Nicolas Capens89a218b2017-11-07 13:05:20 -0500548 Vector4f SamplerCore::textureSize(Pointer<Byte> &texture, Float4 &lod)
Alexis Hetu9f7d5622016-06-02 17:47:38 -0400549 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500550 Vector4f size;
551
Alexis Hetu9f7d5622016-06-02 17:47:38 -0400552 for(int i = 0; i < 4; ++i)
553 {
Alexis Hetu95ac1872016-06-06 13:26:52 -0400554 Int baseLevel = *Pointer<Int>(texture + OFFSET(Texture, baseLevel));
555 Pointer<Byte> mipmap = texture + OFFSET(Texture, mipmap) + (As<Int>(Extract(lod, i)) + baseLevel) * sizeof(Mipmap);
Alexis Hetu9f7d5622016-06-02 17:47:38 -0400556 size.x = Insert(size.x, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, width)))), i);
557 size.y = Insert(size.y, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, height)))), i);
558 size.z = Insert(size.z, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, depth)))), i);
559 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500560
561 return size;
Alexis Hetu9f7d5622016-06-02 17:47:38 -0400562 }
563
John Bauman89401822014-05-06 15:04:28 -0400564 void SamplerCore::border(Short4 &mask, Float4 &coordinates)
565 {
566 Int4 border = As<Int4>(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f)));
Nicolas Capens33438a62017-09-27 11:47:35 -0400567 mask = As<Short4>(Int2(As<Int4>(PackSigned(border, border))));
John Bauman89401822014-05-06 15:04:28 -0400568 }
569
570 void SamplerCore::border(Int4 &mask, Float4 &coordinates)
571 {
572 mask = As<Int4>(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f)));
573 }
574
Nicolas Capens5989fab2016-02-15 10:31:49 -0500575 Short4 SamplerCore::offsetSample(Short4 &uvw, Pointer<Byte> &mipmap, int halfOffset, bool wrap, int count, Float &lod)
John Bauman89401822014-05-06 15:04:28 -0400576 {
Nicolas Capens5989fab2016-02-15 10:31:49 -0500577 Short4 offset = *Pointer<Short4>(mipmap + halfOffset);
578
579 if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
580 {
581 offset &= Short4(CmpNLE(Float4(lod), Float4(0.0f)));
582 }
583 else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR)
584 {
585 offset &= Short4(CmpLE(Float4(lod), Float4(0.0f)));
586 }
587
John Bauman89401822014-05-06 15:04:28 -0400588 if(wrap)
589 {
590 switch(count)
591 {
Nicolas Capens5989fab2016-02-15 10:31:49 -0500592 case -1: return uvw - offset;
John Bauman89401822014-05-06 15:04:28 -0400593 case 0: return uvw;
Nicolas Capens5989fab2016-02-15 10:31:49 -0500594 case +1: return uvw + offset;
595 case 2: return uvw + offset + offset;
John Bauman89401822014-05-06 15:04:28 -0400596 }
597 }
598 else // Clamp or mirror
599 {
600 switch(count)
601 {
Nicolas Capens5989fab2016-02-15 10:31:49 -0500602 case -1: return SubSat(As<UShort4>(uvw), As<UShort4>(offset));
John Bauman89401822014-05-06 15:04:28 -0400603 case 0: return uvw;
Nicolas Capens5989fab2016-02-15 10:31:49 -0500604 case +1: return AddSat(As<UShort4>(uvw), As<UShort4>(offset));
605 case 2: return AddSat(AddSat(As<UShort4>(uvw), As<UShort4>(offset)), As<UShort4>(offset));
John Bauman89401822014-05-06 15:04:28 -0400606 }
607 }
608
609 return uvw;
610 }
611
Nicolas Capens89a218b2017-11-07 13:05:20 -0500612 Vector4s SamplerCore::sampleFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400613 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500614 Vector4s c = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400615
Nicolas Capensa3c16e42016-06-15 16:45:53 -0400616 if(function == Fetch)
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400617 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500618 return c;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400619 }
John Bauman89401822014-05-06 15:04:28 -0400620
621 if(state.mipmapFilter > MIPMAP_POINT)
622 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500623 Vector4s cc = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
John Bauman89401822014-05-06 15:04:28 -0400624
625 lod *= Float(1 << 16);
626
627 UShort4 utri = UShort4(Float4(lod)); // FIXME: Optimize
628 Short4 stri = utri >> 1; // FIXME: Optimize
629
John Bauman19bac1e2014-05-06 15:23:49 -0400630 if(hasUnsignedTextureComponent(0)) cc.x = MulHigh(As<UShort4>(cc.x), utri); else cc.x = MulHigh(cc.x, stri);
631 if(hasUnsignedTextureComponent(1)) cc.y = MulHigh(As<UShort4>(cc.y), utri); else cc.y = MulHigh(cc.y, stri);
632 if(hasUnsignedTextureComponent(2)) cc.z = MulHigh(As<UShort4>(cc.z), utri); else cc.z = MulHigh(cc.z, stri);
633 if(hasUnsignedTextureComponent(3)) cc.w = MulHigh(As<UShort4>(cc.w), utri); else cc.w = MulHigh(cc.w, stri);
John Bauman89401822014-05-06 15:04:28 -0400634
635 utri = ~utri;
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400636 stri = Short4(0x7FFF) - stri;
John Bauman89401822014-05-06 15:04:28 -0400637
John Bauman19bac1e2014-05-06 15:23:49 -0400638 if(hasUnsignedTextureComponent(0)) c.x = MulHigh(As<UShort4>(c.x), utri); else c.x = MulHigh(c.x, stri);
639 if(hasUnsignedTextureComponent(1)) c.y = MulHigh(As<UShort4>(c.y), utri); else c.y = MulHigh(c.y, stri);
640 if(hasUnsignedTextureComponent(2)) c.z = MulHigh(As<UShort4>(c.z), utri); else c.z = MulHigh(c.z, stri);
641 if(hasUnsignedTextureComponent(3)) c.w = MulHigh(As<UShort4>(c.w), utri); else c.w = MulHigh(c.w, stri);
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500642
John Bauman19bac1e2014-05-06 15:23:49 -0400643 c.x += cc.x;
644 c.y += cc.y;
645 c.z += cc.z;
646 c.w += cc.w;
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500647
John Bauman19bac1e2014-05-06 15:23:49 -0400648 if(!hasUnsignedTextureComponent(0)) c.x += c.x;
649 if(!hasUnsignedTextureComponent(1)) c.y += c.y;
650 if(!hasUnsignedTextureComponent(2)) c.z += c.z;
651 if(!hasUnsignedTextureComponent(3)) c.w += c.w;
John Bauman89401822014-05-06 15:04:28 -0400652 }
653
654 Short4 borderMask;
655
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400656 if(state.addressingModeU == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -0400657 {
658 Short4 u0;
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500659
John Bauman89401822014-05-06 15:04:28 -0400660 border(u0, u);
661
662 borderMask = u0;
663 }
664
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400665 if(state.addressingModeV == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -0400666 {
667 Short4 v0;
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500668
John Bauman89401822014-05-06 15:04:28 -0400669 border(v0, v);
670
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400671 if(state.addressingModeU == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -0400672 {
673 borderMask &= v0;
674 }
675 else
676 {
677 borderMask = v0;
678 }
679 }
680
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500681 if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -0400682 {
683 Short4 s0;
684
685 border(s0, w);
686
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400687 if(state.addressingModeU == ADDRESSING_BORDER ||
688 state.addressingModeV == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -0400689 {
690 borderMask &= s0;
691 }
692 else
693 {
694 borderMask = s0;
695 }
696 }
697
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400698 if(state.addressingModeU == ADDRESSING_BORDER ||
699 state.addressingModeV == ADDRESSING_BORDER ||
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500700 (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D))
John Bauman89401822014-05-06 15:04:28 -0400701 {
702 Short4 b;
703
Tom Anderson69bc6e82017-03-20 11:54:29 -0700704 c.x = (borderMask & c.x) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[0])) >> (hasUnsignedTextureComponent(0) ? 0 : 1)));
705 c.y = (borderMask & c.y) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[1])) >> (hasUnsignedTextureComponent(1) ? 0 : 1)));
706 c.z = (borderMask & c.z) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[2])) >> (hasUnsignedTextureComponent(2) ? 0 : 1)));
707 c.w = (borderMask & c.w) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[3])) >> (hasUnsignedTextureComponent(3) ? 0 : 1)));
John Bauman89401822014-05-06 15:04:28 -0400708 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500709
710 return c;
John Bauman89401822014-05-06 15:04:28 -0400711 }
712
Nicolas Capens89a218b2017-11-07 13:05:20 -0500713 Vector4s SamplerCore::sampleAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400714 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500715 Vector4s c;
716
Nicolas Capensa3c16e42016-06-15 16:45:53 -0400717 if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
John Bauman89401822014-05-06 15:04:28 -0400718 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500719 c = sampleQuad(texture, u, v, w, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -0400720 }
721 else
722 {
723 Int a = RoundInt(anisotropy);
724
Alexis Hetu96517182015-04-15 10:30:23 -0400725 Vector4s cSum;
John Bauman89401822014-05-06 15:04:28 -0400726
Alexis Hetu90c7ad62016-06-27 11:50:40 -0400727 cSum.x = Short4(0);
728 cSum.y = Short4(0);
729 cSum.z = Short4(0);
730 cSum.w = Short4(0);
John Bauman89401822014-05-06 15:04:28 -0400731
732 Float4 A = *Pointer<Float4>(constants + OFFSET(Constants,uvWeight) + 16 * a);
733 Float4 B = *Pointer<Float4>(constants + OFFSET(Constants,uvStart) + 16 * a);
734 UShort4 cw = *Pointer<UShort4>(constants + OFFSET(Constants,cWeight) + 8 * a);
735 Short4 sw = Short4(cw >> 1);
736
737 Float4 du = uDelta;
738 Float4 dv = vDelta;
739
740 Float4 u0 = u + B * du;
741 Float4 v0 = v + B * dv;
742
743 du *= A;
744 dv *= A;
745
746 Int i = 0;
747
748 Do
749 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500750 c = sampleQuad(texture, u0, v0, w, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -0400751
752 u0 += du;
753 v0 += dv;
754
John Bauman19bac1e2014-05-06 15:23:49 -0400755 if(hasUnsignedTextureComponent(0)) cSum.x += As<Short4>(MulHigh(As<UShort4>(c.x), cw)); else cSum.x += MulHigh(c.x, sw);
756 if(hasUnsignedTextureComponent(1)) cSum.y += As<Short4>(MulHigh(As<UShort4>(c.y), cw)); else cSum.y += MulHigh(c.y, sw);
757 if(hasUnsignedTextureComponent(2)) cSum.z += As<Short4>(MulHigh(As<UShort4>(c.z), cw)); else cSum.z += MulHigh(c.z, sw);
758 if(hasUnsignedTextureComponent(3)) cSum.w += As<Short4>(MulHigh(As<UShort4>(c.w), cw)); else cSum.w += MulHigh(c.w, sw);
John Bauman89401822014-05-06 15:04:28 -0400759
760 i++;
761 }
762 Until(i >= a)
763
John Bauman19bac1e2014-05-06 15:23:49 -0400764 if(hasUnsignedTextureComponent(0)) c.x = cSum.x; else c.x = AddSat(cSum.x, cSum.x);
765 if(hasUnsignedTextureComponent(1)) c.y = cSum.y; else c.y = AddSat(cSum.y, cSum.y);
766 if(hasUnsignedTextureComponent(2)) c.z = cSum.z; else c.z = AddSat(cSum.z, cSum.z);
767 if(hasUnsignedTextureComponent(3)) c.w = cSum.w; else c.w = AddSat(cSum.w, cSum.w);
John Bauman89401822014-05-06 15:04:28 -0400768 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500769
770 return c;
John Bauman89401822014-05-06 15:04:28 -0400771 }
772
Nicolas Capens89a218b2017-11-07 13:05:20 -0500773 Vector4s SamplerCore::sampleQuad(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400774 {
Alexis Hetuc8b97852016-02-04 21:15:03 -0500775 if(state.textureType != TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -0400776 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500777 return sampleQuad2D(texture, u, v, w, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -0400778 }
779 else
780 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500781 return sample3D(texture, u, v, w, offset, lod, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -0400782 }
783 }
784
Nicolas Capens89a218b2017-11-07 13:05:20 -0500785 Vector4s SamplerCore::sampleQuad2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400786 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500787 Vector4s c;
788
John Bauman89401822014-05-06 15:04:28 -0400789 int componentCount = textureComponentCount();
790 bool gather = state.textureFilter == FILTER_GATHER;
791
792 Pointer<Byte> mipmap;
793 Pointer<Byte> buffer[4];
794
795 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD);
796
Nicolas Capensa3c16e42016-06-15 16:45:53 -0400797 bool texelFetch = (function == Fetch);
John Bauman89401822014-05-06 15:04:28 -0400798
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400799 Short4 uuuu = texelFetch ? Short4(As<Int4>(u)) : address(u, state.addressingModeU, mipmap);
800 Short4 vvvv = texelFetch ? Short4(As<Int4>(v)) : address(v, state.addressingModeV, mipmap);
801 Short4 wwww = texelFetch ? Short4(As<Int4>(w)) : address(w, state.addressingModeW, mipmap);
802
803 if(state.textureFilter == FILTER_POINT || texelFetch)
John Bauman89401822014-05-06 15:04:28 -0400804 {
Nicolas Capens5790c952017-08-01 17:00:36 -0400805 c = sampleTexel(uuuu, vvvv, wwww, offset, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -0400806 }
807 else
808 {
Nicolas Capens5989fab2016-02-15 10:31:49 -0500809 Short4 uuuu0 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 0 : -1, lod);
810 Short4 vvvv0 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 0 : -1, lod);
811 Short4 uuuu1 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 2 : +1, lod);
812 Short4 vvvv1 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 2 : +1, lod);
John Bauman89401822014-05-06 15:04:28 -0400813
Nicolas Capens5790c952017-08-01 17:00:36 -0400814 Vector4s c0 = sampleTexel(uuuu0, vvvv0, wwww, offset, mipmap, buffer, function);
815 Vector4s c1 = sampleTexel(uuuu1, vvvv0, wwww, offset, mipmap, buffer, function);
816 Vector4s c2 = sampleTexel(uuuu0, vvvv1, wwww, offset, mipmap, buffer, function);
817 Vector4s c3 = sampleTexel(uuuu1, vvvv1, wwww, offset, mipmap, buffer, function);
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500818
John Bauman89401822014-05-06 15:04:28 -0400819 if(!gather) // Blend
820 {
821 // Fractions
Nicolas Capens77980512016-12-02 14:22:32 -0500822 UShort4 f0u = As<UShort4>(uuuu0) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,width));
823 UShort4 f0v = As<UShort4>(vvvv0) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,height));
John Bauman89401822014-05-06 15:04:28 -0400824
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400825 UShort4 f1u = ~f0u;
826 UShort4 f1v = ~f0v;
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500827
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400828 UShort4 f0u0v = MulHigh(f0u, f0v);
829 UShort4 f1u0v = MulHigh(f1u, f0v);
830 UShort4 f0u1v = MulHigh(f0u, f1v);
831 UShort4 f1u1v = MulHigh(f1u, f1v);
John Bauman89401822014-05-06 15:04:28 -0400832
833 // Signed fractions
834 Short4 f1u1vs;
835 Short4 f0u1vs;
836 Short4 f1u0vs;
837 Short4 f0u0vs;
838
839 if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3))
840 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400841 f1u1vs = f1u1v >> 1;
842 f0u1vs = f0u1v >> 1;
843 f1u0vs = f1u0v >> 1;
844 f0u0vs = f0u0v >> 1;
John Bauman89401822014-05-06 15:04:28 -0400845 }
846
847 // Bilinear interpolation
848 if(componentCount >= 1)
849 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -0400850 if(has16bitTextureComponents() && hasUnsignedTextureComponent(0))
John Bauman89401822014-05-06 15:04:28 -0400851 {
John Bauman19bac1e2014-05-06 15:23:49 -0400852 c0.x = As<UShort4>(c0.x) - MulHigh(As<UShort4>(c0.x), f0u) + MulHigh(As<UShort4>(c1.x), f0u);
853 c2.x = As<UShort4>(c2.x) - MulHigh(As<UShort4>(c2.x), f0u) + MulHigh(As<UShort4>(c3.x), f0u);
854 c.x = As<UShort4>(c0.x) - MulHigh(As<UShort4>(c0.x), f0v) + MulHigh(As<UShort4>(c2.x), f0v);
John Bauman89401822014-05-06 15:04:28 -0400855 }
856 else
857 {
858 if(hasUnsignedTextureComponent(0))
859 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400860 c0.x = MulHigh(As<UShort4>(c0.x), f1u1v);
861 c1.x = MulHigh(As<UShort4>(c1.x), f0u1v);
862 c2.x = MulHigh(As<UShort4>(c2.x), f1u0v);
863 c3.x = MulHigh(As<UShort4>(c3.x), f0u0v);
John Bauman89401822014-05-06 15:04:28 -0400864 }
865 else
866 {
John Bauman19bac1e2014-05-06 15:23:49 -0400867 c0.x = MulHigh(c0.x, f1u1vs);
868 c1.x = MulHigh(c1.x, f0u1vs);
869 c2.x = MulHigh(c2.x, f1u0vs);
870 c3.x = MulHigh(c3.x, f0u0vs);
John Bauman89401822014-05-06 15:04:28 -0400871 }
872
John Bauman19bac1e2014-05-06 15:23:49 -0400873 c.x = (c0.x + c1.x) + (c2.x + c3.x);
874 if(!hasUnsignedTextureComponent(0)) c.x = AddSat(c.x, c.x); // Correct for signed fractions
John Bauman89401822014-05-06 15:04:28 -0400875 }
876 }
877
878 if(componentCount >= 2)
879 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -0400880 if(has16bitTextureComponents() && hasUnsignedTextureComponent(1))
John Bauman89401822014-05-06 15:04:28 -0400881 {
John Bauman19bac1e2014-05-06 15:23:49 -0400882 c0.y = As<UShort4>(c0.y) - MulHigh(As<UShort4>(c0.y), f0u) + MulHigh(As<UShort4>(c1.y), f0u);
883 c2.y = As<UShort4>(c2.y) - MulHigh(As<UShort4>(c2.y), f0u) + MulHigh(As<UShort4>(c3.y), f0u);
884 c.y = As<UShort4>(c0.y) - MulHigh(As<UShort4>(c0.y), f0v) + MulHigh(As<UShort4>(c2.y), f0v);
John Bauman89401822014-05-06 15:04:28 -0400885 }
886 else
887 {
888 if(hasUnsignedTextureComponent(1))
889 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400890 c0.y = MulHigh(As<UShort4>(c0.y), f1u1v);
891 c1.y = MulHigh(As<UShort4>(c1.y), f0u1v);
892 c2.y = MulHigh(As<UShort4>(c2.y), f1u0v);
893 c3.y = MulHigh(As<UShort4>(c3.y), f0u0v);
John Bauman89401822014-05-06 15:04:28 -0400894 }
895 else
896 {
John Bauman19bac1e2014-05-06 15:23:49 -0400897 c0.y = MulHigh(c0.y, f1u1vs);
898 c1.y = MulHigh(c1.y, f0u1vs);
899 c2.y = MulHigh(c2.y, f1u0vs);
900 c3.y = MulHigh(c3.y, f0u0vs);
John Bauman89401822014-05-06 15:04:28 -0400901 }
902
John Bauman19bac1e2014-05-06 15:23:49 -0400903 c.y = (c0.y + c1.y) + (c2.y + c3.y);
904 if(!hasUnsignedTextureComponent(1)) c.y = AddSat(c.y, c.y); // Correct for signed fractions
John Bauman89401822014-05-06 15:04:28 -0400905 }
906 }
907
908 if(componentCount >= 3)
909 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -0400910 if(has16bitTextureComponents() && hasUnsignedTextureComponent(2))
John Bauman89401822014-05-06 15:04:28 -0400911 {
John Bauman19bac1e2014-05-06 15:23:49 -0400912 c0.z = As<UShort4>(c0.z) - MulHigh(As<UShort4>(c0.z), f0u) + MulHigh(As<UShort4>(c1.z), f0u);
913 c2.z = As<UShort4>(c2.z) - MulHigh(As<UShort4>(c2.z), f0u) + MulHigh(As<UShort4>(c3.z), f0u);
914 c.z = As<UShort4>(c0.z) - MulHigh(As<UShort4>(c0.z), f0v) + MulHigh(As<UShort4>(c2.z), f0v);
John Bauman89401822014-05-06 15:04:28 -0400915 }
916 else
917 {
918 if(hasUnsignedTextureComponent(2))
919 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400920 c0.z = MulHigh(As<UShort4>(c0.z), f1u1v);
921 c1.z = MulHigh(As<UShort4>(c1.z), f0u1v);
922 c2.z = MulHigh(As<UShort4>(c2.z), f1u0v);
923 c3.z = MulHigh(As<UShort4>(c3.z), f0u0v);
John Bauman89401822014-05-06 15:04:28 -0400924 }
925 else
926 {
John Bauman19bac1e2014-05-06 15:23:49 -0400927 c0.z = MulHigh(c0.z, f1u1vs);
928 c1.z = MulHigh(c1.z, f0u1vs);
929 c2.z = MulHigh(c2.z, f1u0vs);
930 c3.z = MulHigh(c3.z, f0u0vs);
John Bauman89401822014-05-06 15:04:28 -0400931 }
932
John Bauman19bac1e2014-05-06 15:23:49 -0400933 c.z = (c0.z + c1.z) + (c2.z + c3.z);
934 if(!hasUnsignedTextureComponent(2)) c.z = AddSat(c.z, c.z); // Correct for signed fractions
John Bauman89401822014-05-06 15:04:28 -0400935 }
936 }
937
938 if(componentCount >= 4)
939 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -0400940 if(has16bitTextureComponents() && hasUnsignedTextureComponent(3))
John Bauman89401822014-05-06 15:04:28 -0400941 {
John Bauman19bac1e2014-05-06 15:23:49 -0400942 c0.w = As<UShort4>(c0.w) - MulHigh(As<UShort4>(c0.w), f0u) + MulHigh(As<UShort4>(c1.w), f0u);
943 c2.w = As<UShort4>(c2.w) - MulHigh(As<UShort4>(c2.w), f0u) + MulHigh(As<UShort4>(c3.w), f0u);
944 c.w = As<UShort4>(c0.w) - MulHigh(As<UShort4>(c0.w), f0v) + MulHigh(As<UShort4>(c2.w), f0v);
John Bauman89401822014-05-06 15:04:28 -0400945 }
946 else
947 {
948 if(hasUnsignedTextureComponent(3))
949 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -0400950 c0.w = MulHigh(As<UShort4>(c0.w), f1u1v);
951 c1.w = MulHigh(As<UShort4>(c1.w), f0u1v);
952 c2.w = MulHigh(As<UShort4>(c2.w), f1u0v);
953 c3.w = MulHigh(As<UShort4>(c3.w), f0u0v);
John Bauman89401822014-05-06 15:04:28 -0400954 }
955 else
956 {
John Bauman19bac1e2014-05-06 15:23:49 -0400957 c0.w = MulHigh(c0.w, f1u1vs);
958 c1.w = MulHigh(c1.w, f0u1vs);
959 c2.w = MulHigh(c2.w, f1u0vs);
960 c3.w = MulHigh(c3.w, f0u0vs);
John Bauman89401822014-05-06 15:04:28 -0400961 }
962
John Bauman19bac1e2014-05-06 15:23:49 -0400963 c.w = (c0.w + c1.w) + (c2.w + c3.w);
964 if(!hasUnsignedTextureComponent(3)) c.w = AddSat(c.w, c.w); // Correct for signed fractions
John Bauman89401822014-05-06 15:04:28 -0400965 }
966 }
967 }
968 else
969 {
John Bauman19bac1e2014-05-06 15:23:49 -0400970 c.x = c1.x;
971 c.y = c2.x;
972 c.z = c3.x;
973 c.w = c0.x;
John Bauman89401822014-05-06 15:04:28 -0400974 }
975 }
Nicolas Capens89a218b2017-11-07 13:05:20 -0500976
977 return c;
John Bauman89401822014-05-06 15:04:28 -0400978 }
979
Nicolas Capens89a218b2017-11-07 13:05:20 -0500980 Vector4s SamplerCore::sample3D(Pointer<Byte> &texture, Float4 &u_, Float4 &v_, Float4 &w_, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -0400981 {
Nicolas Capens89a218b2017-11-07 13:05:20 -0500982 Vector4s c_;
983
John Bauman89401822014-05-06 15:04:28 -0400984 int componentCount = textureComponentCount();
985
986 Pointer<Byte> mipmap;
987 Pointer<Byte> buffer[4];
988 Int face[4];
Alexis Hetu3b96fa82016-02-04 21:15:03 -0500989
John Bauman89401822014-05-06 15:04:28 -0400990 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD);
991
Nicolas Capensa3c16e42016-06-15 16:45:53 -0400992 bool texelFetch = (function == Fetch);
John Bauman89401822014-05-06 15:04:28 -0400993
Meng-Lin Wu2fce5822016-06-07 16:15:12 -0400994 Short4 uuuu = texelFetch ? Short4(As<Int4>(u_)) : address(u_, state.addressingModeU, mipmap);
995 Short4 vvvv = texelFetch ? Short4(As<Int4>(v_)) : address(v_, state.addressingModeV, mipmap);
996 Short4 wwww = texelFetch ? Short4(As<Int4>(w_)) : address(w_, state.addressingModeW, mipmap);
997
998 if(state.textureFilter == FILTER_POINT || texelFetch)
John Bauman89401822014-05-06 15:04:28 -0400999 {
Nicolas Capens5790c952017-08-01 17:00:36 -04001000 c_ = sampleTexel(uuuu, vvvv, wwww, offset, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001001 }
1002 else
1003 {
Alexis Hetu96517182015-04-15 10:30:23 -04001004 Vector4s c[2][2][2];
John Bauman89401822014-05-06 15:04:28 -04001005
1006 Short4 u[2][2][2];
1007 Short4 v[2][2][2];
1008 Short4 s[2][2][2];
1009
1010 for(int i = 0; i < 2; i++)
1011 {
1012 for(int j = 0; j < 2; j++)
1013 {
1014 for(int k = 0; k < 2; k++)
1015 {
Nicolas Capens5989fab2016-02-15 10:31:49 -05001016 u[i][j][k] = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, i * 2 - 1, lod);
1017 v[i][j][k] = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, j * 2 - 1, lod);
1018 s[i][j][k] = offsetSample(wwww, mipmap, OFFSET(Mipmap,wHalf), state.addressingModeW == ADDRESSING_WRAP, k * 2 - 1, lod);
John Bauman89401822014-05-06 15:04:28 -04001019 }
1020 }
1021 }
1022
John Bauman89401822014-05-06 15:04:28 -04001023 // Fractions
Nicolas Capens77980512016-12-02 14:22:32 -05001024 UShort4 f0u = As<UShort4>(u[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,width));
1025 UShort4 f0v = As<UShort4>(v[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,height));
1026 UShort4 f0s = As<UShort4>(s[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,depth));
John Bauman89401822014-05-06 15:04:28 -04001027
Nicolas Capensdf08bd02015-03-29 11:19:59 -04001028 UShort4 f1u = ~f0u;
1029 UShort4 f1v = ~f0v;
1030 UShort4 f1s = ~f0s;
John Bauman89401822014-05-06 15:04:28 -04001031
Nicolas Capens77980512016-12-02 14:22:32 -05001032 UShort4 f[2][2][2];
1033 Short4 fs[2][2][2];
1034
Nicolas Capensdf08bd02015-03-29 11:19:59 -04001035 f[1][1][1] = MulHigh(f1u, f1v);
1036 f[0][1][1] = MulHigh(f0u, f1v);
1037 f[1][0][1] = MulHigh(f1u, f0v);
1038 f[0][0][1] = MulHigh(f0u, f0v);
1039 f[1][1][0] = MulHigh(f1u, f1v);
1040 f[0][1][0] = MulHigh(f0u, f1v);
1041 f[1][0][0] = MulHigh(f1u, f0v);
1042 f[0][0][0] = MulHigh(f0u, f0v);
John Bauman89401822014-05-06 15:04:28 -04001043
Nicolas Capensdf08bd02015-03-29 11:19:59 -04001044 f[1][1][1] = MulHigh(f[1][1][1], f1s);
1045 f[0][1][1] = MulHigh(f[0][1][1], f1s);
1046 f[1][0][1] = MulHigh(f[1][0][1], f1s);
1047 f[0][0][1] = MulHigh(f[0][0][1], f1s);
1048 f[1][1][0] = MulHigh(f[1][1][0], f0s);
1049 f[0][1][0] = MulHigh(f[0][1][0], f0s);
1050 f[1][0][0] = MulHigh(f[1][0][0], f0s);
1051 f[0][0][0] = MulHigh(f[0][0][0], f0s);
John Bauman89401822014-05-06 15:04:28 -04001052
1053 // Signed fractions
1054 if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3))
1055 {
Nicolas Capensdf08bd02015-03-29 11:19:59 -04001056 fs[0][0][0] = f[0][0][0] >> 1;
1057 fs[0][0][1] = f[0][0][1] >> 1;
1058 fs[0][1][0] = f[0][1][0] >> 1;
1059 fs[0][1][1] = f[0][1][1] >> 1;
1060 fs[1][0][0] = f[1][0][0] >> 1;
1061 fs[1][0][1] = f[1][0][1] >> 1;
1062 fs[1][1][0] = f[1][1][0] >> 1;
1063 fs[1][1][1] = f[1][1][1] >> 1;
John Bauman89401822014-05-06 15:04:28 -04001064 }
1065
1066 for(int i = 0; i < 2; i++)
1067 {
1068 for(int j = 0; j < 2; j++)
1069 {
1070 for(int k = 0; k < 2; k++)
1071 {
Nicolas Capens5790c952017-08-01 17:00:36 -04001072 c[i][j][k] = sampleTexel(u[i][j][k], v[i][j][k], s[i][j][k], offset, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001073
Alexis Hetu0085c442015-06-12 15:19:20 -04001074 if(componentCount >= 1) { if(hasUnsignedTextureComponent(0)) c[i][j][k].x = MulHigh(As<UShort4>(c[i][j][k].x), f[1 - i][1 - j][1 - k]); else c[i][j][k].x = MulHigh(c[i][j][k].x, fs[1 - i][1 - j][1 - k]); }
1075 if(componentCount >= 2) { if(hasUnsignedTextureComponent(1)) c[i][j][k].y = MulHigh(As<UShort4>(c[i][j][k].y), f[1 - i][1 - j][1 - k]); else c[i][j][k].y = MulHigh(c[i][j][k].y, fs[1 - i][1 - j][1 - k]); }
1076 if(componentCount >= 3) { if(hasUnsignedTextureComponent(2)) c[i][j][k].z = MulHigh(As<UShort4>(c[i][j][k].z), f[1 - i][1 - j][1 - k]); else c[i][j][k].z = MulHigh(c[i][j][k].z, fs[1 - i][1 - j][1 - k]); }
1077 if(componentCount >= 4) { if(hasUnsignedTextureComponent(3)) c[i][j][k].w = MulHigh(As<UShort4>(c[i][j][k].w), f[1 - i][1 - j][1 - k]); else c[i][j][k].w = MulHigh(c[i][j][k].w, fs[1 - i][1 - j][1 - k]); }
John Bauman89401822014-05-06 15:04:28 -04001078
1079 if(i != 0 || j != 0 || k != 0)
1080 {
John Bauman19bac1e2014-05-06 15:23:49 -04001081 if(componentCount >= 1) c[0][0][0].x += c[i][j][k].x;
1082 if(componentCount >= 2) c[0][0][0].y += c[i][j][k].y;
1083 if(componentCount >= 3) c[0][0][0].z += c[i][j][k].z;
1084 if(componentCount >= 4) c[0][0][0].w += c[i][j][k].w;
John Bauman89401822014-05-06 15:04:28 -04001085 }
1086 }
1087 }
1088 }
1089
John Bauman19bac1e2014-05-06 15:23:49 -04001090 if(componentCount >= 1) c_.x = c[0][0][0].x;
1091 if(componentCount >= 2) c_.y = c[0][0][0].y;
1092 if(componentCount >= 3) c_.z = c[0][0][0].z;
1093 if(componentCount >= 4) c_.w = c[0][0][0].w;
John Bauman89401822014-05-06 15:04:28 -04001094
1095 // Correct for signed fractions
John Bauman19bac1e2014-05-06 15:23:49 -04001096 if(componentCount >= 1) if(!hasUnsignedTextureComponent(0)) c_.x = AddSat(c_.x, c_.x);
1097 if(componentCount >= 2) if(!hasUnsignedTextureComponent(1)) c_.y = AddSat(c_.y, c_.y);
1098 if(componentCount >= 3) if(!hasUnsignedTextureComponent(2)) c_.z = AddSat(c_.z, c_.z);
1099 if(componentCount >= 4) if(!hasUnsignedTextureComponent(3)) c_.w = AddSat(c_.w, c_.w);
John Bauman89401822014-05-06 15:04:28 -04001100 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001101
1102 return c_;
John Bauman89401822014-05-06 15:04:28 -04001103 }
1104
Nicolas Capensa0b57832017-11-07 13:07:53 -05001105 Vector4f SamplerCore::sampleFloatFilter(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001106 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001107 Vector4f c = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, false, function);
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001108
1109 if(function == Fetch)
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001110 {
Nicolas Capens89a218b2017-11-07 13:05:20 -05001111 return c;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001112 }
John Bauman89401822014-05-06 15:04:28 -04001113
1114 if(state.mipmapFilter > MIPMAP_POINT)
1115 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001116 Vector4f cc = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, true, function);
John Bauman89401822014-05-06 15:04:28 -04001117
John Bauman19bac1e2014-05-06 15:23:49 -04001118 Float4 lod4 = Float4(Frac(lod));
John Bauman89401822014-05-06 15:04:28 -04001119
John Bauman19bac1e2014-05-06 15:23:49 -04001120 c.x = (cc.x - c.x) * lod4 + c.x;
1121 c.y = (cc.y - c.y) * lod4 + c.y;
1122 c.z = (cc.z - c.z) * lod4 + c.z;
1123 c.w = (cc.w - c.w) * lod4 + c.w;
John Bauman89401822014-05-06 15:04:28 -04001124 }
1125
1126 Int4 borderMask;
1127
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001128 if(state.addressingModeU == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -04001129 {
1130 Int4 u0;
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001131
John Bauman89401822014-05-06 15:04:28 -04001132 border(u0, u);
1133
1134 borderMask = u0;
1135 }
1136
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001137 if(state.addressingModeV == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -04001138 {
1139 Int4 v0;
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001140
John Bauman89401822014-05-06 15:04:28 -04001141 border(v0, v);
1142
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001143 if(state.addressingModeU == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -04001144 {
1145 borderMask &= v0;
1146 }
1147 else
1148 {
1149 borderMask = v0;
1150 }
1151 }
1152
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001153 if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -04001154 {
1155 Int4 s0;
1156
1157 border(s0, w);
1158
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001159 if(state.addressingModeU == ADDRESSING_BORDER ||
1160 state.addressingModeV == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -04001161 {
1162 borderMask &= s0;
1163 }
1164 else
1165 {
1166 borderMask = s0;
1167 }
1168 }
1169
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001170 if(state.addressingModeU == ADDRESSING_BORDER ||
1171 state.addressingModeV == ADDRESSING_BORDER ||
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001172 (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D))
John Bauman89401822014-05-06 15:04:28 -04001173 {
1174 Int4 b;
1175
Tom Anderson69bc6e82017-03-20 11:54:29 -07001176 c.x = As<Float4>((borderMask & As<Int4>(c.x)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[0]))));
1177 c.y = As<Float4>((borderMask & As<Int4>(c.y)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[1]))));
1178 c.z = As<Float4>((borderMask & As<Int4>(c.z)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[2]))));
1179 c.w = As<Float4>((borderMask & As<Int4>(c.w)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[3]))));
John Bauman89401822014-05-06 15:04:28 -04001180 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001181
1182 return c;
John Bauman89401822014-05-06 15:04:28 -04001183 }
1184
Nicolas Capensa0b57832017-11-07 13:07:53 -05001185 Vector4f SamplerCore::sampleFloatAniso(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001186 {
Nicolas Capens89a218b2017-11-07 13:05:20 -05001187 Vector4f c;
1188
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001189 if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch)
John Bauman89401822014-05-06 15:04:28 -04001190 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001191 c = sampleFloat(texture, u, v, w, q, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -04001192 }
1193 else
1194 {
1195 Int a = RoundInt(anisotropy);
1196
John Bauman19bac1e2014-05-06 15:23:49 -04001197 Vector4f cSum;
John Bauman89401822014-05-06 15:04:28 -04001198
John Bauman19bac1e2014-05-06 15:23:49 -04001199 cSum.x = Float4(0.0f);
1200 cSum.y = Float4(0.0f);
1201 cSum.z = Float4(0.0f);
1202 cSum.w = Float4(0.0f);
John Bauman89401822014-05-06 15:04:28 -04001203
1204 Float4 A = *Pointer<Float4>(constants + OFFSET(Constants,uvWeight) + 16 * a);
1205 Float4 B = *Pointer<Float4>(constants + OFFSET(Constants,uvStart) + 16 * a);
1206
1207 Float4 du = uDelta;
1208 Float4 dv = vDelta;
1209
1210 Float4 u0 = u + B * du;
1211 Float4 v0 = v + B * dv;
1212
1213 du *= A;
1214 dv *= A;
1215
1216 Int i = 0;
1217
1218 Do
1219 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001220 c = sampleFloat(texture, u0, v0, w, q, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -04001221
1222 u0 += du;
1223 v0 += dv;
1224
John Bauman19bac1e2014-05-06 15:23:49 -04001225 cSum.x += c.x * A;
1226 cSum.y += c.y * A;
1227 cSum.z += c.z * A;
1228 cSum.w += c.w * A;
John Bauman89401822014-05-06 15:04:28 -04001229
1230 i++;
1231 }
1232 Until(i >= a)
1233
John Bauman19bac1e2014-05-06 15:23:49 -04001234 c.x = cSum.x;
1235 c.y = cSum.y;
1236 c.z = cSum.z;
1237 c.w = cSum.w;
John Bauman89401822014-05-06 15:04:28 -04001238 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001239
1240 return c;
John Bauman89401822014-05-06 15:04:28 -04001241 }
1242
Nicolas Capensa0b57832017-11-07 13:07:53 -05001243 Vector4f SamplerCore::sampleFloat(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001244 {
Alexis Hetuc8b97852016-02-04 21:15:03 -05001245 if(state.textureType != TEXTURE_3D)
John Bauman89401822014-05-06 15:04:28 -04001246 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001247 return sampleFloat2D(texture, u, v, w, q, offset, lod, face, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -04001248 }
1249 else
1250 {
Nicolas Capens89a218b2017-11-07 13:05:20 -05001251 return sampleFloat3D(texture, u, v, w, offset, lod, secondLOD, function);
John Bauman89401822014-05-06 15:04:28 -04001252 }
1253 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001254
Nicolas Capensa0b57832017-11-07 13:07:53 -05001255 Vector4f SamplerCore::sampleFloat2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001256 {
Nicolas Capens89a218b2017-11-07 13:05:20 -05001257 Vector4f c;
1258
John Bauman89401822014-05-06 15:04:28 -04001259 int componentCount = textureComponentCount();
1260 bool gather = state.textureFilter == FILTER_GATHER;
1261
1262 Pointer<Byte> mipmap;
1263 Pointer<Byte> buffer[4];
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001264
John Bauman89401822014-05-06 15:04:28 -04001265 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD);
1266
Alexis Hetu75a61852017-07-14 14:17:14 -04001267 Int4 x0, x1, y0, y1, z0;
1268 Float4 fu, fv;
1269 Int4 filter = computeFilterOffset(lod);
Alexis Hetu75a61852017-07-14 14:17:14 -04001270 address(u, x0, x1, fu, mipmap, offset.x, filter, OFFSET(Mipmap, width), state.addressingModeU, function);
Nicolas Capensf8b827e2017-11-27 15:25:05 -05001271 address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function);
1272 address(w, z0, z0, fv, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function);
John Bauman89401822014-05-06 15:04:28 -04001273
Alexis Hetu75a61852017-07-14 14:17:14 -04001274 Int4 pitchP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, pitchP), 16);
1275 y0 *= pitchP;
1276 if(hasThirdCoordinate())
John Bauman89401822014-05-06 15:04:28 -04001277 {
Alexis Hetu75a61852017-07-14 14:17:14 -04001278 Int4 sliceP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, sliceP), 16);
1279 z0 *= sliceP;
1280 }
1281
1282 if(state.textureFilter == FILTER_POINT || (function == Fetch))
1283 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001284 c = sampleTexel(x0, y0, z0, q, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001285 }
1286 else
1287 {
Alexis Hetu75a61852017-07-14 14:17:14 -04001288 y1 *= pitchP;
John Bauman89401822014-05-06 15:04:28 -04001289
Nicolas Capensa0b57832017-11-07 13:07:53 -05001290 Vector4f c0 = sampleTexel(x0, y0, z0, q, mipmap, buffer, function);
1291 Vector4f c1 = sampleTexel(x1, y0, z0, q, mipmap, buffer, function);
1292 Vector4f c2 = sampleTexel(x0, y1, z0, q, mipmap, buffer, function);
1293 Vector4f c3 = sampleTexel(x1, y1, z0, q, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001294
1295 if(!gather) // Blend
1296 {
John Bauman19bac1e2014-05-06 15:23:49 -04001297 if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x);
1298 if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y);
1299 if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z);
1300 if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w);
John Bauman89401822014-05-06 15:04:28 -04001301
John Bauman19bac1e2014-05-06 15:23:49 -04001302 if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x);
1303 if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y);
1304 if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z);
1305 if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w);
John Bauman89401822014-05-06 15:04:28 -04001306
John Bauman19bac1e2014-05-06 15:23:49 -04001307 if(componentCount >= 1) c.x = c0.x + fv * (c2.x - c0.x);
1308 if(componentCount >= 2) c.y = c0.y + fv * (c2.y - c0.y);
1309 if(componentCount >= 3) c.z = c0.z + fv * (c2.z - c0.z);
1310 if(componentCount >= 4) c.w = c0.w + fv * (c2.w - c0.w);
John Bauman89401822014-05-06 15:04:28 -04001311 }
1312 else
1313 {
John Bauman19bac1e2014-05-06 15:23:49 -04001314 c.x = c1.x;
1315 c.y = c2.x;
1316 c.z = c3.x;
1317 c.w = c0.x;
John Bauman89401822014-05-06 15:04:28 -04001318 }
1319 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001320
1321 return c;
John Bauman89401822014-05-06 15:04:28 -04001322 }
1323
Nicolas Capens89a218b2017-11-07 13:05:20 -05001324 Vector4f SamplerCore::sampleFloat3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001325 {
Nicolas Capens89a218b2017-11-07 13:05:20 -05001326 Vector4f c;
1327
John Bauman89401822014-05-06 15:04:28 -04001328 int componentCount = textureComponentCount();
1329
1330 Pointer<Byte> mipmap;
1331 Pointer<Byte> buffer[4];
1332 Int face[4];
1333
1334 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD);
1335
Alexis Hetu75a61852017-07-14 14:17:14 -04001336 Int4 x0, x1, y0, y1, z0, z1;
1337 Float4 fu, fv, fw;
1338 Int4 filter = computeFilterOffset(lod);
1339 address(u, x0, x1, fu, mipmap, offset.x, filter, OFFSET(Mipmap, width), state.addressingModeU, function);
1340 address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function);
1341 address(w, z0, z1, fw, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function);
John Bauman89401822014-05-06 15:04:28 -04001342
Alexis Hetu75a61852017-07-14 14:17:14 -04001343 Int4 pitchP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, pitchP), 16);
1344 Int4 sliceP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, sliceP), 16);
1345 y0 *= pitchP;
1346 z0 *= sliceP;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001347
Alexis Hetu75a61852017-07-14 14:17:14 -04001348 if(state.textureFilter == FILTER_POINT || (function == Fetch))
John Bauman89401822014-05-06 15:04:28 -04001349 {
Nicolas Capens5790c952017-08-01 17:00:36 -04001350 c = sampleTexel(x0, y0, z0, w, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001351 }
1352 else
1353 {
Alexis Hetu75a61852017-07-14 14:17:14 -04001354 y1 *= pitchP;
1355 z1 *= sliceP;
John Bauman89401822014-05-06 15:04:28 -04001356
Nicolas Capens5790c952017-08-01 17:00:36 -04001357 Vector4f c0 = sampleTexel(x0, y0, z0, w, mipmap, buffer, function);
1358 Vector4f c1 = sampleTexel(x1, y0, z0, w, mipmap, buffer, function);
1359 Vector4f c2 = sampleTexel(x0, y1, z0, w, mipmap, buffer, function);
1360 Vector4f c3 = sampleTexel(x1, y1, z0, w, mipmap, buffer, function);
1361 Vector4f c4 = sampleTexel(x0, y0, z1, w, mipmap, buffer, function);
1362 Vector4f c5 = sampleTexel(x1, y0, z1, w, mipmap, buffer, function);
1363 Vector4f c6 = sampleTexel(x0, y1, z1, w, mipmap, buffer, function);
1364 Vector4f c7 = sampleTexel(x1, y1, z1, w, mipmap, buffer, function);
John Bauman89401822014-05-06 15:04:28 -04001365
1366 // Blend first slice
John Bauman19bac1e2014-05-06 15:23:49 -04001367 if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x);
1368 if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y);
1369 if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z);
1370 if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w);
John Bauman89401822014-05-06 15:04:28 -04001371
John Bauman19bac1e2014-05-06 15:23:49 -04001372 if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x);
1373 if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y);
1374 if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z);
1375 if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w);
John Bauman89401822014-05-06 15:04:28 -04001376
John Bauman19bac1e2014-05-06 15:23:49 -04001377 if(componentCount >= 1) c0.x = c0.x + fv * (c2.x - c0.x);
1378 if(componentCount >= 2) c0.y = c0.y + fv * (c2.y - c0.y);
1379 if(componentCount >= 3) c0.z = c0.z + fv * (c2.z - c0.z);
1380 if(componentCount >= 4) c0.w = c0.w + fv * (c2.w - c0.w);
John Bauman89401822014-05-06 15:04:28 -04001381
1382 // Blend second slice
John Bauman19bac1e2014-05-06 15:23:49 -04001383 if(componentCount >= 1) c4.x = c4.x + fu * (c5.x - c4.x);
1384 if(componentCount >= 2) c4.y = c4.y + fu * (c5.y - c4.y);
1385 if(componentCount >= 3) c4.z = c4.z + fu * (c5.z - c4.z);
1386 if(componentCount >= 4) c4.w = c4.w + fu * (c5.w - c4.w);
John Bauman89401822014-05-06 15:04:28 -04001387
John Bauman19bac1e2014-05-06 15:23:49 -04001388 if(componentCount >= 1) c6.x = c6.x + fu * (c7.x - c6.x);
1389 if(componentCount >= 2) c6.y = c6.y + fu * (c7.y - c6.y);
1390 if(componentCount >= 3) c6.z = c6.z + fu * (c7.z - c6.z);
1391 if(componentCount >= 4) c6.w = c6.w + fu * (c7.w - c6.w);
John Bauman89401822014-05-06 15:04:28 -04001392
John Bauman19bac1e2014-05-06 15:23:49 -04001393 if(componentCount >= 1) c4.x = c4.x + fv * (c6.x - c4.x);
1394 if(componentCount >= 2) c4.y = c4.y + fv * (c6.y - c4.y);
1395 if(componentCount >= 3) c4.z = c4.z + fv * (c6.z - c4.z);
1396 if(componentCount >= 4) c4.w = c4.w + fv * (c6.w - c4.w);
John Bauman89401822014-05-06 15:04:28 -04001397
1398 // Blend slices
Nicolas Capens5790c952017-08-01 17:00:36 -04001399 if(componentCount >= 1) c.x = c0.x + fw * (c4.x - c0.x);
1400 if(componentCount >= 2) c.y = c0.y + fw * (c4.y - c0.y);
1401 if(componentCount >= 3) c.z = c0.z + fw * (c4.z - c0.z);
1402 if(componentCount >= 4) c.w = c0.w + fw * (c4.w - c0.w);
John Bauman89401822014-05-06 15:04:28 -04001403 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001404
1405 return c;
John Bauman89401822014-05-06 15:04:28 -04001406 }
1407
Nicolas Capens6e744262017-07-07 12:46:21 -04001408 Float SamplerCore::log2sqrt(Float lod)
1409 {
1410 // log2(sqrt(lod)) // Equals 0.25 * log2(lod^2).
1411 lod *= lod; // Squaring doubles the exponent and produces an extra bit of precision.
1412 lod = Float(As<Int>(lod)) - Float(0x3F800000); // Interpret as integer and subtract the exponent bias.
1413 lod *= As<Float>(Int(0x33000000)); // Scale by 0.25 * 2^-23 (mantissa length).
1414
1415 return lod;
1416 }
1417
Nicolas Capens823c1c12017-11-22 15:06:58 -05001418 Float SamplerCore::log2(Float lod)
1419 {
1420 lod *= lod; // Squaring doubles the exponent and produces an extra bit of precision.
1421 lod = Float(As<Int>(lod)) - Float(0x3F800000); // Interpret as integer and subtract the exponent bias.
1422 lod *= As<Float>(Int(0x33800000)); // Scale by 0.5 * 2^-23 (mantissa length).
1423
1424 return lod;
1425 }
1426
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001427 void SamplerCore::computeLod(Pointer<Byte> &texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &uuuu, Float4 &vvvv, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001428 {
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001429 if(function != Lod && function != Fetch)
John Bauman89401822014-05-06 15:04:28 -04001430 {
1431 Float4 duvdxy;
1432
Nicolas Capens161a76e2017-11-24 10:10:22 -05001433 if(function != Grad) // Implicit
John Bauman89401822014-05-06 15:04:28 -04001434 {
1435 duvdxy = Float4(uuuu.yz, vvvv.yz) - Float4(uuuu.xx, vvvv.xx);
1436 }
1437 else
1438 {
1439 Float4 dudxy = Float4(dsx.x.xx, dsy.x.xx);
1440 Float4 dvdxy = Float4(dsx.y.xx, dsy.y.xx);
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001441
John Bauman89401822014-05-06 15:04:28 -04001442 duvdxy = Float4(dudxy.xz, dvdxy.xz);
1443 }
1444
Nicolas Capens823c1c12017-11-22 15:06:58 -05001445 // Scale by texture dimensions and global LOD.
John Bauman89401822014-05-06 15:04:28 -04001446 Float4 dUVdxy = duvdxy * *Pointer<Float4>(texture + OFFSET(Texture,widthHeightLOD));
1447
1448 Float4 dUV2dxy = dUVdxy * dUVdxy;
1449 Float4 dUV2 = dUV2dxy.xy + dUV2dxy.zw;
1450
1451 lod = Max(Float(dUV2.x), Float(dUV2.y)); // Square length of major axis
1452
1453 if(state.textureFilter == FILTER_ANISOTROPIC)
1454 {
1455 Float det = Abs(Float(dUVdxy.x) * Float(dUVdxy.w) - Float(dUVdxy.y) * Float(dUVdxy.z));
1456
1457 Float4 dudx = duvdxy.xxxx;
1458 Float4 dudy = duvdxy.yyyy;
1459 Float4 dvdx = duvdxy.zzzz;
1460 Float4 dvdy = duvdxy.wwww;
1461
1462 Int4 mask = As<Int4>(CmpNLT(dUV2.x, dUV2.y));
Tom Anderson69bc6e82017-03-20 11:54:29 -07001463 uDelta = As<Float4>((As<Int4>(dudx) & mask) | ((As<Int4>(dudy) & ~mask)));
1464 vDelta = As<Float4>((As<Int4>(dvdx) & mask) | ((As<Int4>(dvdy) & ~mask)));
John Bauman89401822014-05-06 15:04:28 -04001465
1466 anisotropy = lod * Rcp_pp(det);
1467 anisotropy = Min(anisotropy, *Pointer<Float>(texture + OFFSET(Texture,maxAnisotropy)));
1468
1469 lod *= Rcp_pp(anisotropy * anisotropy);
1470 }
1471
Nicolas Capens6e744262017-07-07 12:46:21 -04001472 lod = log2sqrt(lod); // log2(sqrt(lod))
John Bauman89401822014-05-06 15:04:28 -04001473
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001474 if(function == Bias)
John Bauman89401822014-05-06 15:04:28 -04001475 {
1476 lod += lodBias;
1477 }
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001478 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001479 else if(function == Lod)
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001480 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001481 lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001482 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001483 else if(function == Fetch)
1484 {
1485 // TODO: Eliminate int-float-int conversion.
1486 lod = Float(As<Int>(lodBias)) + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1487 }
1488 else if(function == Base)
1489 {
1490 lod = Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1491 }
1492 else assert(false);
John Bauman89401822014-05-06 15:04:28 -04001493
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001494 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
1495 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001496 }
1497
Nicolas Capens77f0b682017-11-07 13:25:09 -05001498 void SamplerCore::computeLodCube(Pointer<Byte> &texture, Float &lod, Float4 &u, Float4 &v, Float4 &w, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, Float4 &M, SamplerFunction function)
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001499 {
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001500 if(function != Lod && function != Fetch)
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001501 {
Nicolas Capens77f0b682017-11-07 13:25:09 -05001502 Float4 dudxy, dvdxy, dsdxy;
1503
Nicolas Capens161a76e2017-11-24 10:10:22 -05001504 if(function != Grad) // Implicit
John Bauman89401822014-05-06 15:04:28 -04001505 {
Nicolas Capens77f0b682017-11-07 13:25:09 -05001506 Float4 U = u * M;
1507 Float4 V = v * M;
1508 Float4 W = w * M;
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001509
Nicolas Capens823c1c12017-11-22 15:06:58 -05001510 dudxy = Abs(U - U.xxxx);
1511 dvdxy = Abs(V - V.xxxx);
1512 dsdxy = Abs(W - W.xxxx);
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001513 }
1514 else
1515 {
Nicolas Capens77f0b682017-11-07 13:25:09 -05001516 dudxy = Float4(dsx.x.xx, dsy.x.xx);
1517 dvdxy = Float4(dsx.y.xx, dsy.y.xx);
1518 dsdxy = Float4(dsx.z.xx, dsy.z.xx);
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001519
Nicolas Capens823c1c12017-11-22 15:06:58 -05001520 dudxy = Abs(dudxy * Float4(M.x));
1521 dvdxy = Abs(dvdxy * Float4(M.x));
1522 dsdxy = Abs(dsdxy * Float4(M.x));
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001523 }
1524
Nicolas Capens823c1c12017-11-22 15:06:58 -05001525 // Compute the largest Manhattan distance in two dimensions.
1526 // This takes the footprint across adjacent faces into account.
1527 Float4 duvdxy = dudxy + dvdxy;
1528 Float4 dusdxy = dudxy + dsdxy;
1529 Float4 dvsdxy = dvdxy + dsdxy;
Nicolas Capens77f0b682017-11-07 13:25:09 -05001530
Nicolas Capens823c1c12017-11-22 15:06:58 -05001531 dudxy = Max(Max(duvdxy, dusdxy), dvsdxy);
Nicolas Capens77f0b682017-11-07 13:25:09 -05001532
Nicolas Capens161a76e2017-11-24 10:10:22 -05001533 lod = Max(Float(dudxy.y), Float(dudxy.z)); // FIXME: Max(dudxy.y, dudxy.z);
Nicolas Capens77f0b682017-11-07 13:25:09 -05001534
Nicolas Capens823c1c12017-11-22 15:06:58 -05001535 // Scale by texture dimension and global LOD.
1536 lod *= *Pointer<Float>(texture + OFFSET(Texture,widthLOD));
1537
1538 lod = log2(lod);
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001539
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001540 if(function == Bias)
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001541 {
1542 lod += lodBias;
John Bauman89401822014-05-06 15:04:28 -04001543 }
1544 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001545 else if(function == Lod)
John Bauman89401822014-05-06 15:04:28 -04001546 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001547 lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
John Bauman89401822014-05-06 15:04:28 -04001548 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001549 else if(function == Fetch)
1550 {
1551 // TODO: Eliminate int-float-int conversion.
1552 lod = Float(As<Int>(lodBias)) + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1553 }
1554 else if(function == Base)
1555 {
1556 lod = Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1557 }
1558 else assert(false);
John Bauman89401822014-05-06 15:04:28 -04001559
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001560 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
1561 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
John Bauman89401822014-05-06 15:04:28 -04001562 }
1563
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001564 void SamplerCore::computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &uuuu, Float4 &vvvv, Float4 &wwww, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001565 {
1566 if(state.mipmapFilter == MIPMAP_NONE)
1567 {
1568 }
1569 else // Point and linear filter
1570 {
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001571 if(function != Lod && function != Fetch)
John Bauman89401822014-05-06 15:04:28 -04001572 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001573 Float4 dudxy, dvdxy, dsdxy;
John Bauman89401822014-05-06 15:04:28 -04001574
Nicolas Capens161a76e2017-11-24 10:10:22 -05001575 if(function != Grad) // Implicit
John Bauman89401822014-05-06 15:04:28 -04001576 {
Nicolas Capens161a76e2017-11-24 10:10:22 -05001577 dudxy = uuuu - uuuu.xxxx;
1578 dvdxy = vvvv - vvvv.xxxx;
1579 dsdxy = wwww - wwww.xxxx;
John Bauman89401822014-05-06 15:04:28 -04001580 }
1581 else
1582 {
Nicolas Capensa0b57832017-11-07 13:07:53 -05001583 dudxy = Float4(dsx.x.xx, dsy.x.xx);
1584 dvdxy = Float4(dsx.y.xx, dsy.y.xx);
1585 dsdxy = Float4(dsx.z.xx, dsy.z.xx);
John Bauman89401822014-05-06 15:04:28 -04001586 }
1587
Nicolas Capens823c1c12017-11-22 15:06:58 -05001588 // Scale by texture dimensions and global LOD.
John Bauman89401822014-05-06 15:04:28 -04001589 dudxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD));
1590 dvdxy *= *Pointer<Float4>(texture + OFFSET(Texture,heightLOD));
1591 dsdxy *= *Pointer<Float4>(texture + OFFSET(Texture,depthLOD));
1592
1593 dudxy *= dudxy;
1594 dvdxy *= dvdxy;
1595 dsdxy *= dsdxy;
1596
1597 dudxy += dvdxy;
1598 dudxy += dsdxy;
1599
Nicolas Capens161a76e2017-11-24 10:10:22 -05001600 lod = Max(Float(dudxy.y), Float(dudxy.z)); // FIXME: Max(dudxy.y, dudxy.z);
John Bauman89401822014-05-06 15:04:28 -04001601
Nicolas Capens6e744262017-07-07 12:46:21 -04001602 lod = log2sqrt(lod); // log2(sqrt(lod))
John Bauman89401822014-05-06 15:04:28 -04001603
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001604 if(function == Bias)
John Bauman89401822014-05-06 15:04:28 -04001605 {
1606 lod += lodBias;
1607 }
1608 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001609 else if(function == Lod)
John Bauman89401822014-05-06 15:04:28 -04001610 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001611 lod = lodBias + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
John Bauman89401822014-05-06 15:04:28 -04001612 }
Nicolas Capensa0b57832017-11-07 13:07:53 -05001613 else if(function == Fetch)
1614 {
1615 // TODO: Eliminate int-float-int conversion.
1616 lod = Float(As<Int>(lodBias)) + Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1617 }
1618 else if(function == Base)
1619 {
1620 lod = Float(*Pointer<Int>(texture + OFFSET(Texture,baseLevel)));
1621 }
1622 else assert(false);
John Bauman89401822014-05-06 15:04:28 -04001623
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001624 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod)));
1625 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod)));
John Bauman89401822014-05-06 15:04:28 -04001626 }
1627 }
1628
Nicolas Capens77f0b682017-11-07 13:25:09 -05001629 void SamplerCore::cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &x, Float4 &y, Float4 &z, Float4 &M)
John Bauman89401822014-05-06 15:04:28 -04001630 {
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001631 Int4 xn = CmpLT(x, Float4(0.0f)); // x < 0
1632 Int4 yn = CmpLT(y, Float4(0.0f)); // y < 0
1633 Int4 zn = CmpLT(z, Float4(0.0f)); // z < 0
John Bauman89401822014-05-06 15:04:28 -04001634
1635 Float4 absX = Abs(x);
1636 Float4 absY = Abs(y);
1637 Float4 absZ = Abs(z);
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001638
John Bauman89401822014-05-06 15:04:28 -04001639 Int4 xy = CmpNLE(absX, absY); // abs(x) > abs(y)
1640 Int4 yz = CmpNLE(absY, absZ); // abs(y) > abs(z)
1641 Int4 zx = CmpNLE(absZ, absX); // abs(z) > abs(x)
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001642 Int4 xMajor = xy & ~zx; // abs(x) > abs(y) && abs(x) > abs(z)
1643 Int4 yMajor = yz & ~xy; // abs(y) > abs(z) && abs(y) > abs(x)
1644 Int4 zMajor = zx & ~yz; // abs(z) > abs(x) && abs(z) > abs(y)
John Bauman89401822014-05-06 15:04:28 -04001645
1646 // FACE_POSITIVE_X = 000b
1647 // FACE_NEGATIVE_X = 001b
1648 // FACE_POSITIVE_Y = 010b
1649 // FACE_NEGATIVE_Y = 011b
1650 // FACE_POSITIVE_Z = 100b
1651 // FACE_NEGATIVE_Z = 101b
1652
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001653 Int yAxis = SignMask(yMajor);
1654 Int zAxis = SignMask(zMajor);
John Bauman89401822014-05-06 15:04:28 -04001655
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001656 Int4 n = ((xn & xMajor) | (yn & yMajor) | (zn & zMajor)) & Int4(0x80000000);
John Bauman89401822014-05-06 15:04:28 -04001657 Int negative = SignMask(n);
1658
1659 face[0] = *Pointer<Int>(constants + OFFSET(Constants,transposeBit0) + negative * 4);
1660 face[0] |= *Pointer<Int>(constants + OFFSET(Constants,transposeBit1) + yAxis * 4);
1661 face[0] |= *Pointer<Int>(constants + OFFSET(Constants,transposeBit2) + zAxis * 4);
1662 face[1] = (face[0] >> 4) & 0x7;
1663 face[2] = (face[0] >> 8) & 0x7;
1664 face[3] = (face[0] >> 12) & 0x7;
1665 face[0] &= 0x7;
1666
Nicolas Capens77f0b682017-11-07 13:25:09 -05001667 M = Max(Max(absX, absY), absZ);
John Bauman89401822014-05-06 15:04:28 -04001668
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001669 // U = xMajor ? (neg ^ -z) : (zMajor & neg) ^ x)
1670 U = As<Float4>((xMajor & (n ^ As<Int4>(-z))) | (~xMajor & ((zMajor & n) ^ As<Int4>(x))));
John Bauman89401822014-05-06 15:04:28 -04001671
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001672 // V = !yMajor ? -y : (n ^ z)
1673 V = As<Float4>((~yMajor & As<Int4>(-y)) | (yMajor & (n ^ As<Int4>(z))));
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001674
Nicolas Capens2cfadc62016-04-19 09:09:29 -04001675 M = reciprocal(M) * Float4(0.5f);
1676 U = U * M + Float4(0.5f);
1677 V = V * M + Float4(0.5f);
John Bauman89401822014-05-06 15:04:28 -04001678 }
1679
Meng-Lin Wu2337a192016-06-01 13:54:07 -04001680 Short4 SamplerCore::applyOffset(Short4 &uvw, Float4 &offset, const Int4 &whd, AddressingMode mode)
1681 {
1682 Int4 tmp = Int4(As<UShort4>(uvw));
1683 tmp = tmp + As<Int4>(offset);
1684
Nicolas Capens89a218b2017-11-07 13:05:20 -05001685 switch(mode)
Meng-Lin Wu2337a192016-06-01 13:54:07 -04001686 {
1687 case AddressingMode::ADDRESSING_WRAP:
1688 tmp = (tmp + whd * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % whd;
1689 break;
1690 case AddressingMode::ADDRESSING_CLAMP:
1691 case AddressingMode::ADDRESSING_MIRROR:
1692 case AddressingMode::ADDRESSING_MIRRORONCE:
1693 case AddressingMode::ADDRESSING_BORDER: // FIXME: Implement and test ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE, ADDRESSING_BORDER
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001694 tmp = Min(Max(tmp, Int4(0)), whd - Int4(1));
1695 break;
1696 case ADDRESSING_TEXELFETCH:
Meng-Lin Wu2337a192016-06-01 13:54:07 -04001697 break;
1698 default:
1699 ASSERT(false);
1700 }
1701
1702 return As<Short4>(UShort4(tmp));
1703 }
1704
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001705 void SamplerCore::computeIndices(UInt index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, Vector4f &offset, const Pointer<Byte> &mipmap, SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04001706 {
Nicolas Capensa3c16e42016-06-15 16:45:53 -04001707 bool texelFetch = (function == Fetch);
1708 bool hasOffset = (function.option == Offset);
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001709
Nicolas Capens77980512016-12-02 14:22:32 -05001710 if(!texelFetch)
John Bauman89401822014-05-06 15:04:28 -04001711 {
Nicolas Capens77980512016-12-02 14:22:32 -05001712 uuuu = MulHigh(As<UShort4>(uuuu), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, width)));
1713 vvvv = MulHigh(As<UShort4>(vvvv), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, height)));
John Bauman89401822014-05-06 15:04:28 -04001714 }
Nicolas Capens77980512016-12-02 14:22:32 -05001715
1716 if(hasOffset)
John Bauman89401822014-05-06 15:04:28 -04001717 {
Nicolas Capens2a3932c2017-11-07 14:35:38 -05001718 UShort4 w = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, width));
1719 uuuu = applyOffset(uuuu, offset.x, Int4(w), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeU);
1720 UShort4 h = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, height));
1721 vvvv = applyOffset(vvvv, offset.y, Int4(h), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeV);
Alexis Hetuf15e8942015-12-01 15:13:23 -05001722 }
Nicolas Capens411273e2017-01-26 15:13:36 -08001723
Nicolas Capens77980512016-12-02 14:22:32 -05001724 Short4 uuu2 = uuuu;
1725 uuuu = As<Short4>(UnpackLow(uuuu, vvvv));
1726 uuu2 = As<Short4>(UnpackHigh(uuu2, vvvv));
1727 uuuu = As<Short4>(MulAdd(uuuu, *Pointer<Short4>(mipmap + OFFSET(Mipmap,onePitchP))));
1728 uuu2 = As<Short4>(MulAdd(uuu2, *Pointer<Short4>(mipmap + OFFSET(Mipmap,onePitchP))));
John Bauman89401822014-05-06 15:04:28 -04001729
Alexis Hetu75a61852017-07-14 14:17:14 -04001730 if(hasThirdCoordinate())
Alexis Hetuf15e8942015-12-01 15:13:23 -05001731 {
1732 if(state.textureType != TEXTURE_2D_ARRAY)
John Bauman89401822014-05-06 15:04:28 -04001733 {
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001734 if(!texelFetch)
1735 {
1736 wwww = MulHigh(As<UShort4>(wwww), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth)));
1737 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001738
Meng-Lin Wu2337a192016-06-01 13:54:07 -04001739 if(hasOffset)
1740 {
Nicolas Capens2a3932c2017-11-07 14:35:38 -05001741 UShort4 d = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth));
1742 wwww = applyOffset(wwww, offset.z, Int4(d), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeW);
Meng-Lin Wu2337a192016-06-01 13:54:07 -04001743 }
John Bauman89401822014-05-06 15:04:28 -04001744 }
Nicolas Capens89a218b2017-11-07 13:05:20 -05001745
Alexis Hetu42e53032017-10-03 13:56:07 -04001746 UInt4 uv(As<UInt2>(uuuu), As<UInt2>(uuu2));
1747 uv += As<UInt4>(Int4(As<UShort4>(wwww))) * *Pointer<UInt4>(mipmap + OFFSET(Mipmap, sliceP));
Nicolas Capens89a218b2017-11-07 13:05:20 -05001748
Alexis Hetu42e53032017-10-03 13:56:07 -04001749 index[0] = Extract(As<Int4>(uv), 0);
1750 index[1] = Extract(As<Int4>(uv), 1);
1751 index[2] = Extract(As<Int4>(uv), 2);
1752 index[3] = Extract(As<Int4>(uv), 3);
John Bauman89401822014-05-06 15:04:28 -04001753 }
Alexis Hetu42e53032017-10-03 13:56:07 -04001754 else
1755 {
1756 index[0] = Extract(As<Int2>(uuuu), 0);
1757 index[1] = Extract(As<Int2>(uuuu), 1);
1758 index[2] = Extract(As<Int2>(uuu2), 0);
1759 index[3] = Extract(As<Int2>(uuu2), 1);
1760 }
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001761
1762 if(texelFetch)
1763 {
1764 Int size = Int(*Pointer<Int>(mipmap + OFFSET(Mipmap, sliceP)));
Alexis Hetu75a61852017-07-14 14:17:14 -04001765 if(hasThirdCoordinate())
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001766 {
1767 size *= Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, depth)));
1768 }
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001769 UInt min = 0;
1770 UInt max = size - 1;
Meng-Lin Wu2fce5822016-06-07 16:15:12 -04001771
1772 for(int i = 0; i < 4; i++)
1773 {
1774 index[i] = Min(Max(index[i], min), max);
1775 }
1776 }
John Bauman89401822014-05-06 15:04:28 -04001777 }
1778
Alexis Hetu75a61852017-07-14 14:17:14 -04001779 void SamplerCore::computeIndices(UInt index[4], Int4& uuuu, Int4& vvvv, Int4& wwww, const Pointer<Byte> &mipmap, SamplerFunction function)
1780 {
1781 UInt4 indices = uuuu + vvvv;
1782
1783 if(hasThirdCoordinate())
1784 {
1785 indices += As<UInt4>(wwww);
1786 }
1787
1788 for(int i = 0; i < 4; i++)
1789 {
1790 index[i] = Extract(As<Int4>(indices), i);
1791 }
1792 }
1793
Nicolas Capens5790c952017-08-01 17:00:36 -04001794 Vector4s SamplerCore::sampleTexel(UInt index[4], Pointer<Byte> buffer[4])
John Bauman89401822014-05-06 15:04:28 -04001795 {
Nicolas Capens5790c952017-08-01 17:00:36 -04001796 Vector4s c;
1797
John Bauman89401822014-05-06 15:04:28 -04001798 int f0 = state.textureType == TEXTURE_CUBE ? 0 : 0;
1799 int f1 = state.textureType == TEXTURE_CUBE ? 1 : 0;
1800 int f2 = state.textureType == TEXTURE_CUBE ? 2 : 0;
1801 int f3 = state.textureType == TEXTURE_CUBE ? 3 : 0;
1802
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04001803 if(has16bitTextureFormat())
John Bauman89401822014-05-06 15:04:28 -04001804 {
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001805 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0);
1806 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1);
1807 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2);
1808 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3);
Nicolas Capens27496312015-05-12 15:16:06 -04001809
1810 switch(state.textureFormat)
1811 {
1812 case FORMAT_R5G6B5:
1813 c.z = (c.x & Short4(0x001Fu)) << 11;
1814 c.y = (c.x & Short4(0x07E0u)) << 5;
1815 c.x = (c.x & Short4(0xF800u));
1816 break;
1817 default:
1818 ASSERT(false);
1819 }
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04001820 }
Nicolas Capens21bda852015-09-01 10:23:33 -04001821 else if(has8bitTextureComponents())
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04001822 {
John Bauman89401822014-05-06 15:04:28 -04001823 switch(textureComponentCount())
1824 {
1825 case 4:
1826 {
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001827 Byte4 c0 = Pointer<Byte4>(buffer[f0])[index[0]];
1828 Byte4 c1 = Pointer<Byte4>(buffer[f1])[index[1]];
1829 Byte4 c2 = Pointer<Byte4>(buffer[f2])[index[2]];
1830 Byte4 c3 = Pointer<Byte4>(buffer[f3])[index[3]];
Nicolas Capens411273e2017-01-26 15:13:36 -08001831 c.x = Unpack(c0, c1);
1832 c.y = Unpack(c2, c3);
Alexis Hetu3b96fa82016-02-04 21:15:03 -05001833
John Bauman89401822014-05-06 15:04:28 -04001834 switch(state.textureFormat)
1835 {
1836 case FORMAT_A8R8G8B8:
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001837 c.z = As<Short4>(UnpackLow(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001838 c.x = As<Short4>(UnpackHigh(c.x, c.y));
1839 c.y = c.z;
1840 c.w = c.x;
1841 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z));
1842 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y));
1843 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x));
1844 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(c.w));
John Bauman89401822014-05-06 15:04:28 -04001845 break;
Nicolas Capensb508eaf2015-03-28 18:44:48 -04001846 case FORMAT_A8B8G8R8:
Alexis Hetu3412d872015-10-26 16:40:26 -04001847 case FORMAT_A8B8G8R8I:
Alexis Hetu3412d872015-10-26 16:40:26 -04001848 case FORMAT_A8B8G8R8I_SNORM:
John Bauman89401822014-05-06 15:04:28 -04001849 case FORMAT_Q8W8V8U8:
Alexis Hetu049a1872016-04-25 16:59:58 -04001850 case FORMAT_SRGB8_A8:
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001851 c.z = As<Short4>(UnpackHigh(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001852 c.x = As<Short4>(UnpackLow(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001853 c.y = c.x;
1854 c.w = c.z;
1855 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x));
1856 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y));
1857 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z));
1858 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(c.w));
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001859 // Propagate sign bit
1860 if(state.textureFormat == FORMAT_A8B8G8R8I)
1861 {
1862 c.x >>= 8;
1863 c.y >>= 8;
1864 c.z >>= 8;
1865 c.w >>= 8;
1866 }
1867 break;
1868 case FORMAT_A8B8G8R8UI:
1869 c.z = As<Short4>(UnpackHigh(c.x, c.y));
1870 c.x = As<Short4>(UnpackLow(c.x, c.y));
1871 c.y = c.x;
1872 c.w = c.z;
1873 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(Short4(0)));
1874 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(Short4(0)));
1875 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(Short4(0)));
1876 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(Short4(0)));
John Bauman89401822014-05-06 15:04:28 -04001877 break;
1878 default:
1879 ASSERT(false);
1880 }
1881 }
1882 break;
1883 case 3:
1884 {
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001885 Byte4 c0 = Pointer<Byte4>(buffer[f0])[index[0]];
1886 Byte4 c1 = Pointer<Byte4>(buffer[f1])[index[1]];
1887 Byte4 c2 = Pointer<Byte4>(buffer[f2])[index[2]];
1888 Byte4 c3 = Pointer<Byte4>(buffer[f3])[index[3]];
Nicolas Capens411273e2017-01-26 15:13:36 -08001889 c.x = Unpack(c0, c1);
1890 c.y = Unpack(c2, c3);
John Bauman89401822014-05-06 15:04:28 -04001891
1892 switch(state.textureFormat)
1893 {
1894 case FORMAT_X8R8G8B8:
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001895 c.z = As<Short4>(UnpackLow(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001896 c.x = As<Short4>(UnpackHigh(c.x, c.y));
1897 c.y = c.z;
1898 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z));
1899 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y));
1900 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x));
John Bauman89401822014-05-06 15:04:28 -04001901 break;
Alexis Hetu3412d872015-10-26 16:40:26 -04001902 case FORMAT_X8B8G8R8I_SNORM:
Alexis Hetu3412d872015-10-26 16:40:26 -04001903 case FORMAT_X8B8G8R8I:
Nicolas Capensb508eaf2015-03-28 18:44:48 -04001904 case FORMAT_X8B8G8R8:
John Bauman89401822014-05-06 15:04:28 -04001905 case FORMAT_X8L8V8U8:
Alexis Hetu049a1872016-04-25 16:59:58 -04001906 case FORMAT_SRGB8_X8:
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001907 c.z = As<Short4>(UnpackHigh(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001908 c.x = As<Short4>(UnpackLow(c.x, c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001909 c.y = c.x;
Nicolas Capensb508eaf2015-03-28 18:44:48 -04001910 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x));
1911 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y));
John Bauman19bac1e2014-05-06 15:23:49 -04001912 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z));
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001913 // Propagate sign bit
1914 if(state.textureFormat == FORMAT_X8B8G8R8I)
1915 {
1916 c.x >>= 8;
1917 c.y >>= 8;
1918 c.z >>= 8;
1919 }
1920 break;
1921 case FORMAT_X8B8G8R8UI:
1922 c.z = As<Short4>(UnpackHigh(c.x, c.y));
1923 c.x = As<Short4>(UnpackLow(c.x, c.y));
1924 c.y = c.x;
1925 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(Short4(0)));
1926 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(Short4(0)));
1927 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(Short4(0)));
John Bauman89401822014-05-06 15:04:28 -04001928 break;
1929 default:
1930 ASSERT(false);
1931 }
1932 }
1933 break;
1934 case 2:
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001935 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0);
1936 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1);
1937 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2);
1938 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3);
John Bauman89401822014-05-06 15:04:28 -04001939
1940 switch(state.textureFormat)
1941 {
1942 case FORMAT_G8R8:
Alexis Hetu3412d872015-10-26 16:40:26 -04001943 case FORMAT_G8R8I_SNORM:
John Bauman89401822014-05-06 15:04:28 -04001944 case FORMAT_V8U8:
1945 case FORMAT_A8L8:
Alexis Hetu90c7ad62016-06-27 11:50:40 -04001946 c.y = (c.x & Short4(0xFF00u)) | As<Short4>(As<UShort4>(c.x) >> 8);
1947 c.x = (c.x & Short4(0x00FFu)) | (c.x << 8);
John Bauman89401822014-05-06 15:04:28 -04001948 break;
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001949 case FORMAT_G8R8I:
1950 c.y = c.x >> 8;
1951 c.x = (c.x << 8) >> 8; // Propagate sign bit
1952 break;
1953 case FORMAT_G8R8UI:
1954 c.y = As<Short4>(As<UShort4>(c.x) >> 8);
1955 c.x &= Short4(0x00FFu);
1956 break;
John Bauman89401822014-05-06 15:04:28 -04001957 default:
1958 ASSERT(false);
1959 }
1960 break;
1961 case 1:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04001962 {
1963 Int c0 = Int(*Pointer<Byte>(buffer[f0] + index[0]));
1964 Int c1 = Int(*Pointer<Byte>(buffer[f1] + index[1]));
1965 Int c2 = Int(*Pointer<Byte>(buffer[f2] + index[2]));
1966 Int c3 = Int(*Pointer<Byte>(buffer[f3] + index[3]));
1967 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001968
1969 switch(state.textureFormat)
1970 {
1971 case FORMAT_R8I:
1972 case FORMAT_R8UI:
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001973 {
Nicolas Capens2d8c3702017-07-25 13:56:46 -04001974 Int zero(0);
1975 c.x = Unpack(As<Byte4>(c0), As<Byte4>(zero));
1976 // Propagate sign bit
1977 if(state.textureFormat == FORMAT_R8I)
1978 {
1979 c.x = (c.x << 8) >> 8;
1980 }
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001981 }
Nicolas Capens2d8c3702017-07-25 13:56:46 -04001982 break;
Alexis Hetu91dd1c42017-07-18 13:03:42 -04001983 default:
1984 c.x = Unpack(As<Byte4>(c0));
1985 break;
1986 }
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04001987 }
John Bauman89401822014-05-06 15:04:28 -04001988 break;
1989 default:
1990 ASSERT(false);
1991 }
1992 }
Nicolas Capens21bda852015-09-01 10:23:33 -04001993 else if(has16bitTextureComponents())
John Bauman89401822014-05-06 15:04:28 -04001994 {
1995 switch(textureComponentCount())
1996 {
1997 case 4:
Nicolas Capens9b0e6552017-01-26 21:49:04 -08001998 c.x = Pointer<Short4>(buffer[f0])[index[0]];
1999 c.y = Pointer<Short4>(buffer[f1])[index[1]];
2000 c.z = Pointer<Short4>(buffer[f2])[index[2]];
2001 c.w = Pointer<Short4>(buffer[f3])[index[3]];
John Bauman19bac1e2014-05-06 15:23:49 -04002002 transpose4x4(c.x, c.y, c.z, c.w);
John Bauman89401822014-05-06 15:04:28 -04002003 break;
Nicolas Capense4a88b92017-11-30 00:14:57 -05002004 case 3:
2005 c.x = Pointer<Short4>(buffer[f0])[index[0]];
2006 c.y = Pointer<Short4>(buffer[f1])[index[1]];
2007 c.z = Pointer<Short4>(buffer[f2])[index[2]];
2008 c.w = Pointer<Short4>(buffer[f3])[index[3]];
2009 transpose4x3(c.x, c.y, c.z, c.w);
2010 break;
John Bauman89401822014-05-06 15:04:28 -04002011 case 2:
John Bauman19bac1e2014-05-06 15:23:49 -04002012 c.x = *Pointer<Short4>(buffer[f0] + 4 * index[0]);
2013 c.x = As<Short4>(UnpackLow(c.x, *Pointer<Short4>(buffer[f1] + 4 * index[1])));
2014 c.z = *Pointer<Short4>(buffer[f2] + 4 * index[2]);
2015 c.z = As<Short4>(UnpackLow(c.z, *Pointer<Short4>(buffer[f3] + 4 * index[3])));
2016 c.y = c.x;
Nicolas Capens45f187a2016-12-02 15:30:56 -05002017 c.x = UnpackLow(As<Int2>(c.x), As<Int2>(c.z));
2018 c.y = UnpackHigh(As<Int2>(c.y), As<Int2>(c.z));
John Bauman89401822014-05-06 15:04:28 -04002019 break;
2020 case 1:
Nicolas Capens9b0e6552017-01-26 21:49:04 -08002021 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0);
2022 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1);
2023 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2);
2024 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3);
John Bauman89401822014-05-06 15:04:28 -04002025 break;
2026 default:
2027 ASSERT(false);
2028 }
2029 }
Alexis Hetu5de90b22017-07-17 11:19:12 -04002030 else ASSERT(false);
Nicolas Capens5790c952017-08-01 17:00:36 -04002031
2032 return c;
Alexis Hetu5de90b22017-07-17 11:19:12 -04002033 }
2034
Nicolas Capens5790c952017-08-01 17:00:36 -04002035 Vector4s SamplerCore::sampleTexel(Short4 &uuuu, Short4 &vvvv, Short4 &wwww, Vector4f &offset, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function)
Alexis Hetu5de90b22017-07-17 11:19:12 -04002036 {
Nicolas Capens5790c952017-08-01 17:00:36 -04002037 Vector4s c;
Alexis Hetu5de90b22017-07-17 11:19:12 -04002038
Nicolas Capens5790c952017-08-01 17:00:36 -04002039 UInt index[4];
Alexis Hetu5de90b22017-07-17 11:19:12 -04002040 computeIndices(index, uuuu, vvvv, wwww, offset, mipmap, function);
2041
2042 if(hasYuvFormat())
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002043 {
2044 // Generic YPbPr to RGB transformation
2045 // R = Y + 2 * (1 - Kr) * Pr
2046 // G = Y - 2 * Kb * (1 - Kb) / Kg * Pb - 2 * Kr * (1 - Kr) / Kg * Pr
2047 // B = Y + 2 * (1 - Kb) * Pb
2048
2049 float Kb = 0.114f;
2050 float Kr = 0.299f;
2051 int studioSwing = 1;
2052
2053 switch(state.textureFormat)
2054 {
2055 case FORMAT_YV12_BT601:
2056 Kb = 0.114f;
2057 Kr = 0.299f;
2058 studioSwing = 1;
2059 break;
2060 case FORMAT_YV12_BT709:
2061 Kb = 0.0722f;
2062 Kr = 0.2126f;
2063 studioSwing = 1;
2064 break;
2065 case FORMAT_YV12_JFIF:
2066 Kb = 0.114f;
2067 Kr = 0.299f;
2068 studioSwing = 0;
2069 break;
2070 default:
2071 ASSERT(false);
2072 }
2073
2074 const float Kg = 1.0f - Kr - Kb;
2075
2076 const float Rr = 2 * (1 - Kr);
2077 const float Gb = -2 * Kb * (1 - Kb) / Kg;
2078 const float Gr = -2 * Kr * (1 - Kr) / Kg;
2079 const float Bb = 2 * (1 - Kb);
2080
2081 // Scaling and bias for studio-swing range: Y = [16 .. 235], U/V = [16 .. 240]
2082 const float Yy = studioSwing ? 255.0f / (235 - 16) : 1.0f;
2083 const float Uu = studioSwing ? 255.0f / (240 - 16) : 1.0f;
2084 const float Vv = studioSwing ? 255.0f / (240 - 16) : 1.0f;
2085
2086 const float Rv = Vv * Rr;
2087 const float Gu = Uu * Gb;
2088 const float Gv = Vv * Gr;
2089 const float Bu = Uu * Bb;
2090
2091 const float R0 = (studioSwing * -16 * Yy - 128 * Rv) / 255;
2092 const float G0 = (studioSwing * -16 * Yy - 128 * Gu - 128 * Gv) / 255;
2093 const float B0 = (studioSwing * -16 * Yy - 128 * Bu) / 255;
2094
Nicolas Capens9b0e6552017-01-26 21:49:04 -08002095 Int c0 = Int(buffer[0][index[0]]);
2096 Int c1 = Int(buffer[0][index[1]]);
2097 Int c2 = Int(buffer[0][index[2]]);
2098 Int c3 = Int(buffer[0][index[3]]);
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002099 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
2100 UShort4 Y = As<UShort4>(Unpack(As<Byte4>(c0)));
2101
Nicolas Capensa3c16e42016-06-15 16:45:53 -04002102 computeIndices(index, uuuu, vvvv, wwww, offset, mipmap + sizeof(Mipmap), function);
Nicolas Capens9b0e6552017-01-26 21:49:04 -08002103 c0 = Int(buffer[1][index[0]]);
2104 c1 = Int(buffer[1][index[1]]);
2105 c2 = Int(buffer[1][index[2]]);
2106 c3 = Int(buffer[1][index[3]]);
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002107 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
2108 UShort4 V = As<UShort4>(Unpack(As<Byte4>(c0)));
2109
Nicolas Capens9b0e6552017-01-26 21:49:04 -08002110 c0 = Int(buffer[2][index[0]]);
2111 c1 = Int(buffer[2][index[1]]);
2112 c2 = Int(buffer[2][index[2]]);
2113 c3 = Int(buffer[2][index[3]]);
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002114 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
2115 UShort4 U = As<UShort4>(Unpack(As<Byte4>(c0)));
2116
2117 const UShort4 yY = UShort4(iround(Yy * 0x4000));
2118 const UShort4 rV = UShort4(iround(Rv * 0x4000));
2119 const UShort4 gU = UShort4(iround(-Gu * 0x4000));
2120 const UShort4 gV = UShort4(iround(-Gv * 0x4000));
2121 const UShort4 bU = UShort4(iround(Bu * 0x4000));
2122
2123 const UShort4 r0 = UShort4(iround(-R0 * 0x4000));
2124 const UShort4 g0 = UShort4(iround(G0 * 0x4000));
2125 const UShort4 b0 = UShort4(iround(-B0 * 0x4000));
2126
2127 UShort4 y = MulHigh(Y, yY);
2128 UShort4 r = SubSat(y + MulHigh(V, rV), r0);
2129 UShort4 g = SubSat(y + g0, MulHigh(U, gU) + MulHigh(V, gV));
2130 UShort4 b = SubSat(y + MulHigh(U, bU), b0);
2131
2132 c.x = Min(r, UShort4(0x3FFF)) << 2;
2133 c.y = Min(g, UShort4(0x3FFF)) << 2;
2134 c.z = Min(b, UShort4(0x3FFF)) << 2;
2135 }
Alexis Hetu5de90b22017-07-17 11:19:12 -04002136 else
2137 {
Nicolas Capens5790c952017-08-01 17:00:36 -04002138 return sampleTexel(index, buffer);
Alexis Hetu5de90b22017-07-17 11:19:12 -04002139 }
Nicolas Capens5790c952017-08-01 17:00:36 -04002140
2141 return c;
John Bauman89401822014-05-06 15:04:28 -04002142 }
2143
Nicolas Capens5790c952017-08-01 17:00:36 -04002144 Vector4f SamplerCore::sampleTexel(Int4 &uuuu, Int4 &vvvv, Int4 &wwww, Float4 &z, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function)
John Bauman89401822014-05-06 15:04:28 -04002145 {
Nicolas Capens5790c952017-08-01 17:00:36 -04002146 Vector4f c;
John Bauman89401822014-05-06 15:04:28 -04002147
Nicolas Capens5790c952017-08-01 17:00:36 -04002148 UInt index[4];
Alexis Hetu75a61852017-07-14 14:17:14 -04002149 computeIndices(index, uuuu, vvvv, wwww, mipmap, function);
John Bauman89401822014-05-06 15:04:28 -04002150
Alexis Hetu91dd1c42017-07-18 13:03:42 -04002151 if(hasFloatTexture() || has32bitIntegerTextureComponents())
John Bauman89401822014-05-06 15:04:28 -04002152 {
Alexis Hetu5de90b22017-07-17 11:19:12 -04002153 int f0 = state.textureType == TEXTURE_CUBE ? 0 : 0;
2154 int f1 = state.textureType == TEXTURE_CUBE ? 1 : 0;
2155 int f2 = state.textureType == TEXTURE_CUBE ? 2 : 0;
2156 int f3 = state.textureType == TEXTURE_CUBE ? 3 : 0;
John Bauman89401822014-05-06 15:04:28 -04002157
Alexis Hetu5de90b22017-07-17 11:19:12 -04002158 // Read texels
2159 switch(textureComponentCount())
John Bauman89401822014-05-06 15:04:28 -04002160 {
Alexis Hetu5de90b22017-07-17 11:19:12 -04002161 case 4:
2162 c.x = *Pointer<Float4>(buffer[f0] + index[0] * 16, 16);
2163 c.y = *Pointer<Float4>(buffer[f1] + index[1] * 16, 16);
2164 c.z = *Pointer<Float4>(buffer[f2] + index[2] * 16, 16);
2165 c.w = *Pointer<Float4>(buffer[f3] + index[3] * 16, 16);
2166 transpose4x4(c.x, c.y, c.z, c.w);
2167 break;
2168 case 3:
Alexis Hetu5de90b22017-07-17 11:19:12 -04002169 c.x = *Pointer<Float4>(buffer[f0] + index[0] * 16, 16);
2170 c.y = *Pointer<Float4>(buffer[f1] + index[1] * 16, 16);
2171 c.z = *Pointer<Float4>(buffer[f2] + index[2] * 16, 16);
2172 c.w = *Pointer<Float4>(buffer[f3] + index[3] * 16, 16);
2173 transpose4x3(c.x, c.y, c.z, c.w);
Alexis Hetu5de90b22017-07-17 11:19:12 -04002174 break;
2175 case 2:
2176 // FIXME: Optimal shuffling?
2177 c.x.xy = *Pointer<Float4>(buffer[f0] + index[0] * 8);
2178 c.x.zw = *Pointer<Float4>(buffer[f1] + index[1] * 8 - 8);
2179 c.z.xy = *Pointer<Float4>(buffer[f2] + index[2] * 8);
2180 c.z.zw = *Pointer<Float4>(buffer[f3] + index[3] * 8 - 8);
2181 c.y = c.x;
2182 c.x = Float4(c.x.xz, c.z.xz);
2183 c.y = Float4(c.y.yw, c.z.yw);
2184 break;
2185 case 1:
2186 // FIXME: Optimal shuffling?
2187 c.x.x = *Pointer<Float>(buffer[f0] + index[0] * 4);
2188 c.x.y = *Pointer<Float>(buffer[f1] + index[1] * 4);
2189 c.x.z = *Pointer<Float>(buffer[f2] + index[2] * 4);
2190 c.x.w = *Pointer<Float>(buffer[f3] + index[3] * 4);
Alexis Hetu5de90b22017-07-17 11:19:12 -04002191 break;
2192 default:
2193 ASSERT(false);
John Bauman89401822014-05-06 15:04:28 -04002194 }
Nicolas Capens185c18b2017-11-07 13:51:50 -05002195
2196 if(state.compare != COMPARE_BYPASS)
2197 {
2198 Float4 ref = z;
2199
2200 if(!hasFloatTexture())
2201 {
2202 ref = Min(Max(ref, Float4(0.0f)), Float4(1.0f));
2203 }
2204
2205 Int4 boolean;
2206
2207 switch(state.compare)
2208 {
2209 case COMPARE_LESSEQUAL: boolean = CmpLE(ref, c.x); break;
2210 case COMPARE_GREATEREQUAL: boolean = CmpNLT(ref, c.x); break;
2211 case COMPARE_LESS: boolean = CmpLT(ref, c.x); break;
2212 case COMPARE_GREATER: boolean = CmpNLE(ref, c.x); break;
2213 case COMPARE_EQUAL: boolean = CmpEQ(ref, c.x); break;
2214 case COMPARE_NOTEQUAL: boolean = CmpNEQ(ref, c.x); break;
2215 case COMPARE_ALWAYS: boolean = Int4(-1); break;
2216 case COMPARE_NEVER: boolean = Int4(0); break;
2217 default: ASSERT(false);
2218 }
2219
2220 c.x = As<Float4>(boolean & As<Int4>(Float4(1.0f)));
2221 c.y = Float4(0.0f);
2222 c.z = Float4(0.0f);
2223 c.w = Float4(1.0f);
2224 }
Alexis Hetu5de90b22017-07-17 11:19:12 -04002225 }
2226 else
2227 {
2228 ASSERT(!hasYuvFormat());
2229
Nicolas Capens5790c952017-08-01 17:00:36 -04002230 Vector4s cs = sampleTexel(index, buffer);
Alexis Hetu5de90b22017-07-17 11:19:12 -04002231
2232 bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat);
2233 int componentCount = textureComponentCount();
2234 for(int n = 0; n < componentCount; ++n)
2235 {
2236 if(hasUnsignedTextureComponent(n))
2237 {
2238 if(isInteger)
2239 {
2240 c[n] = As<Float4>(Int4(As<UShort4>(cs[n])));
2241 }
2242 else
2243 {
2244 c[n] = Float4(As<UShort4>(cs[n]));
2245 }
2246 }
2247 else
2248 {
2249 if(isInteger)
2250 {
2251 c[n] = As<Float4>(Int4(cs[n]));
2252 }
2253 else
2254 {
2255 c[n] = Float4(cs[n]);
2256 }
2257 }
2258 }
John Bauman89401822014-05-06 15:04:28 -04002259 }
Nicolas Capens5790c952017-08-01 17:00:36 -04002260
2261 return c;
John Bauman89401822014-05-06 15:04:28 -04002262 }
2263
2264 void SamplerCore::selectMipmap(Pointer<Byte> &texture, Pointer<Byte> buffer[4], Pointer<Byte> &mipmap, Float &lod, Int face[4], bool secondLOD)
2265 {
2266 if(state.mipmapFilter < MIPMAP_POINT)
2267 {
2268 mipmap = texture + OFFSET(Texture,mipmap[0]);
2269 }
2270 else
2271 {
2272 Int ilod;
2273
2274 if(state.mipmapFilter == MIPMAP_POINT)
2275 {
2276 ilod = RoundInt(lod);
2277 }
2278 else // Linear
2279 {
2280 ilod = Int(lod);
2281 }
2282
2283 mipmap = texture + OFFSET(Texture,mipmap) + ilod * sizeof(Mipmap) + secondLOD * sizeof(Mipmap);
2284 }
2285
2286 if(state.textureType != TEXTURE_CUBE)
2287 {
John Bauman66b8ab22014-05-06 15:57:45 -04002288 buffer[0] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[0]));
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002289
2290 if(hasYuvFormat())
2291 {
2292 buffer[1] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[1]));
2293 buffer[2] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[2]));
2294 }
John Bauman89401822014-05-06 15:04:28 -04002295 }
2296 else
2297 {
2298 for(int i = 0; i < 4; i++)
2299 {
John Bauman66b8ab22014-05-06 15:57:45 -04002300 buffer[i] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer) + face[i] * sizeof(void*));
John Bauman89401822014-05-06 15:04:28 -04002301 }
2302 }
2303 }
2304
Alexis Hetu75a61852017-07-14 14:17:14 -04002305 Int4 SamplerCore::computeFilterOffset(Float &lod)
2306 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002307 Int4 filter = -1;
2308
2309 if(state.textureFilter == FILTER_POINT)
Alexis Hetu75a61852017-07-14 14:17:14 -04002310 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002311 filter = 0;
2312 }
2313 else if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
2314 {
2315 filter = CmpNLE(Float4(lod), Float4(0.0f));
Alexis Hetu75a61852017-07-14 14:17:14 -04002316 }
2317 else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR)
2318 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002319 filter = CmpLE(Float4(lod), Float4(0.0f));
Alexis Hetu75a61852017-07-14 14:17:14 -04002320 }
2321
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002322 return filter;
Alexis Hetu75a61852017-07-14 14:17:14 -04002323 }
2324
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002325 Short4 SamplerCore::address(Float4 &uw, AddressingMode addressingMode, Pointer<Byte> &mipmap)
John Bauman89401822014-05-06 15:04:28 -04002326 {
Nicolas Capens7bb62682016-02-08 11:30:56 -05002327 if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY)
2328 {
2329 return Short4(); // Unused
2330 }
2331 else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY)
2332 {
2333 return Min(Max(Short4(RoundInt(uw)), Short4(0)), *Pointer<Short4>(mipmap + OFFSET(Mipmap, depth)) - Short4(1));
2334 }
Nicolas Capensc4b1bfa2017-11-28 15:52:52 -05002335 else if(addressingMode == ADDRESSING_CLAMP || addressingMode == ADDRESSING_BORDER)
John Bauman89401822014-05-06 15:04:28 -04002336 {
2337 Float4 clamp = Min(Max(uw, Float4(0.0f)), Float4(65535.0f / 65536.0f));
2338
Nicolas Capens7bb62682016-02-08 11:30:56 -05002339 return Short4(Int4(clamp * Float4(1 << 16)));
John Bauman89401822014-05-06 15:04:28 -04002340 }
2341 else if(addressingMode == ADDRESSING_MIRROR)
2342 {
2343 Int4 convert = Int4(uw * Float4(1 << 16));
2344 Int4 mirror = (convert << 15) >> 31;
2345
2346 convert ^= mirror;
2347
Nicolas Capens7bb62682016-02-08 11:30:56 -05002348 return Short4(convert);
John Bauman89401822014-05-06 15:04:28 -04002349 }
2350 else if(addressingMode == ADDRESSING_MIRRORONCE)
2351 {
2352 // Absolute value
2353 Int4 convert = Int4(Abs(uw * Float4(1 << 16)));
2354
2355 // Clamp
2356 convert -= Int4(0x00008000, 0x00008000, 0x00008000, 0x00008000);
Nicolas Capens33438a62017-09-27 11:47:35 -04002357 convert = As<Int4>(PackSigned(convert, convert));
John Bauman89401822014-05-06 15:04:28 -04002358
Alexis Hetu90c7ad62016-06-27 11:50:40 -04002359 return As<Short4>(Int2(convert)) + Short4(0x8000u);
John Bauman89401822014-05-06 15:04:28 -04002360 }
Nicolas Capensc4b1bfa2017-11-28 15:52:52 -05002361 else // Wrap
John Bauman89401822014-05-06 15:04:28 -04002362 {
Nicolas Capens7bb62682016-02-08 11:30:56 -05002363 return Short4(Int4(uw * Float4(1 << 16)));
Alexis Hetuf15e8942015-12-01 15:13:23 -05002364 }
2365 }
2366
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002367 void SamplerCore::address(Float4 &uvw, Int4 &xyz0, Int4 &xyz1, Float4 &f, Pointer<Byte> &mipmap, Float4 &texOffset, Int4 &filter, int whd, AddressingMode addressingMode, SamplerFunction function)
Alexis Hetu75a61852017-07-14 14:17:14 -04002368 {
2369 if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY)
2370 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002371 return; // Unused
Alexis Hetu75a61852017-07-14 14:17:14 -04002372 }
2373
2374 Int4 dim = Int4(*Pointer<Short4>(mipmap + whd, 16));
2375 Int4 maxXYZ = dim - Int4(1);
2376
2377 if(function == Fetch)
2378 {
2379 xyz0 = Min(Max(((function.option == Offset) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ);
2380 }
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002381 else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY) // Note: Offset does not apply to array layers
Alexis Hetu75a61852017-07-14 14:17:14 -04002382 {
2383 xyz0 = Min(Max(RoundInt(uvw), Int4(0)), maxXYZ);
2384 }
2385 else
2386 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002387 const int halfBits = 0x3EFFFFFF; // Value just under 0.5f
2388 const int oneBits = 0x3F7FFFFF; // Value just under 1.0f
2389 const int twoBits = 0x3FFFFFFF; // Value just under 2.0f
Alexis Hetu75a61852017-07-14 14:17:14 -04002390
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002391 Float4 coord = uvw;
Alexis Hetu75a61852017-07-14 14:17:14 -04002392 switch(addressingMode)
2393 {
2394 case ADDRESSING_CLAMP:
Nicolas Capensc4b1bfa2017-11-28 15:52:52 -05002395 case ADDRESSING_BORDER:
Alexis Hetu75a61852017-07-14 14:17:14 -04002396 {
2397 Float4 one = As<Float4>(Int4(oneBits));
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002398 coord = Min(Max(coord, Float4(0.0f)), one);
Alexis Hetu75a61852017-07-14 14:17:14 -04002399 }
2400 break;
2401 case ADDRESSING_MIRROR:
2402 {
2403 Float4 half = As<Float4>(Int4(halfBits));
2404 Float4 one = As<Float4>(Int4(oneBits));
2405 Float4 two = As<Float4>(Int4(twoBits));
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002406 coord = one - Abs(two * Frac(coord * half) - one);
Alexis Hetu75a61852017-07-14 14:17:14 -04002407 }
2408 break;
2409 case ADDRESSING_MIRRORONCE:
2410 {
2411 Float4 half = As<Float4>(Int4(halfBits));
2412 Float4 one = As<Float4>(Int4(oneBits));
2413 Float4 two = As<Float4>(Int4(twoBits));
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002414 coord = one - Abs(two * Frac(Min(Max(coord, -one), two) * half) - one);
Alexis Hetu75a61852017-07-14 14:17:14 -04002415 }
2416 break;
Nicolas Capensc4b1bfa2017-11-28 15:52:52 -05002417 default: // Wrap
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002418 coord = Frac(coord);
Alexis Hetu75a61852017-07-14 14:17:14 -04002419 break;
2420 }
2421
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002422 coord = coord * Float4(dim);
2423
2424 if(state.textureFilter == FILTER_POINT ||
2425 state.textureFilter == FILTER_GATHER)
2426 {
2427 xyz0 = Int4(coord);
2428 }
2429 else
2430 {
2431 if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR ||
2432 state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT)
2433 {
2434 coord -= As<Float4>(As<Int4>(Float4(0.5f)) & filter);
2435 }
2436 else
2437 {
2438 coord -= Float4(0.5f);
2439 }
2440
2441 Float4 floor = Floor(coord);
2442 xyz0 = Int4(floor);
2443 f = coord - floor;
2444 }
Alexis Hetu75a61852017-07-14 14:17:14 -04002445
2446 if(function.option == Offset)
2447 {
2448 xyz0 += As<Int4>(texOffset);
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002449 }
2450
2451 xyz1 = xyz0 - filter; // Increment
2452
2453 if(function.option == Offset)
2454 {
Alexis Hetu75a61852017-07-14 14:17:14 -04002455 switch(addressingMode)
2456 {
2457 case ADDRESSING_MIRROR:
2458 case ADDRESSING_MIRRORONCE:
2459 case ADDRESSING_BORDER:
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002460 // FIXME: Implement ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE, and ADDRESSING_BORDER.
2461 // Fall through to Clamp.
Alexis Hetu75a61852017-07-14 14:17:14 -04002462 case ADDRESSING_CLAMP:
2463 xyz0 = Min(Max(xyz0, Int4(0)), maxXYZ);
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002464 xyz1 = Min(Max(xyz1, Int4(0)), maxXYZ);
Alexis Hetu75a61852017-07-14 14:17:14 -04002465 break;
2466 default: // Wrap
2467 xyz0 = (xyz0 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim;
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002468 xyz1 = (xyz1 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim;
Alexis Hetu75a61852017-07-14 14:17:14 -04002469 break;
2470 }
2471 }
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002472 else if(state.textureFilter != FILTER_POINT)
Alexis Hetu75a61852017-07-14 14:17:14 -04002473 {
Alexis Hetu75a61852017-07-14 14:17:14 -04002474 switch(addressingMode)
2475 {
2476 case ADDRESSING_MIRROR:
2477 case ADDRESSING_MIRRORONCE:
2478 case ADDRESSING_BORDER:
Alexis Hetu75a61852017-07-14 14:17:14 -04002479 case ADDRESSING_CLAMP:
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002480 xyz0 = Max(xyz0, Int4(0));
2481 xyz1 = Min(xyz1, maxXYZ);
Alexis Hetu75a61852017-07-14 14:17:14 -04002482 break;
2483 default: // Wrap
2484 {
Nicolas Capensf8b827e2017-11-27 15:25:05 -05002485 Int4 under = CmpLT(xyz0, Int4(0));
2486 xyz0 = (under & maxXYZ) | (~under & xyz0); // xyz < 0 ? dim - 1 : xyz // FIXME: IfThenElse()
2487
2488 Int4 nover = CmpLT(xyz1, dim);
2489 xyz1 = nover & xyz1; // xyz >= dim ? 0 : xyz
Alexis Hetu75a61852017-07-14 14:17:14 -04002490 }
2491 break;
2492 }
2493 }
2494 }
2495 }
2496
Alexis Hetu96517182015-04-15 10:30:23 -04002497 void SamplerCore::convertFixed12(Short4 &cs, Float4 &cf)
John Bauman89401822014-05-06 15:04:28 -04002498 {
Alexis Hetu96517182015-04-15 10:30:23 -04002499 cs = RoundShort4(cf * Float4(0x1000));
John Bauman89401822014-05-06 15:04:28 -04002500 }
2501
Alexis Hetu96517182015-04-15 10:30:23 -04002502 void SamplerCore::convertFixed12(Vector4s &cs, Vector4f &cf)
John Bauman89401822014-05-06 15:04:28 -04002503 {
Alexis Hetu96517182015-04-15 10:30:23 -04002504 convertFixed12(cs.x, cf.x);
2505 convertFixed12(cs.y, cf.y);
2506 convertFixed12(cs.z, cf.z);
2507 convertFixed12(cs.w, cf.w);
John Bauman89401822014-05-06 15:04:28 -04002508 }
2509
Alexis Hetu96517182015-04-15 10:30:23 -04002510 void SamplerCore::convertSigned12(Float4 &cf, Short4 &cs)
John Bauman89401822014-05-06 15:04:28 -04002511 {
Alexis Hetu96517182015-04-15 10:30:23 -04002512 cf = Float4(cs) * Float4(1.0f / 0x0FFE);
John Bauman89401822014-05-06 15:04:28 -04002513 }
2514
Alexis Hetu96517182015-04-15 10:30:23 -04002515// void SamplerCore::convertSigned12(Vector4f &cf, Vector4s &cs)
John Bauman89401822014-05-06 15:04:28 -04002516// {
Alexis Hetu96517182015-04-15 10:30:23 -04002517// convertSigned12(cf.x, cs.x);
2518// convertSigned12(cf.y, cs.y);
2519// convertSigned12(cf.z, cs.z);
2520// convertSigned12(cf.w, cs.w);
John Bauman89401822014-05-06 15:04:28 -04002521// }
2522
Alexis Hetu96517182015-04-15 10:30:23 -04002523 void SamplerCore::convertSigned15(Float4 &cf, Short4 &cs)
John Bauman89401822014-05-06 15:04:28 -04002524 {
Alexis Hetu96517182015-04-15 10:30:23 -04002525 cf = Float4(cs) * Float4(1.0f / 0x7FFF);
John Bauman89401822014-05-06 15:04:28 -04002526 }
2527
Alexis Hetu96517182015-04-15 10:30:23 -04002528 void SamplerCore::convertUnsigned16(Float4 &cf, Short4 &cs)
John Bauman89401822014-05-06 15:04:28 -04002529 {
Alexis Hetu96517182015-04-15 10:30:23 -04002530 cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF);
John Bauman89401822014-05-06 15:04:28 -04002531 }
2532
Nicolas Capense1a50af2015-05-13 16:48:18 -04002533 void SamplerCore::sRGBtoLinear16_8_12(Short4 &c)
John Bauman89401822014-05-06 15:04:28 -04002534 {
2535 c = As<UShort4>(c) >> 8;
2536
Nicolas Capense1a50af2015-05-13 16:48:18 -04002537 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_12));
2538
2539 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
2540 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
2541 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 2))), 2);
2542 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
2543 }
2544
2545 void SamplerCore::sRGBtoLinear16_6_12(Short4 &c)
2546 {
2547 c = As<UShort4>(c) >> 10;
2548
2549 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_12));
2550
2551 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
2552 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
2553 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 2))), 2);
2554 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
2555 }
2556
2557 void SamplerCore::sRGBtoLinear16_5_12(Short4 &c)
2558 {
2559 c = As<UShort4>(c) >> 11;
2560
2561 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_12));
John Bauman89401822014-05-06 15:04:28 -04002562
2563 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
2564 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
2565 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 2))), 2);
2566 c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 3))), 3);
2567 }
2568
2569 bool SamplerCore::hasFloatTexture() const
2570 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002571 return Surface::isFloatFormat(state.textureFormat);
John Bauman89401822014-05-06 15:04:28 -04002572 }
2573
Alexis Hetu91dd1c42017-07-18 13:03:42 -04002574 bool SamplerCore::hasUnnormalizedIntegerTexture() const
2575 {
2576 return Surface::isNonNormalizedInteger(state.textureFormat);
2577 }
2578
John Bauman89401822014-05-06 15:04:28 -04002579 bool SamplerCore::hasUnsignedTextureComponent(int component) const
2580 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002581 return Surface::isUnsignedComponent(state.textureFormat, component);
John Bauman89401822014-05-06 15:04:28 -04002582 }
2583
2584 int SamplerCore::textureComponentCount() const
2585 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002586 return Surface::componentCount(state.textureFormat);
John Bauman89401822014-05-06 15:04:28 -04002587 }
2588
Alexis Hetu75a61852017-07-14 14:17:14 -04002589 bool SamplerCore::hasThirdCoordinate() const
2590 {
2591 return (state.textureType == TEXTURE_3D) || (state.textureType == TEXTURE_2D_ARRAY);
2592 }
2593
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002594 bool SamplerCore::has16bitTextureFormat() const
John Bauman89401822014-05-06 15:04:28 -04002595 {
2596 switch(state.textureFormat)
2597 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002598 case FORMAT_R5G6B5:
2599 return true;
Alexis Hetu3412d872015-10-26 16:40:26 -04002600 case FORMAT_R8I_SNORM:
2601 case FORMAT_G8R8I_SNORM:
2602 case FORMAT_X8B8G8R8I_SNORM:
2603 case FORMAT_A8B8G8R8I_SNORM:
2604 case FORMAT_R8I:
2605 case FORMAT_R8UI:
2606 case FORMAT_G8R8I:
2607 case FORMAT_G8R8UI:
2608 case FORMAT_X8B8G8R8I:
2609 case FORMAT_X8B8G8R8UI:
2610 case FORMAT_A8B8G8R8I:
2611 case FORMAT_A8B8G8R8UI:
2612 case FORMAT_R32I:
2613 case FORMAT_R32UI:
2614 case FORMAT_G32R32I:
2615 case FORMAT_G32R32UI:
2616 case FORMAT_X32B32G32R32I:
2617 case FORMAT_X32B32G32R32UI:
2618 case FORMAT_A32B32G32R32I:
2619 case FORMAT_A32B32G32R32UI:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002620 case FORMAT_G8R8:
2621 case FORMAT_X8R8G8B8:
2622 case FORMAT_X8B8G8R8:
2623 case FORMAT_A8R8G8B8:
2624 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -04002625 case FORMAT_SRGB8_X8:
2626 case FORMAT_SRGB8_A8:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002627 case FORMAT_V8U8:
2628 case FORMAT_Q8W8V8U8:
2629 case FORMAT_X8L8V8U8:
2630 case FORMAT_R32F:
2631 case FORMAT_G32R32F:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002632 case FORMAT_X32B32G32R32F:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002633 case FORMAT_A32B32G32R32F:
2634 case FORMAT_A8:
2635 case FORMAT_R8:
2636 case FORMAT_L8:
2637 case FORMAT_A8L8:
Alexis Hetu3412d872015-10-26 16:40:26 -04002638 case FORMAT_D32F:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002639 case FORMAT_D32F_LOCKABLE:
2640 case FORMAT_D32FS8_TEXTURE:
2641 case FORMAT_D32FS8_SHADOW:
2642 case FORMAT_L16:
2643 case FORMAT_G16R16:
2644 case FORMAT_A16B16G16R16:
2645 case FORMAT_V16U16:
2646 case FORMAT_A16W16V16U16:
2647 case FORMAT_Q16W16V16U16:
Alexis Hetu3412d872015-10-26 16:40:26 -04002648 case FORMAT_R16I:
2649 case FORMAT_R16UI:
2650 case FORMAT_G16R16I:
2651 case FORMAT_G16R16UI:
2652 case FORMAT_X16B16G16R16I:
2653 case FORMAT_X16B16G16R16UI:
2654 case FORMAT_A16B16G16R16I:
2655 case FORMAT_A16B16G16R16UI:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002656 case FORMAT_YV12_BT601:
2657 case FORMAT_YV12_BT709:
2658 case FORMAT_YV12_JFIF:
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002659 return false;
2660 default:
2661 ASSERT(false);
2662 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05002663
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002664 return false;
2665 }
2666
Nicolas Capens21bda852015-09-01 10:23:33 -04002667 bool SamplerCore::has8bitTextureComponents() const
2668 {
2669 switch(state.textureFormat)
2670 {
Nicolas Capens21bda852015-09-01 10:23:33 -04002671 case FORMAT_G8R8:
2672 case FORMAT_X8R8G8B8:
2673 case FORMAT_X8B8G8R8:
2674 case FORMAT_A8R8G8B8:
2675 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -04002676 case FORMAT_SRGB8_X8:
2677 case FORMAT_SRGB8_A8:
Nicolas Capens21bda852015-09-01 10:23:33 -04002678 case FORMAT_V8U8:
2679 case FORMAT_Q8W8V8U8:
2680 case FORMAT_X8L8V8U8:
2681 case FORMAT_A8:
2682 case FORMAT_R8:
2683 case FORMAT_L8:
2684 case FORMAT_A8L8:
Alexis Hetu3412d872015-10-26 16:40:26 -04002685 case FORMAT_R8I_SNORM:
2686 case FORMAT_G8R8I_SNORM:
2687 case FORMAT_X8B8G8R8I_SNORM:
2688 case FORMAT_A8B8G8R8I_SNORM:
2689 case FORMAT_R8I:
2690 case FORMAT_R8UI:
2691 case FORMAT_G8R8I:
2692 case FORMAT_G8R8UI:
2693 case FORMAT_X8B8G8R8I:
2694 case FORMAT_X8B8G8R8UI:
2695 case FORMAT_A8B8G8R8I:
2696 case FORMAT_A8B8G8R8UI:
Nicolas Capens21bda852015-09-01 10:23:33 -04002697 return true;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002698 case FORMAT_R5G6B5:
Nicolas Capens21bda852015-09-01 10:23:33 -04002699 case FORMAT_R32F:
2700 case FORMAT_G32R32F:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002701 case FORMAT_X32B32G32R32F:
Nicolas Capens21bda852015-09-01 10:23:33 -04002702 case FORMAT_A32B32G32R32F:
Alexis Hetu3412d872015-10-26 16:40:26 -04002703 case FORMAT_D32F:
Nicolas Capens21bda852015-09-01 10:23:33 -04002704 case FORMAT_D32F_LOCKABLE:
2705 case FORMAT_D32FS8_TEXTURE:
2706 case FORMAT_D32FS8_SHADOW:
2707 case FORMAT_L16:
2708 case FORMAT_G16R16:
2709 case FORMAT_A16B16G16R16:
2710 case FORMAT_V16U16:
2711 case FORMAT_A16W16V16U16:
2712 case FORMAT_Q16W16V16U16:
Alexis Hetu3412d872015-10-26 16:40:26 -04002713 case FORMAT_R32I:
2714 case FORMAT_R32UI:
2715 case FORMAT_G32R32I:
2716 case FORMAT_G32R32UI:
2717 case FORMAT_X32B32G32R32I:
2718 case FORMAT_X32B32G32R32UI:
2719 case FORMAT_A32B32G32R32I:
2720 case FORMAT_A32B32G32R32UI:
2721 case FORMAT_R16I:
2722 case FORMAT_R16UI:
2723 case FORMAT_G16R16I:
2724 case FORMAT_G16R16UI:
2725 case FORMAT_X16B16G16R16I:
2726 case FORMAT_X16B16G16R16UI:
2727 case FORMAT_A16B16G16R16I:
2728 case FORMAT_A16B16G16R16UI:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002729 case FORMAT_YV12_BT601:
2730 case FORMAT_YV12_BT709:
2731 case FORMAT_YV12_JFIF:
Nicolas Capens21bda852015-09-01 10:23:33 -04002732 return false;
2733 default:
2734 ASSERT(false);
2735 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05002736
Nicolas Capens21bda852015-09-01 10:23:33 -04002737 return false;
2738 }
2739
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002740 bool SamplerCore::has16bitTextureComponents() const
2741 {
2742 switch(state.textureFormat)
2743 {
2744 case FORMAT_R5G6B5:
Alexis Hetu3412d872015-10-26 16:40:26 -04002745 case FORMAT_R8I_SNORM:
2746 case FORMAT_G8R8I_SNORM:
2747 case FORMAT_X8B8G8R8I_SNORM:
2748 case FORMAT_A8B8G8R8I_SNORM:
2749 case FORMAT_R8I:
2750 case FORMAT_R8UI:
2751 case FORMAT_G8R8I:
2752 case FORMAT_G8R8UI:
2753 case FORMAT_X8B8G8R8I:
2754 case FORMAT_X8B8G8R8UI:
2755 case FORMAT_A8B8G8R8I:
2756 case FORMAT_A8B8G8R8UI:
2757 case FORMAT_R32I:
2758 case FORMAT_R32UI:
2759 case FORMAT_G32R32I:
2760 case FORMAT_G32R32UI:
2761 case FORMAT_X32B32G32R32I:
2762 case FORMAT_X32B32G32R32UI:
2763 case FORMAT_A32B32G32R32I:
2764 case FORMAT_A32B32G32R32UI:
John Bauman89401822014-05-06 15:04:28 -04002765 case FORMAT_G8R8:
2766 case FORMAT_X8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -04002767 case FORMAT_X8B8G8R8:
John Bauman89401822014-05-06 15:04:28 -04002768 case FORMAT_A8R8G8B8:
Nicolas Capensb508eaf2015-03-28 18:44:48 -04002769 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -04002770 case FORMAT_SRGB8_X8:
2771 case FORMAT_SRGB8_A8:
John Bauman89401822014-05-06 15:04:28 -04002772 case FORMAT_V8U8:
2773 case FORMAT_Q8W8V8U8:
2774 case FORMAT_X8L8V8U8:
2775 case FORMAT_R32F:
2776 case FORMAT_G32R32F:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002777 case FORMAT_X32B32G32R32F:
John Bauman89401822014-05-06 15:04:28 -04002778 case FORMAT_A32B32G32R32F:
2779 case FORMAT_A8:
2780 case FORMAT_R8:
2781 case FORMAT_L8:
2782 case FORMAT_A8L8:
Alexis Hetu3412d872015-10-26 16:40:26 -04002783 case FORMAT_D32F:
John Bauman89401822014-05-06 15:04:28 -04002784 case FORMAT_D32F_LOCKABLE:
John Bauman66b8ab22014-05-06 15:57:45 -04002785 case FORMAT_D32FS8_TEXTURE:
2786 case FORMAT_D32FS8_SHADOW:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002787 case FORMAT_YV12_BT601:
2788 case FORMAT_YV12_BT709:
2789 case FORMAT_YV12_JFIF:
John Bauman89401822014-05-06 15:04:28 -04002790 return false;
2791 case FORMAT_L16:
2792 case FORMAT_G16R16:
2793 case FORMAT_A16B16G16R16:
Alexis Hetu3412d872015-10-26 16:40:26 -04002794 case FORMAT_R16I:
2795 case FORMAT_R16UI:
2796 case FORMAT_G16R16I:
2797 case FORMAT_G16R16UI:
2798 case FORMAT_X16B16G16R16I:
2799 case FORMAT_X16B16G16R16UI:
2800 case FORMAT_A16B16G16R16I:
2801 case FORMAT_A16B16G16R16UI:
John Bauman89401822014-05-06 15:04:28 -04002802 case FORMAT_V16U16:
2803 case FORMAT_A16W16V16U16:
2804 case FORMAT_Q16W16V16U16:
2805 return true;
2806 default:
2807 ASSERT(false);
2808 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05002809
John Bauman89401822014-05-06 15:04:28 -04002810 return false;
2811 }
2812
Alexis Hetu91dd1c42017-07-18 13:03:42 -04002813 bool SamplerCore::has32bitIntegerTextureComponents() const
2814 {
2815 switch(state.textureFormat)
2816 {
2817 case FORMAT_R5G6B5:
2818 case FORMAT_R8I_SNORM:
2819 case FORMAT_G8R8I_SNORM:
2820 case FORMAT_X8B8G8R8I_SNORM:
2821 case FORMAT_A8B8G8R8I_SNORM:
2822 case FORMAT_R8I:
2823 case FORMAT_R8UI:
2824 case FORMAT_G8R8I:
2825 case FORMAT_G8R8UI:
2826 case FORMAT_X8B8G8R8I:
2827 case FORMAT_X8B8G8R8UI:
2828 case FORMAT_A8B8G8R8I:
2829 case FORMAT_A8B8G8R8UI:
2830 case FORMAT_G8R8:
2831 case FORMAT_X8R8G8B8:
2832 case FORMAT_X8B8G8R8:
2833 case FORMAT_A8R8G8B8:
2834 case FORMAT_A8B8G8R8:
2835 case FORMAT_SRGB8_X8:
2836 case FORMAT_SRGB8_A8:
2837 case FORMAT_V8U8:
2838 case FORMAT_Q8W8V8U8:
2839 case FORMAT_X8L8V8U8:
2840 case FORMAT_L16:
2841 case FORMAT_G16R16:
2842 case FORMAT_A16B16G16R16:
2843 case FORMAT_R16I:
2844 case FORMAT_R16UI:
2845 case FORMAT_G16R16I:
2846 case FORMAT_G16R16UI:
2847 case FORMAT_X16B16G16R16I:
2848 case FORMAT_X16B16G16R16UI:
2849 case FORMAT_A16B16G16R16I:
2850 case FORMAT_A16B16G16R16UI:
2851 case FORMAT_V16U16:
2852 case FORMAT_A16W16V16U16:
2853 case FORMAT_Q16W16V16U16:
2854 case FORMAT_R32F:
2855 case FORMAT_G32R32F:
2856 case FORMAT_X32B32G32R32F:
2857 case FORMAT_A32B32G32R32F:
2858 case FORMAT_A8:
2859 case FORMAT_R8:
2860 case FORMAT_L8:
2861 case FORMAT_A8L8:
2862 case FORMAT_D32F:
2863 case FORMAT_D32F_LOCKABLE:
2864 case FORMAT_D32FS8_TEXTURE:
2865 case FORMAT_D32FS8_SHADOW:
2866 case FORMAT_YV12_BT601:
2867 case FORMAT_YV12_BT709:
2868 case FORMAT_YV12_JFIF:
2869 return false;
2870 case FORMAT_R32I:
2871 case FORMAT_R32UI:
2872 case FORMAT_G32R32I:
2873 case FORMAT_G32R32UI:
2874 case FORMAT_X32B32G32R32I:
2875 case FORMAT_X32B32G32R32UI:
2876 case FORMAT_A32B32G32R32I:
2877 case FORMAT_A32B32G32R32UI:
2878 return true;
2879 default:
2880 ASSERT(false);
2881 }
2882
2883 return false;
2884 }
2885
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002886 bool SamplerCore::hasYuvFormat() const
2887 {
2888 switch(state.textureFormat)
2889 {
2890 case FORMAT_YV12_BT601:
2891 case FORMAT_YV12_BT709:
2892 case FORMAT_YV12_JFIF:
2893 return true;
2894 case FORMAT_R5G6B5:
Alexis Hetu3412d872015-10-26 16:40:26 -04002895 case FORMAT_R8I_SNORM:
2896 case FORMAT_G8R8I_SNORM:
2897 case FORMAT_X8B8G8R8I_SNORM:
2898 case FORMAT_A8B8G8R8I_SNORM:
2899 case FORMAT_R8I:
2900 case FORMAT_R8UI:
2901 case FORMAT_G8R8I:
2902 case FORMAT_G8R8UI:
2903 case FORMAT_X8B8G8R8I:
2904 case FORMAT_X8B8G8R8UI:
2905 case FORMAT_A8B8G8R8I:
2906 case FORMAT_A8B8G8R8UI:
2907 case FORMAT_R32I:
2908 case FORMAT_R32UI:
2909 case FORMAT_G32R32I:
2910 case FORMAT_G32R32UI:
2911 case FORMAT_X32B32G32R32I:
2912 case FORMAT_X32B32G32R32UI:
2913 case FORMAT_A32B32G32R32I:
2914 case FORMAT_A32B32G32R32UI:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002915 case FORMAT_G8R8:
2916 case FORMAT_X8R8G8B8:
2917 case FORMAT_X8B8G8R8:
2918 case FORMAT_A8R8G8B8:
2919 case FORMAT_A8B8G8R8:
Alexis Hetu049a1872016-04-25 16:59:58 -04002920 case FORMAT_SRGB8_X8:
2921 case FORMAT_SRGB8_A8:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002922 case FORMAT_V8U8:
2923 case FORMAT_Q8W8V8U8:
2924 case FORMAT_X8L8V8U8:
2925 case FORMAT_R32F:
2926 case FORMAT_G32R32F:
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002927 case FORMAT_X32B32G32R32F:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002928 case FORMAT_A32B32G32R32F:
2929 case FORMAT_A8:
2930 case FORMAT_R8:
2931 case FORMAT_L8:
2932 case FORMAT_A8L8:
Alexis Hetu3412d872015-10-26 16:40:26 -04002933 case FORMAT_D32F:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002934 case FORMAT_D32F_LOCKABLE:
2935 case FORMAT_D32FS8_TEXTURE:
2936 case FORMAT_D32FS8_SHADOW:
2937 case FORMAT_L16:
2938 case FORMAT_G16R16:
2939 case FORMAT_A16B16G16R16:
Alexis Hetu3412d872015-10-26 16:40:26 -04002940 case FORMAT_R16I:
2941 case FORMAT_R16UI:
2942 case FORMAT_G16R16I:
2943 case FORMAT_G16R16UI:
2944 case FORMAT_X16B16G16R16I:
2945 case FORMAT_X16B16G16R16UI:
2946 case FORMAT_A16B16G16R16I:
2947 case FORMAT_A16B16G16R16UI:
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002948 case FORMAT_V16U16:
2949 case FORMAT_A16W16V16U16:
2950 case FORMAT_Q16W16V16U16:
2951 return false;
2952 default:
2953 ASSERT(false);
2954 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05002955
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04002956 return false;
2957 }
2958
John Bauman89401822014-05-06 15:04:28 -04002959 bool SamplerCore::isRGBComponent(int component) const
2960 {
2961 switch(state.textureFormat)
2962 {
Nicolas Capensd43f4ce2015-05-13 17:39:44 -04002963 case FORMAT_R5G6B5: return component < 3;
Alexis Hetu3412d872015-10-26 16:40:26 -04002964 case FORMAT_R8I_SNORM: return component < 1;
2965 case FORMAT_G8R8I_SNORM: return component < 2;
2966 case FORMAT_X8B8G8R8I_SNORM: return component < 3;
2967 case FORMAT_A8B8G8R8I_SNORM: return component < 3;
2968 case FORMAT_R8I: return component < 1;
2969 case FORMAT_R8UI: return component < 1;
2970 case FORMAT_G8R8I: return component < 2;
2971 case FORMAT_G8R8UI: return component < 2;
2972 case FORMAT_X8B8G8R8I: return component < 3;
2973 case FORMAT_X8B8G8R8UI: return component < 3;
2974 case FORMAT_A8B8G8R8I: return component < 3;
2975 case FORMAT_A8B8G8R8UI: return component < 3;
2976 case FORMAT_R32I: return component < 1;
2977 case FORMAT_R32UI: return component < 1;
2978 case FORMAT_G32R32I: return component < 2;
2979 case FORMAT_G32R32UI: return component < 2;
2980 case FORMAT_X32B32G32R32I: return component < 3;
2981 case FORMAT_X32B32G32R32UI: return component < 3;
2982 case FORMAT_A32B32G32R32I: return component < 3;
2983 case FORMAT_A32B32G32R32UI: return component < 3;
John Bauman66b8ab22014-05-06 15:57:45 -04002984 case FORMAT_G8R8: return component < 2;
2985 case FORMAT_X8R8G8B8: return component < 3;
Nicolas Capensb508eaf2015-03-28 18:44:48 -04002986 case FORMAT_X8B8G8R8: return component < 3;
John Bauman66b8ab22014-05-06 15:57:45 -04002987 case FORMAT_A8R8G8B8: return component < 3;
Nicolas Capensb508eaf2015-03-28 18:44:48 -04002988 case FORMAT_A8B8G8R8: return component < 3;
Alexis Hetu049a1872016-04-25 16:59:58 -04002989 case FORMAT_SRGB8_X8: return component < 3;
2990 case FORMAT_SRGB8_A8: return component < 3;
John Bauman66b8ab22014-05-06 15:57:45 -04002991 case FORMAT_V8U8: return false;
2992 case FORMAT_Q8W8V8U8: return false;
2993 case FORMAT_X8L8V8U8: return false;
2994 case FORMAT_R32F: return component < 1;
2995 case FORMAT_G32R32F: return component < 2;
Alexis Hetudbd1a8e2016-04-13 11:40:30 -04002996 case FORMAT_X32B32G32R32F: return component < 3;
John Bauman66b8ab22014-05-06 15:57:45 -04002997 case FORMAT_A32B32G32R32F: return component < 3;
2998 case FORMAT_A8: return false;
2999 case FORMAT_R8: return component < 1;
3000 case FORMAT_L8: return component < 1;
3001 case FORMAT_A8L8: return component < 1;
Alexis Hetu3412d872015-10-26 16:40:26 -04003002 case FORMAT_D32F: return false;
John Bauman66b8ab22014-05-06 15:57:45 -04003003 case FORMAT_D32F_LOCKABLE: return false;
3004 case FORMAT_D32FS8_TEXTURE: return false;
3005 case FORMAT_D32FS8_SHADOW: return false;
3006 case FORMAT_L16: return component < 1;
3007 case FORMAT_G16R16: return component < 2;
3008 case FORMAT_A16B16G16R16: return component < 3;
Alexis Hetu3412d872015-10-26 16:40:26 -04003009 case FORMAT_R16I: return component < 1;
3010 case FORMAT_R16UI: return component < 1;
3011 case FORMAT_G16R16I: return component < 2;
3012 case FORMAT_G16R16UI: return component < 2;
3013 case FORMAT_X16B16G16R16I: return component < 3;
3014 case FORMAT_X16B16G16R16UI: return component < 3;
3015 case FORMAT_A16B16G16R16I: return component < 3;
3016 case FORMAT_A16B16G16R16UI: return component < 3;
John Bauman66b8ab22014-05-06 15:57:45 -04003017 case FORMAT_V16U16: return false;
3018 case FORMAT_A16W16V16U16: return false;
3019 case FORMAT_Q16W16V16U16: return false;
Nicolas Capens8e8a7e82015-09-01 14:39:57 -04003020 case FORMAT_YV12_BT601: return component < 3;
3021 case FORMAT_YV12_BT709: return component < 3;
3022 case FORMAT_YV12_JFIF: return component < 3;
John Bauman89401822014-05-06 15:04:28 -04003023 default:
3024 ASSERT(false);
3025 }
Alexis Hetu3b96fa82016-02-04 21:15:03 -05003026
John Bauman89401822014-05-06 15:04:28 -04003027 return false;
3028 }
3029}