1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // 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 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // 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. 14 15 #include "SamplerCore.hpp" 16 17 #include "Constants.hpp" 18 #include "Common/Debug.hpp" 19 20 namespace 21 { applySwizzle(sw::SwizzleType swizzle,sw::Short4 & s,const sw::Vector4s & c)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; 30 case sw::SWIZZLE_ZERO: s = sw::Short4(0x0000); break; 31 case sw::SWIZZLE_ONE: s = sw::Short4(0x1000); break; 32 default: ASSERT(false); 33 } 34 } 35 applySwizzle(sw::SwizzleType swizzle,sw::Float4 & f,const sw::Vector4f & c)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 51 namespace sw 52 { 53 extern bool colorsDefaultToZero; 54 SamplerCore(Pointer<Byte> & constants,const Sampler::State & state)55 SamplerCore::SamplerCore(Pointer<Byte> &constants, const Sampler::State &state) : constants(constants), state(state) 56 { 57 } 58 sampleTexture(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Float4 & q,Float4 & bias,Vector4f & dsx,Vector4f & dsy)59 Vector4s SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy) 60 { 61 return sampleTexture(texture, u, v, w, q, q, dsx, dsy, (dsx), Implicit, true); 62 } 63 sampleTexture(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Float4 & q,Float4 & bias,Vector4f & dsx,Vector4f & dsy,Vector4f & offset,SamplerFunction function,bool fixed12)64 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) 65 { 66 Vector4s c; 67 68 #if PERF_PROFILE 69 AddAtomic(Pointer<Long>(&profiler.texOperations), 4); 70 71 if(state.compressedFormat) 72 { 73 AddAtomic(Pointer<Long>(&profiler.compressedTex), 4); 74 } 75 #endif 76 77 if(state.textureType == TEXTURE_NULL) 78 { 79 c.x = Short4(0x0000); 80 c.y = Short4(0x0000); 81 c.z = Short4(0x0000); 82 83 if(fixed12) // FIXME: Convert to fixed12 at higher level, when required 84 { 85 c.w = Short4(0x1000); 86 } 87 else 88 { 89 c.w = Short4(0xFFFFu); // FIXME 90 } 91 } 92 else 93 { 94 Float4 uuuu = u; 95 Float4 vvvv = v; 96 Float4 wwww = w; 97 Float4 qqqq = q; 98 99 Int face[4]; 100 Float lod; 101 Float anisotropy; 102 Float4 uDelta; 103 Float4 vDelta; 104 105 if(state.textureType != TEXTURE_3D) 106 { 107 if(state.textureType != TEXTURE_CUBE) 108 { 109 computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function); 110 } 111 else 112 { 113 Float4 M; 114 cubeFace(face, uuuu, vvvv, u, v, w, M); 115 computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function); 116 } 117 } 118 else 119 { 120 computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function); 121 } 122 123 if(!hasFloatTexture()) 124 { 125 c = sampleFilter(texture, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function); 126 } 127 else 128 { 129 Vector4f cf = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function); 130 131 convertFixed12(c, cf); 132 } 133 134 if(fixed12) 135 { 136 if(!hasFloatTexture()) 137 { 138 if(state.textureFormat == FORMAT_R5G6B5) 139 { 140 c.x = MulHigh(As<UShort4>(c.x), UShort4(0x10000000 / 0xF800)); 141 c.y = MulHigh(As<UShort4>(c.y), UShort4(0x10000000 / 0xFC00)); 142 c.z = MulHigh(As<UShort4>(c.z), UShort4(0x10000000 / 0xF800)); 143 } 144 else 145 { 146 for(int component = 0; component < textureComponentCount(); component++) 147 { 148 if(hasUnsignedTextureComponent(component)) 149 { 150 c[component] = As<UShort4>(c[component]) >> 4; 151 } 152 else 153 { 154 c[component] = c[component] >> 3; 155 } 156 } 157 } 158 } 159 160 if(state.textureFilter != FILTER_GATHER) 161 { 162 int componentCount = textureComponentCount(); 163 short defaultColorValue = colorsDefaultToZero ? 0x0000 : 0x1000; 164 165 switch(state.textureFormat) 166 { 167 case FORMAT_R8_SNORM: 168 case FORMAT_G8R8_SNORM: 169 case FORMAT_X8B8G8R8_SNORM: 170 case FORMAT_A8B8G8R8_SNORM: 171 case FORMAT_R8: 172 case FORMAT_R5G6B5: 173 case FORMAT_G8R8: 174 case FORMAT_R8I: 175 case FORMAT_R8UI: 176 case FORMAT_G8R8I: 177 case FORMAT_G8R8UI: 178 case FORMAT_X8B8G8R8I: 179 case FORMAT_X8B8G8R8UI: 180 case FORMAT_A8B8G8R8I: 181 case FORMAT_A8B8G8R8UI: 182 case FORMAT_R16I: 183 case FORMAT_R16UI: 184 case FORMAT_G16R16: 185 case FORMAT_G16R16I: 186 case FORMAT_G16R16UI: 187 case FORMAT_X16B16G16R16I: 188 case FORMAT_X16B16G16R16UI: 189 case FORMAT_A16B16G16R16: 190 case FORMAT_A16B16G16R16I: 191 case FORMAT_A16B16G16R16UI: 192 case FORMAT_R32I: 193 case FORMAT_R32UI: 194 case FORMAT_G32R32I: 195 case FORMAT_G32R32UI: 196 case FORMAT_X32B32G32R32I: 197 case FORMAT_X32B32G32R32UI: 198 case FORMAT_A32B32G32R32I: 199 case FORMAT_A32B32G32R32UI: 200 case FORMAT_X8R8G8B8: 201 case FORMAT_X8B8G8R8: 202 case FORMAT_A8R8G8B8: 203 case FORMAT_A8B8G8R8: 204 case FORMAT_SRGB8_X8: 205 case FORMAT_SRGB8_A8: 206 case FORMAT_V8U8: 207 case FORMAT_Q8W8V8U8: 208 case FORMAT_X8L8V8U8: 209 case FORMAT_V16U16: 210 case FORMAT_A16W16V16U16: 211 case FORMAT_Q16W16V16U16: 212 case FORMAT_YV12_BT601: 213 case FORMAT_YV12_BT709: 214 case FORMAT_YV12_JFIF: 215 if(componentCount < 2) c.y = Short4(defaultColorValue); 216 if(componentCount < 3) c.z = Short4(defaultColorValue); 217 if(componentCount < 4) c.w = Short4(0x1000); 218 break; 219 case FORMAT_A8: 220 c.w = c.x; 221 c.x = Short4(0x0000); 222 c.y = Short4(0x0000); 223 c.z = Short4(0x0000); 224 break; 225 case FORMAT_L8: 226 case FORMAT_L16: 227 c.y = c.x; 228 c.z = c.x; 229 c.w = Short4(0x1000); 230 break; 231 case FORMAT_A8L8: 232 c.w = c.y; 233 c.y = c.x; 234 c.z = c.x; 235 break; 236 case FORMAT_R32F: 237 c.y = Short4(defaultColorValue); 238 case FORMAT_G32R32F: 239 c.z = Short4(defaultColorValue); 240 case FORMAT_X32B32G32R32F: 241 case FORMAT_X32B32G32R32F_UNSIGNED: 242 c.w = Short4(0x1000); 243 case FORMAT_A32B32G32R32F: 244 break; 245 case FORMAT_D32F_LOCKABLE: 246 case FORMAT_D32FS8_TEXTURE: 247 case FORMAT_D32F_SHADOW: 248 case FORMAT_D32FS8_SHADOW: 249 c.y = c.x; 250 c.z = c.x; 251 c.w = c.x; 252 break; 253 default: 254 ASSERT(false); 255 } 256 } 257 258 if((state.swizzleR != SWIZZLE_RED) || 259 (state.swizzleG != SWIZZLE_GREEN) || 260 (state.swizzleB != SWIZZLE_BLUE) || 261 (state.swizzleA != SWIZZLE_ALPHA)) 262 { 263 const Vector4s col(c); 264 applySwizzle(state.swizzleR, c.x, col); 265 applySwizzle(state.swizzleG, c.y, col); 266 applySwizzle(state.swizzleB, c.z, col); 267 applySwizzle(state.swizzleA, c.w, col); 268 } 269 } 270 } 271 272 return c; 273 } 274 sampleTexture(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Float4 & q,Float4 & bias,Vector4f & dsx,Vector4f & dsy,Vector4f & offset,SamplerFunction function)275 Vector4f SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function) 276 { 277 Vector4f c; 278 279 #if PERF_PROFILE 280 AddAtomic(Pointer<Long>(&profiler.texOperations), 4); 281 282 if(state.compressedFormat) 283 { 284 AddAtomic(Pointer<Long>(&profiler.compressedTex), 4); 285 } 286 #endif 287 288 if(state.textureType == TEXTURE_NULL) 289 { 290 c.x = Float4(0.0f); 291 c.y = Float4(0.0f); 292 c.z = Float4(0.0f); 293 c.w = Float4(1.0f); 294 } 295 else 296 { 297 // FIXME: YUV is not supported by the floating point path 298 bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT); 299 bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS); 300 bool rectangleTexture = (state.textureType == TEXTURE_RECTANGLE); 301 if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube || rectangleTexture) // FIXME: Mostly identical to integer sampling 302 { 303 Float4 uuuu = u; 304 Float4 vvvv = v; 305 Float4 wwww = w; 306 Float4 qqqq = q; 307 308 Int face[4]; 309 Float lod; 310 Float anisotropy; 311 Float4 uDelta; 312 Float4 vDelta; 313 314 if(state.textureType != TEXTURE_3D) 315 { 316 if(state.textureType != TEXTURE_CUBE) 317 { 318 computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, bias.x, dsx, dsy, function); 319 } 320 else 321 { 322 Float4 M; 323 cubeFace(face, uuuu, vvvv, u, v, w, M); 324 computeLodCube(texture, lod, u, v, w, bias.x, dsx, dsy, M, function); 325 } 326 } 327 else 328 { 329 computeLod3D(texture, lod, uuuu, vvvv, wwww, bias.x, dsx, dsy, function); 330 } 331 332 c = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function); 333 334 if(!hasFloatTexture() && !hasUnnormalizedIntegerTexture()) 335 { 336 if(has16bitTextureFormat()) 337 { 338 switch(state.textureFormat) 339 { 340 case FORMAT_R5G6B5: 341 c.x *= Float4(1.0f / 0xF800); 342 c.y *= Float4(1.0f / 0xFC00); 343 c.z *= Float4(1.0f / 0xF800); 344 break; 345 default: 346 ASSERT(false); 347 } 348 } 349 else 350 { 351 for(int component = 0; component < textureComponentCount(); component++) 352 { 353 c[component] *= Float4(hasUnsignedTextureComponent(component) ? 1.0f / 0xFFFF : 1.0f / 0x7FFF); 354 } 355 } 356 } 357 } 358 else 359 { 360 Vector4s cs = sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, function, false); 361 362 if(state.textureFormat == FORMAT_R5G6B5) 363 { 364 c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800); 365 c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00); 366 c.z = Float4(As<UShort4>(cs.z)) * Float4(1.0f / 0xF800); 367 } 368 else 369 { 370 for(int component = 0; component < textureComponentCount(); component++) 371 { 372 if(hasUnsignedTextureComponent(component)) 373 { 374 convertUnsigned16(c[component], cs[component]); 375 } 376 else 377 { 378 convertSigned15(c[component], cs[component]); 379 } 380 } 381 } 382 } 383 384 int componentCount = textureComponentCount(); 385 float defaultColorValue = colorsDefaultToZero ? 0.0f : 1.0f; 386 387 if(state.textureFilter != FILTER_GATHER) 388 { 389 switch(state.textureFormat) 390 { 391 case FORMAT_R8I: 392 case FORMAT_R8UI: 393 case FORMAT_R16I: 394 case FORMAT_R16UI: 395 case FORMAT_R32I: 396 case FORMAT_R32UI: 397 c.y = As<Float4>(UInt4(0)); 398 case FORMAT_G8R8I: 399 case FORMAT_G8R8UI: 400 case FORMAT_G16R16I: 401 case FORMAT_G16R16UI: 402 case FORMAT_G32R32I: 403 case FORMAT_G32R32UI: 404 c.z = As<Float4>(UInt4(0)); 405 case FORMAT_X8B8G8R8I: 406 case FORMAT_X8B8G8R8UI: 407 case FORMAT_X16B16G16R16I: 408 case FORMAT_X16B16G16R16UI: 409 case FORMAT_X32B32G32R32I: 410 case FORMAT_X32B32G32R32UI: 411 c.w = As<Float4>(UInt4(1)); 412 case FORMAT_A8B8G8R8I: 413 case FORMAT_A8B8G8R8UI: 414 case FORMAT_A16B16G16R16I: 415 case FORMAT_A16B16G16R16UI: 416 case FORMAT_A32B32G32R32I: 417 case FORMAT_A32B32G32R32UI: 418 break; 419 case FORMAT_R8_SNORM: 420 case FORMAT_G8R8_SNORM: 421 case FORMAT_X8B8G8R8_SNORM: 422 case FORMAT_A8B8G8R8_SNORM: 423 case FORMAT_R8: 424 case FORMAT_R5G6B5: 425 case FORMAT_G8R8: 426 case FORMAT_G16R16: 427 case FORMAT_A16B16G16R16: 428 case FORMAT_X8R8G8B8: 429 case FORMAT_X8B8G8R8: 430 case FORMAT_A8R8G8B8: 431 case FORMAT_A8B8G8R8: 432 case FORMAT_SRGB8_X8: 433 case FORMAT_SRGB8_A8: 434 case FORMAT_V8U8: 435 case FORMAT_Q8W8V8U8: 436 case FORMAT_X8L8V8U8: 437 case FORMAT_V16U16: 438 case FORMAT_A16W16V16U16: 439 case FORMAT_Q16W16V16U16: 440 case FORMAT_YV12_BT601: 441 case FORMAT_YV12_BT709: 442 case FORMAT_YV12_JFIF: 443 if(componentCount < 2) c.y = Float4(defaultColorValue); 444 if(componentCount < 3) c.z = Float4(defaultColorValue); 445 if(componentCount < 4) c.w = Float4(1.0f); 446 break; 447 case FORMAT_A8: 448 c.w = c.x; 449 c.x = Float4(0.0f); 450 c.y = Float4(0.0f); 451 c.z = Float4(0.0f); 452 break; 453 case FORMAT_L8: 454 case FORMAT_L16: 455 c.y = c.x; 456 c.z = c.x; 457 c.w = Float4(1.0f); 458 break; 459 case FORMAT_A8L8: 460 c.w = c.y; 461 c.y = c.x; 462 c.z = c.x; 463 break; 464 case FORMAT_R32F: 465 c.y = Float4(defaultColorValue); 466 case FORMAT_G32R32F: 467 c.z = Float4(defaultColorValue); 468 case FORMAT_X32B32G32R32F: 469 case FORMAT_X32B32G32R32F_UNSIGNED: 470 c.w = Float4(1.0f); 471 case FORMAT_A32B32G32R32F: 472 break; 473 case FORMAT_D32F_LOCKABLE: 474 case FORMAT_D32FS8_TEXTURE: 475 case FORMAT_D32F_SHADOW: 476 case FORMAT_D32FS8_SHADOW: 477 c.y = Float4(0.0f); 478 c.z = Float4(0.0f); 479 c.w = Float4(1.0f); 480 break; 481 default: 482 ASSERT(false); 483 } 484 } 485 486 if((state.swizzleR != SWIZZLE_RED) || 487 (state.swizzleG != SWIZZLE_GREEN) || 488 (state.swizzleB != SWIZZLE_BLUE) || 489 (state.swizzleA != SWIZZLE_ALPHA)) 490 { 491 const Vector4f col(c); 492 applySwizzle(state.swizzleR, c.x, col); 493 applySwizzle(state.swizzleG, c.y, col); 494 applySwizzle(state.swizzleB, c.z, col); 495 applySwizzle(state.swizzleA, c.w, col); 496 } 497 } 498 499 return c; 500 } 501 textureSize(Pointer<Byte> & texture,Float4 & lod)502 Vector4f SamplerCore::textureSize(Pointer<Byte> &texture, Float4 &lod) 503 { 504 Vector4f size; 505 506 for(int i = 0; i < 4; ++i) 507 { 508 Int baseLevel = *Pointer<Int>(texture + OFFSET(Texture, baseLevel)); 509 Pointer<Byte> mipmap = texture + OFFSET(Texture, mipmap) + (As<Int>(Extract(lod, i)) + baseLevel) * sizeof(Mipmap); 510 size.x = Insert(size.x, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, width)))), i); 511 size.y = Insert(size.y, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, height)))), i); 512 size.z = Insert(size.z, As<Float>(Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, depth)))), i); 513 } 514 515 return size; 516 } 517 border(Short4 & mask,Float4 & coordinates)518 void SamplerCore::border(Short4 &mask, Float4 &coordinates) 519 { 520 Int4 border = As<Int4>(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f))); 521 mask = As<Short4>(Int2(As<Int4>(PackSigned(border, border)))); 522 } 523 border(Int4 & mask,Float4 & coordinates)524 void SamplerCore::border(Int4 &mask, Float4 &coordinates) 525 { 526 mask = As<Int4>(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f))); 527 } 528 offsetSample(Short4 & uvw,Pointer<Byte> & mipmap,int halfOffset,bool wrap,int count,Float & lod)529 Short4 SamplerCore::offsetSample(Short4 &uvw, Pointer<Byte> &mipmap, int halfOffset, bool wrap, int count, Float &lod) 530 { 531 Short4 offset = *Pointer<Short4>(mipmap + halfOffset); 532 533 if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT) 534 { 535 offset &= Short4(CmpNLE(Float4(lod), Float4(0.0f))); 536 } 537 else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR) 538 { 539 offset &= Short4(CmpLE(Float4(lod), Float4(0.0f))); 540 } 541 542 if(wrap) 543 { 544 switch(count) 545 { 546 case -1: return uvw - offset; 547 case 0: return uvw; 548 case +1: return uvw + offset; 549 case 2: return uvw + offset + offset; 550 } 551 } 552 else // Clamp or mirror 553 { 554 switch(count) 555 { 556 case -1: return SubSat(As<UShort4>(uvw), As<UShort4>(offset)); 557 case 0: return uvw; 558 case +1: return AddSat(As<UShort4>(uvw), As<UShort4>(offset)); 559 case 2: return AddSat(AddSat(As<UShort4>(uvw), As<UShort4>(offset)), As<UShort4>(offset)); 560 } 561 } 562 563 return uvw; 564 } 565 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)566 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) 567 { 568 Vector4s c = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, false, function); 569 570 if(function == Fetch) 571 { 572 return c; 573 } 574 575 if(state.mipmapFilter == MIPMAP_LINEAR) 576 { 577 Vector4s cc = sampleAniso(texture, u, v, w, offset, lod, anisotropy, uDelta, vDelta, face, true, function); 578 579 lod *= Float(1 << 16); 580 581 UShort4 utri = UShort4(Float4(lod)); // FIXME: Optimize 582 Short4 stri = utri >> 1; // FIXME: Optimize 583 584 if(hasUnsignedTextureComponent(0)) cc.x = MulHigh(As<UShort4>(cc.x), utri); else cc.x = MulHigh(cc.x, stri); 585 if(hasUnsignedTextureComponent(1)) cc.y = MulHigh(As<UShort4>(cc.y), utri); else cc.y = MulHigh(cc.y, stri); 586 if(hasUnsignedTextureComponent(2)) cc.z = MulHigh(As<UShort4>(cc.z), utri); else cc.z = MulHigh(cc.z, stri); 587 if(hasUnsignedTextureComponent(3)) cc.w = MulHigh(As<UShort4>(cc.w), utri); else cc.w = MulHigh(cc.w, stri); 588 589 utri = ~utri; 590 stri = Short4(0x7FFF) - stri; 591 592 if(hasUnsignedTextureComponent(0)) c.x = MulHigh(As<UShort4>(c.x), utri); else c.x = MulHigh(c.x, stri); 593 if(hasUnsignedTextureComponent(1)) c.y = MulHigh(As<UShort4>(c.y), utri); else c.y = MulHigh(c.y, stri); 594 if(hasUnsignedTextureComponent(2)) c.z = MulHigh(As<UShort4>(c.z), utri); else c.z = MulHigh(c.z, stri); 595 if(hasUnsignedTextureComponent(3)) c.w = MulHigh(As<UShort4>(c.w), utri); else c.w = MulHigh(c.w, stri); 596 597 c.x += cc.x; 598 c.y += cc.y; 599 c.z += cc.z; 600 c.w += cc.w; 601 602 if(!hasUnsignedTextureComponent(0)) c.x += c.x; 603 if(!hasUnsignedTextureComponent(1)) c.y += c.y; 604 if(!hasUnsignedTextureComponent(2)) c.z += c.z; 605 if(!hasUnsignedTextureComponent(3)) c.w += c.w; 606 } 607 608 Short4 borderMask; 609 610 if(state.addressingModeU == ADDRESSING_BORDER) 611 { 612 Short4 u0; 613 614 border(u0, u); 615 616 borderMask = u0; 617 } 618 619 if(state.addressingModeV == ADDRESSING_BORDER) 620 { 621 Short4 v0; 622 623 border(v0, v); 624 625 if(state.addressingModeU == ADDRESSING_BORDER) 626 { 627 borderMask &= v0; 628 } 629 else 630 { 631 borderMask = v0; 632 } 633 } 634 635 if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D) 636 { 637 Short4 s0; 638 639 border(s0, w); 640 641 if(state.addressingModeU == ADDRESSING_BORDER || 642 state.addressingModeV == ADDRESSING_BORDER) 643 { 644 borderMask &= s0; 645 } 646 else 647 { 648 borderMask = s0; 649 } 650 } 651 652 if(state.addressingModeU == ADDRESSING_BORDER || 653 state.addressingModeV == ADDRESSING_BORDER || 654 (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)) 655 { 656 Short4 b; 657 658 c.x = (borderMask & c.x) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[0])) >> (hasUnsignedTextureComponent(0) ? 0 : 1))); 659 c.y = (borderMask & c.y) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[1])) >> (hasUnsignedTextureComponent(1) ? 0 : 1))); 660 c.z = (borderMask & c.z) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[2])) >> (hasUnsignedTextureComponent(2) ? 0 : 1))); 661 c.w = (borderMask & c.w) | (~borderMask & (*Pointer<Short4>(texture + OFFSET(Texture,borderColor4[3])) >> (hasUnsignedTextureComponent(3) ? 0 : 1))); 662 } 663 664 return c; 665 } 666 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)667 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) 668 { 669 Vector4s c; 670 671 if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch) 672 { 673 c = sampleQuad(texture, u, v, w, offset, lod, face, secondLOD, function); 674 } 675 else 676 { 677 Int a = RoundInt(anisotropy); 678 679 Vector4s cSum; 680 681 cSum.x = Short4(0); 682 cSum.y = Short4(0); 683 cSum.z = Short4(0); 684 cSum.w = Short4(0); 685 686 Float4 A = *Pointer<Float4>(constants + OFFSET(Constants,uvWeight) + 16 * a); 687 Float4 B = *Pointer<Float4>(constants + OFFSET(Constants,uvStart) + 16 * a); 688 UShort4 cw = *Pointer<UShort4>(constants + OFFSET(Constants,cWeight) + 8 * a); 689 Short4 sw = Short4(cw >> 1); 690 691 Float4 du = uDelta; 692 Float4 dv = vDelta; 693 694 Float4 u0 = u + B * du; 695 Float4 v0 = v + B * dv; 696 697 du *= A; 698 dv *= A; 699 700 Int i = 0; 701 702 Do 703 { 704 c = sampleQuad(texture, u0, v0, w, offset, lod, face, secondLOD, function); 705 706 u0 += du; 707 v0 += dv; 708 709 if(hasUnsignedTextureComponent(0)) cSum.x += As<Short4>(MulHigh(As<UShort4>(c.x), cw)); else cSum.x += MulHigh(c.x, sw); 710 if(hasUnsignedTextureComponent(1)) cSum.y += As<Short4>(MulHigh(As<UShort4>(c.y), cw)); else cSum.y += MulHigh(c.y, sw); 711 if(hasUnsignedTextureComponent(2)) cSum.z += As<Short4>(MulHigh(As<UShort4>(c.z), cw)); else cSum.z += MulHigh(c.z, sw); 712 if(hasUnsignedTextureComponent(3)) cSum.w += As<Short4>(MulHigh(As<UShort4>(c.w), cw)); else cSum.w += MulHigh(c.w, sw); 713 714 i++; 715 } 716 Until(i >= a) 717 718 if(hasUnsignedTextureComponent(0)) c.x = cSum.x; else c.x = AddSat(cSum.x, cSum.x); 719 if(hasUnsignedTextureComponent(1)) c.y = cSum.y; else c.y = AddSat(cSum.y, cSum.y); 720 if(hasUnsignedTextureComponent(2)) c.z = cSum.z; else c.z = AddSat(cSum.z, cSum.z); 721 if(hasUnsignedTextureComponent(3)) c.w = cSum.w; else c.w = AddSat(cSum.w, cSum.w); 722 } 723 724 return c; 725 } 726 sampleQuad(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Vector4f & offset,Float & lod,Int face[4],bool secondLOD,SamplerFunction function)727 Vector4s SamplerCore::sampleQuad(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function) 728 { 729 if(state.textureType != TEXTURE_3D) 730 { 731 return sampleQuad2D(texture, u, v, w, offset, lod, face, secondLOD, function); 732 } 733 else 734 { 735 return sample3D(texture, u, v, w, offset, lod, secondLOD, function); 736 } 737 } 738 sampleQuad2D(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Vector4f & offset,Float & lod,Int face[4],bool secondLOD,SamplerFunction function)739 Vector4s SamplerCore::sampleQuad2D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, Int face[4], bool secondLOD, SamplerFunction function) 740 { 741 Vector4s c; 742 743 int componentCount = textureComponentCount(); 744 bool gather = state.textureFilter == FILTER_GATHER; 745 746 Pointer<Byte> mipmap; 747 Pointer<Byte> buffer[4]; 748 749 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); 750 751 bool texelFetch = (function == Fetch); 752 753 Short4 uuuu = texelFetch ? Short4(As<Int4>(u)) : address(u, state.addressingModeU, mipmap); 754 Short4 vvvv = texelFetch ? Short4(As<Int4>(v)) : address(v, state.addressingModeV, mipmap); 755 Short4 wwww = texelFetch ? Short4(As<Int4>(w)) : address(w, state.addressingModeW, mipmap); 756 757 if(state.textureFilter == FILTER_POINT || texelFetch) 758 { 759 c = sampleTexel(uuuu, vvvv, wwww, offset, mipmap, buffer, function); 760 } 761 else 762 { 763 Short4 uuuu0 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 0 : -1, lod); 764 Short4 vvvv0 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 0 : -1, lod); 765 Short4 uuuu1 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 2 : +1, lod); 766 Short4 vvvv1 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 2 : +1, lod); 767 768 Vector4s c0 = sampleTexel(uuuu0, vvvv0, wwww, offset, mipmap, buffer, function); 769 Vector4s c1 = sampleTexel(uuuu1, vvvv0, wwww, offset, mipmap, buffer, function); 770 Vector4s c2 = sampleTexel(uuuu0, vvvv1, wwww, offset, mipmap, buffer, function); 771 Vector4s c3 = sampleTexel(uuuu1, vvvv1, wwww, offset, mipmap, buffer, function); 772 773 if(!gather) // Blend 774 { 775 // Fractions 776 UShort4 f0u = As<UShort4>(uuuu0) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,width)); 777 UShort4 f0v = As<UShort4>(vvvv0) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,height)); 778 779 UShort4 f1u = ~f0u; 780 UShort4 f1v = ~f0v; 781 782 UShort4 f0u0v = MulHigh(f0u, f0v); 783 UShort4 f1u0v = MulHigh(f1u, f0v); 784 UShort4 f0u1v = MulHigh(f0u, f1v); 785 UShort4 f1u1v = MulHigh(f1u, f1v); 786 787 // Signed fractions 788 Short4 f1u1vs; 789 Short4 f0u1vs; 790 Short4 f1u0vs; 791 Short4 f0u0vs; 792 793 if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3)) 794 { 795 f1u1vs = f1u1v >> 1; 796 f0u1vs = f0u1v >> 1; 797 f1u0vs = f1u0v >> 1; 798 f0u0vs = f0u0v >> 1; 799 } 800 801 // Bilinear interpolation 802 if(componentCount >= 1) 803 { 804 if(has16bitTextureComponents() && hasUnsignedTextureComponent(0)) 805 { 806 c0.x = As<UShort4>(c0.x) - MulHigh(As<UShort4>(c0.x), f0u) + MulHigh(As<UShort4>(c1.x), f0u); 807 c2.x = As<UShort4>(c2.x) - MulHigh(As<UShort4>(c2.x), f0u) + MulHigh(As<UShort4>(c3.x), f0u); 808 c.x = As<UShort4>(c0.x) - MulHigh(As<UShort4>(c0.x), f0v) + MulHigh(As<UShort4>(c2.x), f0v); 809 } 810 else 811 { 812 if(hasUnsignedTextureComponent(0)) 813 { 814 c0.x = MulHigh(As<UShort4>(c0.x), f1u1v); 815 c1.x = MulHigh(As<UShort4>(c1.x), f0u1v); 816 c2.x = MulHigh(As<UShort4>(c2.x), f1u0v); 817 c3.x = MulHigh(As<UShort4>(c3.x), f0u0v); 818 } 819 else 820 { 821 c0.x = MulHigh(c0.x, f1u1vs); 822 c1.x = MulHigh(c1.x, f0u1vs); 823 c2.x = MulHigh(c2.x, f1u0vs); 824 c3.x = MulHigh(c3.x, f0u0vs); 825 } 826 827 c.x = (c0.x + c1.x) + (c2.x + c3.x); 828 if(!hasUnsignedTextureComponent(0)) c.x = AddSat(c.x, c.x); // Correct for signed fractions 829 } 830 } 831 832 if(componentCount >= 2) 833 { 834 if(has16bitTextureComponents() && hasUnsignedTextureComponent(1)) 835 { 836 c0.y = As<UShort4>(c0.y) - MulHigh(As<UShort4>(c0.y), f0u) + MulHigh(As<UShort4>(c1.y), f0u); 837 c2.y = As<UShort4>(c2.y) - MulHigh(As<UShort4>(c2.y), f0u) + MulHigh(As<UShort4>(c3.y), f0u); 838 c.y = As<UShort4>(c0.y) - MulHigh(As<UShort4>(c0.y), f0v) + MulHigh(As<UShort4>(c2.y), f0v); 839 } 840 else 841 { 842 if(hasUnsignedTextureComponent(1)) 843 { 844 c0.y = MulHigh(As<UShort4>(c0.y), f1u1v); 845 c1.y = MulHigh(As<UShort4>(c1.y), f0u1v); 846 c2.y = MulHigh(As<UShort4>(c2.y), f1u0v); 847 c3.y = MulHigh(As<UShort4>(c3.y), f0u0v); 848 } 849 else 850 { 851 c0.y = MulHigh(c0.y, f1u1vs); 852 c1.y = MulHigh(c1.y, f0u1vs); 853 c2.y = MulHigh(c2.y, f1u0vs); 854 c3.y = MulHigh(c3.y, f0u0vs); 855 } 856 857 c.y = (c0.y + c1.y) + (c2.y + c3.y); 858 if(!hasUnsignedTextureComponent(1)) c.y = AddSat(c.y, c.y); // Correct for signed fractions 859 } 860 } 861 862 if(componentCount >= 3) 863 { 864 if(has16bitTextureComponents() && hasUnsignedTextureComponent(2)) 865 { 866 c0.z = As<UShort4>(c0.z) - MulHigh(As<UShort4>(c0.z), f0u) + MulHigh(As<UShort4>(c1.z), f0u); 867 c2.z = As<UShort4>(c2.z) - MulHigh(As<UShort4>(c2.z), f0u) + MulHigh(As<UShort4>(c3.z), f0u); 868 c.z = As<UShort4>(c0.z) - MulHigh(As<UShort4>(c0.z), f0v) + MulHigh(As<UShort4>(c2.z), f0v); 869 } 870 else 871 { 872 if(hasUnsignedTextureComponent(2)) 873 { 874 c0.z = MulHigh(As<UShort4>(c0.z), f1u1v); 875 c1.z = MulHigh(As<UShort4>(c1.z), f0u1v); 876 c2.z = MulHigh(As<UShort4>(c2.z), f1u0v); 877 c3.z = MulHigh(As<UShort4>(c3.z), f0u0v); 878 } 879 else 880 { 881 c0.z = MulHigh(c0.z, f1u1vs); 882 c1.z = MulHigh(c1.z, f0u1vs); 883 c2.z = MulHigh(c2.z, f1u0vs); 884 c3.z = MulHigh(c3.z, f0u0vs); 885 } 886 887 c.z = (c0.z + c1.z) + (c2.z + c3.z); 888 if(!hasUnsignedTextureComponent(2)) c.z = AddSat(c.z, c.z); // Correct for signed fractions 889 } 890 } 891 892 if(componentCount >= 4) 893 { 894 if(has16bitTextureComponents() && hasUnsignedTextureComponent(3)) 895 { 896 c0.w = As<UShort4>(c0.w) - MulHigh(As<UShort4>(c0.w), f0u) + MulHigh(As<UShort4>(c1.w), f0u); 897 c2.w = As<UShort4>(c2.w) - MulHigh(As<UShort4>(c2.w), f0u) + MulHigh(As<UShort4>(c3.w), f0u); 898 c.w = As<UShort4>(c0.w) - MulHigh(As<UShort4>(c0.w), f0v) + MulHigh(As<UShort4>(c2.w), f0v); 899 } 900 else 901 { 902 if(hasUnsignedTextureComponent(3)) 903 { 904 c0.w = MulHigh(As<UShort4>(c0.w), f1u1v); 905 c1.w = MulHigh(As<UShort4>(c1.w), f0u1v); 906 c2.w = MulHigh(As<UShort4>(c2.w), f1u0v); 907 c3.w = MulHigh(As<UShort4>(c3.w), f0u0v); 908 } 909 else 910 { 911 c0.w = MulHigh(c0.w, f1u1vs); 912 c1.w = MulHigh(c1.w, f0u1vs); 913 c2.w = MulHigh(c2.w, f1u0vs); 914 c3.w = MulHigh(c3.w, f0u0vs); 915 } 916 917 c.w = (c0.w + c1.w) + (c2.w + c3.w); 918 if(!hasUnsignedTextureComponent(3)) c.w = AddSat(c.w, c.w); // Correct for signed fractions 919 } 920 } 921 } 922 else 923 { 924 c.x = c1.x; 925 c.y = c2.x; 926 c.z = c3.x; 927 c.w = c0.x; 928 } 929 } 930 931 return c; 932 } 933 sample3D(Pointer<Byte> & texture,Float4 & u_,Float4 & v_,Float4 & w_,Vector4f & offset,Float & lod,bool secondLOD,SamplerFunction function)934 Vector4s SamplerCore::sample3D(Pointer<Byte> &texture, Float4 &u_, Float4 &v_, Float4 &w_, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function) 935 { 936 Vector4s c_; 937 938 int componentCount = textureComponentCount(); 939 940 Pointer<Byte> mipmap; 941 Pointer<Byte> buffer[4]; 942 Int face[4]; 943 944 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); 945 946 bool texelFetch = (function == Fetch); 947 948 Short4 uuuu = texelFetch ? Short4(As<Int4>(u_)) : address(u_, state.addressingModeU, mipmap); 949 Short4 vvvv = texelFetch ? Short4(As<Int4>(v_)) : address(v_, state.addressingModeV, mipmap); 950 Short4 wwww = texelFetch ? Short4(As<Int4>(w_)) : address(w_, state.addressingModeW, mipmap); 951 952 if(state.textureFilter == FILTER_POINT || texelFetch) 953 { 954 c_ = sampleTexel(uuuu, vvvv, wwww, offset, mipmap, buffer, function); 955 } 956 else 957 { 958 Vector4s c[2][2][2]; 959 960 Short4 u[2][2][2]; 961 Short4 v[2][2][2]; 962 Short4 s[2][2][2]; 963 964 for(int i = 0; i < 2; i++) 965 { 966 for(int j = 0; j < 2; j++) 967 { 968 for(int k = 0; k < 2; k++) 969 { 970 u[i][j][k] = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, i * 2 - 1, lod); 971 v[i][j][k] = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, j * 2 - 1, lod); 972 s[i][j][k] = offsetSample(wwww, mipmap, OFFSET(Mipmap,wHalf), state.addressingModeW == ADDRESSING_WRAP, k * 2 - 1, lod); 973 } 974 } 975 } 976 977 // Fractions 978 UShort4 f0u = As<UShort4>(u[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,width)); 979 UShort4 f0v = As<UShort4>(v[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,height)); 980 UShort4 f0s = As<UShort4>(s[0][0][0]) * *Pointer<UShort4>(mipmap + OFFSET(Mipmap,depth)); 981 982 UShort4 f1u = ~f0u; 983 UShort4 f1v = ~f0v; 984 UShort4 f1s = ~f0s; 985 986 UShort4 f[2][2][2]; 987 Short4 fs[2][2][2]; 988 989 f[1][1][1] = MulHigh(f1u, f1v); 990 f[0][1][1] = MulHigh(f0u, f1v); 991 f[1][0][1] = MulHigh(f1u, f0v); 992 f[0][0][1] = MulHigh(f0u, f0v); 993 f[1][1][0] = MulHigh(f1u, f1v); 994 f[0][1][0] = MulHigh(f0u, f1v); 995 f[1][0][0] = MulHigh(f1u, f0v); 996 f[0][0][0] = MulHigh(f0u, f0v); 997 998 f[1][1][1] = MulHigh(f[1][1][1], f1s); 999 f[0][1][1] = MulHigh(f[0][1][1], f1s); 1000 f[1][0][1] = MulHigh(f[1][0][1], f1s); 1001 f[0][0][1] = MulHigh(f[0][0][1], f1s); 1002 f[1][1][0] = MulHigh(f[1][1][0], f0s); 1003 f[0][1][0] = MulHigh(f[0][1][0], f0s); 1004 f[1][0][0] = MulHigh(f[1][0][0], f0s); 1005 f[0][0][0] = MulHigh(f[0][0][0], f0s); 1006 1007 // Signed fractions 1008 if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3)) 1009 { 1010 fs[0][0][0] = f[0][0][0] >> 1; 1011 fs[0][0][1] = f[0][0][1] >> 1; 1012 fs[0][1][0] = f[0][1][0] >> 1; 1013 fs[0][1][1] = f[0][1][1] >> 1; 1014 fs[1][0][0] = f[1][0][0] >> 1; 1015 fs[1][0][1] = f[1][0][1] >> 1; 1016 fs[1][1][0] = f[1][1][0] >> 1; 1017 fs[1][1][1] = f[1][1][1] >> 1; 1018 } 1019 1020 for(int i = 0; i < 2; i++) 1021 { 1022 for(int j = 0; j < 2; j++) 1023 { 1024 for(int k = 0; k < 2; k++) 1025 { 1026 c[i][j][k] = sampleTexel(u[i][j][k], v[i][j][k], s[i][j][k], offset, mipmap, buffer, function); 1027 1028 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]); } 1029 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]); } 1030 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]); } 1031 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]); } 1032 1033 if(i != 0 || j != 0 || k != 0) 1034 { 1035 if(componentCount >= 1) c[0][0][0].x += c[i][j][k].x; 1036 if(componentCount >= 2) c[0][0][0].y += c[i][j][k].y; 1037 if(componentCount >= 3) c[0][0][0].z += c[i][j][k].z; 1038 if(componentCount >= 4) c[0][0][0].w += c[i][j][k].w; 1039 } 1040 } 1041 } 1042 } 1043 1044 if(componentCount >= 1) c_.x = c[0][0][0].x; 1045 if(componentCount >= 2) c_.y = c[0][0][0].y; 1046 if(componentCount >= 3) c_.z = c[0][0][0].z; 1047 if(componentCount >= 4) c_.w = c[0][0][0].w; 1048 1049 // Correct for signed fractions 1050 if(componentCount >= 1) if(!hasUnsignedTextureComponent(0)) c_.x = AddSat(c_.x, c_.x); 1051 if(componentCount >= 2) if(!hasUnsignedTextureComponent(1)) c_.y = AddSat(c_.y, c_.y); 1052 if(componentCount >= 3) if(!hasUnsignedTextureComponent(2)) c_.z = AddSat(c_.z, c_.z); 1053 if(componentCount >= 4) if(!hasUnsignedTextureComponent(3)) c_.w = AddSat(c_.w, c_.w); 1054 } 1055 1056 return c_; 1057 } 1058 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)1059 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) 1060 { 1061 Vector4f c = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, false, function); 1062 1063 if(function == Fetch) 1064 { 1065 return c; 1066 } 1067 1068 if(state.mipmapFilter == MIPMAP_LINEAR) 1069 { 1070 Vector4f cc = sampleFloatAniso(texture, u, v, w, q, offset, lod, anisotropy, uDelta, vDelta, face, true, function); 1071 1072 Float4 lod4 = Float4(Frac(lod)); 1073 1074 c.x = (cc.x - c.x) * lod4 + c.x; 1075 c.y = (cc.y - c.y) * lod4 + c.y; 1076 c.z = (cc.z - c.z) * lod4 + c.z; 1077 c.w = (cc.w - c.w) * lod4 + c.w; 1078 } 1079 1080 Int4 borderMask; 1081 1082 if(state.addressingModeU == ADDRESSING_BORDER) 1083 { 1084 Int4 u0; 1085 1086 border(u0, u); 1087 1088 borderMask = u0; 1089 } 1090 1091 if(state.addressingModeV == ADDRESSING_BORDER) 1092 { 1093 Int4 v0; 1094 1095 border(v0, v); 1096 1097 if(state.addressingModeU == ADDRESSING_BORDER) 1098 { 1099 borderMask &= v0; 1100 } 1101 else 1102 { 1103 borderMask = v0; 1104 } 1105 } 1106 1107 if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D) 1108 { 1109 Int4 s0; 1110 1111 border(s0, w); 1112 1113 if(state.addressingModeU == ADDRESSING_BORDER || 1114 state.addressingModeV == ADDRESSING_BORDER) 1115 { 1116 borderMask &= s0; 1117 } 1118 else 1119 { 1120 borderMask = s0; 1121 } 1122 } 1123 1124 if(state.addressingModeU == ADDRESSING_BORDER || 1125 state.addressingModeV == ADDRESSING_BORDER || 1126 (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)) 1127 { 1128 Int4 b; 1129 1130 c.x = As<Float4>((borderMask & As<Int4>(c.x)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[0])))); 1131 c.y = As<Float4>((borderMask & As<Int4>(c.y)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[1])))); 1132 c.z = As<Float4>((borderMask & As<Int4>(c.z)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[2])))); 1133 c.w = As<Float4>((borderMask & As<Int4>(c.w)) | (~borderMask & *Pointer<Int4>(texture + OFFSET(Texture,borderColorF[3])))); 1134 } 1135 1136 return c; 1137 } 1138 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)1139 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) 1140 { 1141 Vector4f c; 1142 1143 if(state.textureFilter != FILTER_ANISOTROPIC || function == Lod || function == Fetch) 1144 { 1145 c = sampleFloat(texture, u, v, w, q, offset, lod, face, secondLOD, function); 1146 } 1147 else 1148 { 1149 Int a = RoundInt(anisotropy); 1150 1151 Vector4f cSum; 1152 1153 cSum.x = Float4(0.0f); 1154 cSum.y = Float4(0.0f); 1155 cSum.z = Float4(0.0f); 1156 cSum.w = Float4(0.0f); 1157 1158 Float4 A = *Pointer<Float4>(constants + OFFSET(Constants,uvWeight) + 16 * a); 1159 Float4 B = *Pointer<Float4>(constants + OFFSET(Constants,uvStart) + 16 * a); 1160 1161 Float4 du = uDelta; 1162 Float4 dv = vDelta; 1163 1164 Float4 u0 = u + B * du; 1165 Float4 v0 = v + B * dv; 1166 1167 du *= A; 1168 dv *= A; 1169 1170 Int i = 0; 1171 1172 Do 1173 { 1174 c = sampleFloat(texture, u0, v0, w, q, offset, lod, face, secondLOD, function); 1175 1176 u0 += du; 1177 v0 += dv; 1178 1179 cSum.x += c.x * A; 1180 cSum.y += c.y * A; 1181 cSum.z += c.z * A; 1182 cSum.w += c.w * A; 1183 1184 i++; 1185 } 1186 Until(i >= a) 1187 1188 c.x = cSum.x; 1189 c.y = cSum.y; 1190 c.z = cSum.z; 1191 c.w = cSum.w; 1192 } 1193 1194 return c; 1195 } 1196 sampleFloat(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Float4 & q,Vector4f & offset,Float & lod,Int face[4],bool secondLOD,SamplerFunction function)1197 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) 1198 { 1199 if(state.textureType != TEXTURE_3D) 1200 { 1201 return sampleFloat2D(texture, u, v, w, q, offset, lod, face, secondLOD, function); 1202 } 1203 else 1204 { 1205 return sampleFloat3D(texture, u, v, w, offset, lod, secondLOD, function); 1206 } 1207 } 1208 sampleFloat2D(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Float4 & q,Vector4f & offset,Float & lod,Int face[4],bool secondLOD,SamplerFunction function)1209 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) 1210 { 1211 Vector4f c; 1212 1213 int componentCount = textureComponentCount(); 1214 bool gather = state.textureFilter == FILTER_GATHER; 1215 1216 Pointer<Byte> mipmap; 1217 Pointer<Byte> buffer[4]; 1218 1219 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); 1220 1221 Int4 x0, x1, y0, y1, z0; 1222 Float4 fu, fv; 1223 Int4 filter = computeFilterOffset(lod); 1224 address(u, x0, x1, fu, mipmap, offset.x, filter, OFFSET(Mipmap, width), state.addressingModeU, function); 1225 address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function); 1226 address(w, z0, z0, fv, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function); 1227 1228 Int4 pitchP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, pitchP), 16); 1229 y0 *= pitchP; 1230 if(hasThirdCoordinate()) 1231 { 1232 Int4 sliceP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, sliceP), 16); 1233 z0 *= sliceP; 1234 } 1235 1236 if(state.textureFilter == FILTER_POINT || (function == Fetch)) 1237 { 1238 c = sampleTexel(x0, y0, z0, q, mipmap, buffer, function); 1239 } 1240 else 1241 { 1242 y1 *= pitchP; 1243 1244 Vector4f c0 = sampleTexel(x0, y0, z0, q, mipmap, buffer, function); 1245 Vector4f c1 = sampleTexel(x1, y0, z0, q, mipmap, buffer, function); 1246 Vector4f c2 = sampleTexel(x0, y1, z0, q, mipmap, buffer, function); 1247 Vector4f c3 = sampleTexel(x1, y1, z0, q, mipmap, buffer, function); 1248 1249 if(!gather) // Blend 1250 { 1251 if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x); 1252 if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y); 1253 if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z); 1254 if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w); 1255 1256 if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x); 1257 if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y); 1258 if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z); 1259 if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w); 1260 1261 if(componentCount >= 1) c.x = c0.x + fv * (c2.x - c0.x); 1262 if(componentCount >= 2) c.y = c0.y + fv * (c2.y - c0.y); 1263 if(componentCount >= 3) c.z = c0.z + fv * (c2.z - c0.z); 1264 if(componentCount >= 4) c.w = c0.w + fv * (c2.w - c0.w); 1265 } 1266 else 1267 { 1268 c.x = c1.x; 1269 c.y = c2.x; 1270 c.z = c3.x; 1271 c.w = c0.x; 1272 } 1273 } 1274 1275 return c; 1276 } 1277 sampleFloat3D(Pointer<Byte> & texture,Float4 & u,Float4 & v,Float4 & w,Vector4f & offset,Float & lod,bool secondLOD,SamplerFunction function)1278 Vector4f SamplerCore::sampleFloat3D(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Vector4f &offset, Float &lod, bool secondLOD, SamplerFunction function) 1279 { 1280 Vector4f c; 1281 1282 int componentCount = textureComponentCount(); 1283 1284 Pointer<Byte> mipmap; 1285 Pointer<Byte> buffer[4]; 1286 Int face[4]; 1287 1288 selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); 1289 1290 Int4 x0, x1, y0, y1, z0, z1; 1291 Float4 fu, fv, fw; 1292 Int4 filter = computeFilterOffset(lod); 1293 address(u, x0, x1, fu, mipmap, offset.x, filter, OFFSET(Mipmap, width), state.addressingModeU, function); 1294 address(v, y0, y1, fv, mipmap, offset.y, filter, OFFSET(Mipmap, height), state.addressingModeV, function); 1295 address(w, z0, z1, fw, mipmap, offset.z, filter, OFFSET(Mipmap, depth), state.addressingModeW, function); 1296 1297 Int4 pitchP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, pitchP), 16); 1298 Int4 sliceP = *Pointer<Int4>(mipmap + OFFSET(Mipmap, sliceP), 16); 1299 y0 *= pitchP; 1300 z0 *= sliceP; 1301 1302 if(state.textureFilter == FILTER_POINT || (function == Fetch)) 1303 { 1304 c = sampleTexel(x0, y0, z0, w, mipmap, buffer, function); 1305 } 1306 else 1307 { 1308 y1 *= pitchP; 1309 z1 *= sliceP; 1310 1311 Vector4f c0 = sampleTexel(x0, y0, z0, w, mipmap, buffer, function); 1312 Vector4f c1 = sampleTexel(x1, y0, z0, w, mipmap, buffer, function); 1313 Vector4f c2 = sampleTexel(x0, y1, z0, w, mipmap, buffer, function); 1314 Vector4f c3 = sampleTexel(x1, y1, z0, w, mipmap, buffer, function); 1315 Vector4f c4 = sampleTexel(x0, y0, z1, w, mipmap, buffer, function); 1316 Vector4f c5 = sampleTexel(x1, y0, z1, w, mipmap, buffer, function); 1317 Vector4f c6 = sampleTexel(x0, y1, z1, w, mipmap, buffer, function); 1318 Vector4f c7 = sampleTexel(x1, y1, z1, w, mipmap, buffer, function); 1319 1320 // Blend first slice 1321 if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x); 1322 if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y); 1323 if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z); 1324 if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w); 1325 1326 if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x); 1327 if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y); 1328 if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z); 1329 if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w); 1330 1331 if(componentCount >= 1) c0.x = c0.x + fv * (c2.x - c0.x); 1332 if(componentCount >= 2) c0.y = c0.y + fv * (c2.y - c0.y); 1333 if(componentCount >= 3) c0.z = c0.z + fv * (c2.z - c0.z); 1334 if(componentCount >= 4) c0.w = c0.w + fv * (c2.w - c0.w); 1335 1336 // Blend second slice 1337 if(componentCount >= 1) c4.x = c4.x + fu * (c5.x - c4.x); 1338 if(componentCount >= 2) c4.y = c4.y + fu * (c5.y - c4.y); 1339 if(componentCount >= 3) c4.z = c4.z + fu * (c5.z - c4.z); 1340 if(componentCount >= 4) c4.w = c4.w + fu * (c5.w - c4.w); 1341 1342 if(componentCount >= 1) c6.x = c6.x + fu * (c7.x - c6.x); 1343 if(componentCount >= 2) c6.y = c6.y + fu * (c7.y - c6.y); 1344 if(componentCount >= 3) c6.z = c6.z + fu * (c7.z - c6.z); 1345 if(componentCount >= 4) c6.w = c6.w + fu * (c7.w - c6.w); 1346 1347 if(componentCount >= 1) c4.x = c4.x + fv * (c6.x - c4.x); 1348 if(componentCount >= 2) c4.y = c4.y + fv * (c6.y - c4.y); 1349 if(componentCount >= 3) c4.z = c4.z + fv * (c6.z - c4.z); 1350 if(componentCount >= 4) c4.w = c4.w + fv * (c6.w - c4.w); 1351 1352 // Blend slices 1353 if(componentCount >= 1) c.x = c0.x + fw * (c4.x - c0.x); 1354 if(componentCount >= 2) c.y = c0.y + fw * (c4.y - c0.y); 1355 if(componentCount >= 3) c.z = c0.z + fw * (c4.z - c0.z); 1356 if(componentCount >= 4) c.w = c0.w + fw * (c4.w - c0.w); 1357 } 1358 1359 return c; 1360 } 1361 log2sqrt(Float lod)1362 Float SamplerCore::log2sqrt(Float lod) 1363 { 1364 // log2(sqrt(lod)) // Equals 0.25 * log2(lod^2). 1365 lod *= lod; // Squaring doubles the exponent and produces an extra bit of precision. 1366 lod = Float(As<Int>(lod)) - Float(0x3F800000); // Interpret as integer and subtract the exponent bias. 1367 lod *= As<Float>(Int(0x33000000)); // Scale by 0.25 * 2^-23 (mantissa length). 1368 1369 return lod; 1370 } 1371 log2(Float lod)1372 Float SamplerCore::log2(Float lod) 1373 { 1374 lod *= lod; // Squaring doubles the exponent and produces an extra bit of precision. 1375 lod = Float(As<Int>(lod)) - Float(0x3F800000); // Interpret as integer and subtract the exponent bias. 1376 lod *= As<Float>(Int(0x33800000)); // Scale by 0.5 * 2^-23 (mantissa length). 1377 1378 return lod; 1379 } 1380 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)1381 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) 1382 { 1383 if(function != Lod && function != Fetch) 1384 { 1385 Float4 duvdxy; 1386 1387 if(function != Grad) // Implicit 1388 { 1389 duvdxy = Float4(uuuu.yz, vvvv.yz) - Float4(uuuu.xx, vvvv.xx); 1390 } 1391 else 1392 { 1393 Float4 dudxy = Float4(dsx.x.xx, dsy.x.xx); 1394 Float4 dvdxy = Float4(dsx.y.xx, dsy.y.xx); 1395 1396 duvdxy = Float4(dudxy.xz, dvdxy.xz); 1397 } 1398 1399 // Scale by texture dimensions and global LOD. 1400 Float4 dUVdxy = duvdxy * *Pointer<Float4>(texture + OFFSET(Texture,widthHeightLOD)); 1401 1402 Float4 dUV2dxy = dUVdxy * dUVdxy; 1403 Float4 dUV2 = dUV2dxy.xy + dUV2dxy.zw; 1404 1405 lod = Max(Float(dUV2.x), Float(dUV2.y)); // Square length of major axis 1406 1407 if(state.textureFilter == FILTER_ANISOTROPIC) 1408 { 1409 Float det = Abs(Float(dUVdxy.x) * Float(dUVdxy.w) - Float(dUVdxy.y) * Float(dUVdxy.z)); 1410 1411 Float4 dudx = duvdxy.xxxx; 1412 Float4 dudy = duvdxy.yyyy; 1413 Float4 dvdx = duvdxy.zzzz; 1414 Float4 dvdy = duvdxy.wwww; 1415 1416 Int4 mask = As<Int4>(CmpNLT(dUV2.x, dUV2.y)); 1417 uDelta = As<Float4>((As<Int4>(dudx) & mask) | ((As<Int4>(dudy) & ~mask))); 1418 vDelta = As<Float4>((As<Int4>(dvdx) & mask) | ((As<Int4>(dvdy) & ~mask))); 1419 1420 anisotropy = lod * Rcp_pp(det); 1421 anisotropy = Min(anisotropy, *Pointer<Float>(texture + OFFSET(Texture,maxAnisotropy))); 1422 1423 lod *= Rcp_pp(anisotropy * anisotropy); 1424 } 1425 1426 lod = log2sqrt(lod); // log2(sqrt(lod)) 1427 1428 if(function == Bias) 1429 { 1430 lod += lodBias; 1431 } 1432 } 1433 else if(function == Lod) 1434 { 1435 lod = lodBias; 1436 } 1437 else if(function == Fetch) 1438 { 1439 // TODO: Eliminate int-float-int conversion. 1440 lod = Float(As<Int>(lodBias)); 1441 } 1442 else if(function == Base) 1443 { 1444 lod = Float(0); 1445 } 1446 else assert(false); 1447 1448 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod))); 1449 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod))); 1450 } 1451 computeLodCube(Pointer<Byte> & texture,Float & lod,Float4 & u,Float4 & v,Float4 & w,const Float & lodBias,Vector4f & dsx,Vector4f & dsy,Float4 & M,SamplerFunction function)1452 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) 1453 { 1454 if(function != Lod && function != Fetch) 1455 { 1456 Float4 dudxy, dvdxy, dsdxy; 1457 1458 if(function != Grad) // Implicit 1459 { 1460 Float4 U = u * M; 1461 Float4 V = v * M; 1462 Float4 W = w * M; 1463 1464 dudxy = Abs(U - U.xxxx); 1465 dvdxy = Abs(V - V.xxxx); 1466 dsdxy = Abs(W - W.xxxx); 1467 } 1468 else 1469 { 1470 dudxy = Float4(dsx.x.xx, dsy.x.xx); 1471 dvdxy = Float4(dsx.y.xx, dsy.y.xx); 1472 dsdxy = Float4(dsx.z.xx, dsy.z.xx); 1473 1474 dudxy = Abs(dudxy * Float4(M.x)); 1475 dvdxy = Abs(dvdxy * Float4(M.x)); 1476 dsdxy = Abs(dsdxy * Float4(M.x)); 1477 } 1478 1479 // Compute the largest Manhattan distance in two dimensions. 1480 // This takes the footprint across adjacent faces into account. 1481 Float4 duvdxy = dudxy + dvdxy; 1482 Float4 dusdxy = dudxy + dsdxy; 1483 Float4 dvsdxy = dvdxy + dsdxy; 1484 1485 dudxy = Max(Max(duvdxy, dusdxy), dvsdxy); 1486 1487 lod = Max(Float(dudxy.y), Float(dudxy.z)); // FIXME: Max(dudxy.y, dudxy.z); 1488 1489 // Scale by texture dimension and global LOD. 1490 lod *= *Pointer<Float>(texture + OFFSET(Texture,widthLOD)); 1491 1492 lod = log2(lod); 1493 1494 if(function == Bias) 1495 { 1496 lod += lodBias; 1497 } 1498 } 1499 else if(function == Lod) 1500 { 1501 lod = lodBias; 1502 } 1503 else if(function == Fetch) 1504 { 1505 // TODO: Eliminate int-float-int conversion. 1506 lod = Float(As<Int>(lodBias)); 1507 } 1508 else if(function == Base) 1509 { 1510 lod = Float(0); 1511 } 1512 else assert(false); 1513 1514 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod))); 1515 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod))); 1516 } 1517 computeLod3D(Pointer<Byte> & texture,Float & lod,Float4 & uuuu,Float4 & vvvv,Float4 & wwww,const Float & lodBias,Vector4f & dsx,Vector4f & dsy,SamplerFunction function)1518 void SamplerCore::computeLod3D(Pointer<Byte> &texture, Float &lod, Float4 &uuuu, Float4 &vvvv, Float4 &wwww, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerFunction function) 1519 { 1520 if(function != Lod && function != Fetch) 1521 { 1522 Float4 dudxy, dvdxy, dsdxy; 1523 1524 if(function != Grad) // Implicit 1525 { 1526 dudxy = uuuu - uuuu.xxxx; 1527 dvdxy = vvvv - vvvv.xxxx; 1528 dsdxy = wwww - wwww.xxxx; 1529 } 1530 else 1531 { 1532 dudxy = Float4(dsx.x.xx, dsy.x.xx); 1533 dvdxy = Float4(dsx.y.xx, dsy.y.xx); 1534 dsdxy = Float4(dsx.z.xx, dsy.z.xx); 1535 } 1536 1537 // Scale by texture dimensions and global LOD. 1538 dudxy *= *Pointer<Float4>(texture + OFFSET(Texture,widthLOD)); 1539 dvdxy *= *Pointer<Float4>(texture + OFFSET(Texture,heightLOD)); 1540 dsdxy *= *Pointer<Float4>(texture + OFFSET(Texture,depthLOD)); 1541 1542 dudxy *= dudxy; 1543 dvdxy *= dvdxy; 1544 dsdxy *= dsdxy; 1545 1546 dudxy += dvdxy; 1547 dudxy += dsdxy; 1548 1549 lod = Max(Float(dudxy.y), Float(dudxy.z)); // FIXME: Max(dudxy.y, dudxy.z); 1550 1551 lod = log2sqrt(lod); // log2(sqrt(lod)) 1552 1553 if(function == Bias) 1554 { 1555 lod += lodBias; 1556 } 1557 } 1558 else if(function == Lod) 1559 { 1560 lod = lodBias; 1561 } 1562 else if(function == Fetch) 1563 { 1564 // TODO: Eliminate int-float-int conversion. 1565 lod = Float(As<Int>(lodBias)); 1566 } 1567 else if(function == Base) 1568 { 1569 lod = Float(0); 1570 } 1571 else assert(false); 1572 1573 lod = Max(lod, *Pointer<Float>(texture + OFFSET(Texture, minLod))); 1574 lod = Min(lod, *Pointer<Float>(texture + OFFSET(Texture, maxLod))); 1575 } 1576 cubeFace(Int face[4],Float4 & U,Float4 & V,Float4 & x,Float4 & y,Float4 & z,Float4 & M)1577 void SamplerCore::cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &x, Float4 &y, Float4 &z, Float4 &M) 1578 { 1579 Int4 xn = CmpLT(x, Float4(0.0f)); // x < 0 1580 Int4 yn = CmpLT(y, Float4(0.0f)); // y < 0 1581 Int4 zn = CmpLT(z, Float4(0.0f)); // z < 0 1582 1583 Float4 absX = Abs(x); 1584 Float4 absY = Abs(y); 1585 Float4 absZ = Abs(z); 1586 1587 Int4 xy = CmpNLE(absX, absY); // abs(x) > abs(y) 1588 Int4 yz = CmpNLE(absY, absZ); // abs(y) > abs(z) 1589 Int4 zx = CmpNLE(absZ, absX); // abs(z) > abs(x) 1590 Int4 xMajor = xy & ~zx; // abs(x) > abs(y) && abs(x) > abs(z) 1591 Int4 yMajor = yz & ~xy; // abs(y) > abs(z) && abs(y) > abs(x) 1592 Int4 zMajor = zx & ~yz; // abs(z) > abs(x) && abs(z) > abs(y) 1593 1594 // FACE_POSITIVE_X = 000b 1595 // FACE_NEGATIVE_X = 001b 1596 // FACE_POSITIVE_Y = 010b 1597 // FACE_NEGATIVE_Y = 011b 1598 // FACE_POSITIVE_Z = 100b 1599 // FACE_NEGATIVE_Z = 101b 1600 1601 Int yAxis = SignMask(yMajor); 1602 Int zAxis = SignMask(zMajor); 1603 1604 Int4 n = ((xn & xMajor) | (yn & yMajor) | (zn & zMajor)) & Int4(0x80000000); 1605 Int negative = SignMask(n); 1606 1607 face[0] = *Pointer<Int>(constants + OFFSET(Constants,transposeBit0) + negative * 4); 1608 face[0] |= *Pointer<Int>(constants + OFFSET(Constants,transposeBit1) + yAxis * 4); 1609 face[0] |= *Pointer<Int>(constants + OFFSET(Constants,transposeBit2) + zAxis * 4); 1610 face[1] = (face[0] >> 4) & 0x7; 1611 face[2] = (face[0] >> 8) & 0x7; 1612 face[3] = (face[0] >> 12) & 0x7; 1613 face[0] &= 0x7; 1614 1615 M = Max(Max(absX, absY), absZ); 1616 1617 // U = xMajor ? (neg ^ -z) : ((zMajor & neg) ^ x) 1618 U = As<Float4>((xMajor & (n ^ As<Int4>(-z))) | (~xMajor & ((zMajor & n) ^ As<Int4>(x)))); 1619 1620 // V = !yMajor ? -y : (n ^ z) 1621 V = As<Float4>((~yMajor & As<Int4>(-y)) | (yMajor & (n ^ As<Int4>(z)))); 1622 1623 M = reciprocal(M) * Float4(0.5f); 1624 U = U * M + Float4(0.5f); 1625 V = V * M + Float4(0.5f); 1626 } 1627 applyOffset(Short4 & uvw,Float4 & offset,const Int4 & whd,AddressingMode mode)1628 Short4 SamplerCore::applyOffset(Short4 &uvw, Float4 &offset, const Int4 &whd, AddressingMode mode) 1629 { 1630 Int4 tmp = Int4(As<UShort4>(uvw)); 1631 tmp = tmp + As<Int4>(offset); 1632 1633 switch(mode) 1634 { 1635 case AddressingMode::ADDRESSING_WRAP: 1636 tmp = (tmp + whd * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % whd; 1637 break; 1638 case AddressingMode::ADDRESSING_CLAMP: 1639 case AddressingMode::ADDRESSING_MIRROR: 1640 case AddressingMode::ADDRESSING_MIRRORONCE: 1641 case AddressingMode::ADDRESSING_BORDER: // FIXME: Implement and test ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE, ADDRESSING_BORDER 1642 tmp = Min(Max(tmp, Int4(0)), whd - Int4(1)); 1643 break; 1644 case ADDRESSING_TEXELFETCH: 1645 break; 1646 case AddressingMode::ADDRESSING_SEAMLESS: 1647 ASSERT(false); // Cube sampling doesn't support offset. 1648 default: 1649 ASSERT(false); 1650 } 1651 1652 return As<Short4>(UShort4(tmp)); 1653 } 1654 computeIndices(UInt index[4],Short4 uuuu,Short4 vvvv,Short4 wwww,Vector4f & offset,const Pointer<Byte> & mipmap,SamplerFunction function)1655 void SamplerCore::computeIndices(UInt index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, Vector4f &offset, const Pointer<Byte> &mipmap, SamplerFunction function) 1656 { 1657 bool texelFetch = (function == Fetch); 1658 bool hasOffset = (function.option == Offset); 1659 1660 if(!texelFetch) 1661 { 1662 uuuu = MulHigh(As<UShort4>(uuuu), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, width))); 1663 vvvv = MulHigh(As<UShort4>(vvvv), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, height))); 1664 } 1665 1666 if(hasOffset) 1667 { 1668 UShort4 w = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, width)); 1669 uuuu = applyOffset(uuuu, offset.x, Int4(w), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeU); 1670 UShort4 h = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, height)); 1671 vvvv = applyOffset(vvvv, offset.y, Int4(h), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeV); 1672 } 1673 1674 Short4 uuu2 = uuuu; 1675 uuuu = As<Short4>(UnpackLow(uuuu, vvvv)); 1676 uuu2 = As<Short4>(UnpackHigh(uuu2, vvvv)); 1677 uuuu = As<Short4>(MulAdd(uuuu, *Pointer<Short4>(mipmap + OFFSET(Mipmap,onePitchP)))); 1678 uuu2 = As<Short4>(MulAdd(uuu2, *Pointer<Short4>(mipmap + OFFSET(Mipmap,onePitchP)))); 1679 1680 if(hasThirdCoordinate()) 1681 { 1682 if(state.textureType != TEXTURE_2D_ARRAY) 1683 { 1684 if(!texelFetch) 1685 { 1686 wwww = MulHigh(As<UShort4>(wwww), *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth))); 1687 } 1688 1689 if(hasOffset) 1690 { 1691 UShort4 d = *Pointer<UShort4>(mipmap + OFFSET(Mipmap, depth)); 1692 wwww = applyOffset(wwww, offset.z, Int4(d), texelFetch ? ADDRESSING_TEXELFETCH : state.addressingModeW); 1693 } 1694 } 1695 1696 UInt4 uv(As<UInt2>(uuuu), As<UInt2>(uuu2)); 1697 uv += As<UInt4>(Int4(As<UShort4>(wwww))) * *Pointer<UInt4>(mipmap + OFFSET(Mipmap, sliceP)); 1698 1699 index[0] = Extract(As<Int4>(uv), 0); 1700 index[1] = Extract(As<Int4>(uv), 1); 1701 index[2] = Extract(As<Int4>(uv), 2); 1702 index[3] = Extract(As<Int4>(uv), 3); 1703 } 1704 else 1705 { 1706 index[0] = Extract(As<Int2>(uuuu), 0); 1707 index[1] = Extract(As<Int2>(uuuu), 1); 1708 index[2] = Extract(As<Int2>(uuu2), 0); 1709 index[3] = Extract(As<Int2>(uuu2), 1); 1710 } 1711 1712 if(texelFetch) 1713 { 1714 Int size = Int(*Pointer<Int>(mipmap + OFFSET(Mipmap, sliceP))); 1715 if(hasThirdCoordinate()) 1716 { 1717 size *= Int(*Pointer<Short>(mipmap + OFFSET(Mipmap, depth))); 1718 } 1719 UInt min = 0; 1720 UInt max = size - 1; 1721 1722 for(int i = 0; i < 4; i++) 1723 { 1724 index[i] = Min(Max(index[i], min), max); 1725 } 1726 } 1727 } 1728 computeIndices(UInt index[4],Int4 & uuuu,Int4 & vvvv,Int4 & wwww,const Pointer<Byte> & mipmap,SamplerFunction function)1729 void SamplerCore::computeIndices(UInt index[4], Int4& uuuu, Int4& vvvv, Int4& wwww, const Pointer<Byte> &mipmap, SamplerFunction function) 1730 { 1731 UInt4 indices = uuuu + vvvv; 1732 1733 if(hasThirdCoordinate()) 1734 { 1735 indices += As<UInt4>(wwww); 1736 } 1737 1738 for(int i = 0; i < 4; i++) 1739 { 1740 index[i] = Extract(As<Int4>(indices), i); 1741 } 1742 } 1743 sampleTexel(UInt index[4],Pointer<Byte> buffer[4])1744 Vector4s SamplerCore::sampleTexel(UInt index[4], Pointer<Byte> buffer[4]) 1745 { 1746 Vector4s c; 1747 1748 int f0 = state.textureType == TEXTURE_CUBE ? 0 : 0; 1749 int f1 = state.textureType == TEXTURE_CUBE ? 1 : 0; 1750 int f2 = state.textureType == TEXTURE_CUBE ? 2 : 0; 1751 int f3 = state.textureType == TEXTURE_CUBE ? 3 : 0; 1752 1753 if(has16bitTextureFormat()) 1754 { 1755 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0); 1756 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1); 1757 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2); 1758 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3); 1759 1760 switch(state.textureFormat) 1761 { 1762 case FORMAT_R5G6B5: 1763 c.z = (c.x & Short4(0x001Fu)) << 11; 1764 c.y = (c.x & Short4(0x07E0u)) << 5; 1765 c.x = (c.x & Short4(0xF800u)); 1766 break; 1767 default: 1768 ASSERT(false); 1769 } 1770 } 1771 else if(has8bitTextureComponents()) 1772 { 1773 switch(textureComponentCount()) 1774 { 1775 case 4: 1776 { 1777 Byte4 c0 = Pointer<Byte4>(buffer[f0])[index[0]]; 1778 Byte4 c1 = Pointer<Byte4>(buffer[f1])[index[1]]; 1779 Byte4 c2 = Pointer<Byte4>(buffer[f2])[index[2]]; 1780 Byte4 c3 = Pointer<Byte4>(buffer[f3])[index[3]]; 1781 c.x = Unpack(c0, c1); 1782 c.y = Unpack(c2, c3); 1783 1784 switch(state.textureFormat) 1785 { 1786 case FORMAT_A8R8G8B8: 1787 c.z = As<Short4>(UnpackLow(c.x, c.y)); 1788 c.x = As<Short4>(UnpackHigh(c.x, c.y)); 1789 c.y = c.z; 1790 c.w = c.x; 1791 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z)); 1792 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y)); 1793 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x)); 1794 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(c.w)); 1795 break; 1796 case FORMAT_A8B8G8R8: 1797 case FORMAT_A8B8G8R8I: 1798 case FORMAT_A8B8G8R8_SNORM: 1799 case FORMAT_Q8W8V8U8: 1800 case FORMAT_SRGB8_A8: 1801 c.z = As<Short4>(UnpackHigh(c.x, c.y)); 1802 c.x = As<Short4>(UnpackLow(c.x, c.y)); 1803 c.y = c.x; 1804 c.w = c.z; 1805 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x)); 1806 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y)); 1807 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z)); 1808 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(c.w)); 1809 // Propagate sign bit 1810 if(state.textureFormat == FORMAT_A8B8G8R8I) 1811 { 1812 c.x >>= 8; 1813 c.y >>= 8; 1814 c.z >>= 8; 1815 c.w >>= 8; 1816 } 1817 break; 1818 case FORMAT_A8B8G8R8UI: 1819 c.z = As<Short4>(UnpackHigh(c.x, c.y)); 1820 c.x = As<Short4>(UnpackLow(c.x, c.y)); 1821 c.y = c.x; 1822 c.w = c.z; 1823 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(Short4(0))); 1824 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(Short4(0))); 1825 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(Short4(0))); 1826 c.w = UnpackHigh(As<Byte8>(c.w), As<Byte8>(Short4(0))); 1827 break; 1828 default: 1829 ASSERT(false); 1830 } 1831 } 1832 break; 1833 case 3: 1834 { 1835 Byte4 c0 = Pointer<Byte4>(buffer[f0])[index[0]]; 1836 Byte4 c1 = Pointer<Byte4>(buffer[f1])[index[1]]; 1837 Byte4 c2 = Pointer<Byte4>(buffer[f2])[index[2]]; 1838 Byte4 c3 = Pointer<Byte4>(buffer[f3])[index[3]]; 1839 c.x = Unpack(c0, c1); 1840 c.y = Unpack(c2, c3); 1841 1842 switch(state.textureFormat) 1843 { 1844 case FORMAT_X8R8G8B8: 1845 c.z = As<Short4>(UnpackLow(c.x, c.y)); 1846 c.x = As<Short4>(UnpackHigh(c.x, c.y)); 1847 c.y = c.z; 1848 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z)); 1849 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y)); 1850 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x)); 1851 break; 1852 case FORMAT_X8B8G8R8_SNORM: 1853 case FORMAT_X8B8G8R8I: 1854 case FORMAT_X8B8G8R8: 1855 case FORMAT_X8L8V8U8: 1856 case FORMAT_SRGB8_X8: 1857 c.z = As<Short4>(UnpackHigh(c.x, c.y)); 1858 c.x = As<Short4>(UnpackLow(c.x, c.y)); 1859 c.y = c.x; 1860 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(c.x)); 1861 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(c.y)); 1862 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(c.z)); 1863 // Propagate sign bit 1864 if(state.textureFormat == FORMAT_X8B8G8R8I) 1865 { 1866 c.x >>= 8; 1867 c.y >>= 8; 1868 c.z >>= 8; 1869 } 1870 break; 1871 case FORMAT_X8B8G8R8UI: 1872 c.z = As<Short4>(UnpackHigh(c.x, c.y)); 1873 c.x = As<Short4>(UnpackLow(c.x, c.y)); 1874 c.y = c.x; 1875 c.x = UnpackLow(As<Byte8>(c.x), As<Byte8>(Short4(0))); 1876 c.y = UnpackHigh(As<Byte8>(c.y), As<Byte8>(Short4(0))); 1877 c.z = UnpackLow(As<Byte8>(c.z), As<Byte8>(Short4(0))); 1878 break; 1879 default: 1880 ASSERT(false); 1881 } 1882 } 1883 break; 1884 case 2: 1885 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0); 1886 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1); 1887 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2); 1888 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3); 1889 1890 switch(state.textureFormat) 1891 { 1892 case FORMAT_G8R8: 1893 case FORMAT_G8R8_SNORM: 1894 case FORMAT_V8U8: 1895 case FORMAT_A8L8: 1896 c.y = (c.x & Short4(0xFF00u)) | As<Short4>(As<UShort4>(c.x) >> 8); 1897 c.x = (c.x & Short4(0x00FFu)) | (c.x << 8); 1898 break; 1899 case FORMAT_G8R8I: 1900 c.y = c.x >> 8; 1901 c.x = (c.x << 8) >> 8; // Propagate sign bit 1902 break; 1903 case FORMAT_G8R8UI: 1904 c.y = As<Short4>(As<UShort4>(c.x) >> 8); 1905 c.x &= Short4(0x00FFu); 1906 break; 1907 default: 1908 ASSERT(false); 1909 } 1910 break; 1911 case 1: 1912 { 1913 Int c0 = Int(*Pointer<Byte>(buffer[f0] + index[0])); 1914 Int c1 = Int(*Pointer<Byte>(buffer[f1] + index[1])); 1915 Int c2 = Int(*Pointer<Byte>(buffer[f2] + index[2])); 1916 Int c3 = Int(*Pointer<Byte>(buffer[f3] + index[3])); 1917 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24); 1918 1919 switch(state.textureFormat) 1920 { 1921 case FORMAT_R8I: 1922 case FORMAT_R8UI: 1923 { 1924 Int zero(0); 1925 c.x = Unpack(As<Byte4>(c0), As<Byte4>(zero)); 1926 // Propagate sign bit 1927 if(state.textureFormat == FORMAT_R8I) 1928 { 1929 c.x = (c.x << 8) >> 8; 1930 } 1931 } 1932 break; 1933 default: 1934 c.x = Unpack(As<Byte4>(c0)); 1935 break; 1936 } 1937 } 1938 break; 1939 default: 1940 ASSERT(false); 1941 } 1942 } 1943 else if(has16bitTextureComponents()) 1944 { 1945 switch(textureComponentCount()) 1946 { 1947 case 4: 1948 c.x = Pointer<Short4>(buffer[f0])[index[0]]; 1949 c.y = Pointer<Short4>(buffer[f1])[index[1]]; 1950 c.z = Pointer<Short4>(buffer[f2])[index[2]]; 1951 c.w = Pointer<Short4>(buffer[f3])[index[3]]; 1952 transpose4x4(c.x, c.y, c.z, c.w); 1953 break; 1954 case 3: 1955 c.x = Pointer<Short4>(buffer[f0])[index[0]]; 1956 c.y = Pointer<Short4>(buffer[f1])[index[1]]; 1957 c.z = Pointer<Short4>(buffer[f2])[index[2]]; 1958 c.w = Pointer<Short4>(buffer[f3])[index[3]]; 1959 transpose4x3(c.x, c.y, c.z, c.w); 1960 break; 1961 case 2: 1962 c.x = *Pointer<Short4>(buffer[f0] + 4 * index[0]); 1963 c.x = As<Short4>(UnpackLow(c.x, *Pointer<Short4>(buffer[f1] + 4 * index[1]))); 1964 c.z = *Pointer<Short4>(buffer[f2] + 4 * index[2]); 1965 c.z = As<Short4>(UnpackLow(c.z, *Pointer<Short4>(buffer[f3] + 4 * index[3]))); 1966 c.y = c.x; 1967 c.x = UnpackLow(As<Int2>(c.x), As<Int2>(c.z)); 1968 c.y = UnpackHigh(As<Int2>(c.y), As<Int2>(c.z)); 1969 break; 1970 case 1: 1971 c.x = Insert(c.x, Pointer<Short>(buffer[f0])[index[0]], 0); 1972 c.x = Insert(c.x, Pointer<Short>(buffer[f1])[index[1]], 1); 1973 c.x = Insert(c.x, Pointer<Short>(buffer[f2])[index[2]], 2); 1974 c.x = Insert(c.x, Pointer<Short>(buffer[f3])[index[3]], 3); 1975 break; 1976 default: 1977 ASSERT(false); 1978 } 1979 } 1980 else ASSERT(false); 1981 1982 if(state.sRGB) 1983 { 1984 if(state.textureFormat == FORMAT_R5G6B5) 1985 { 1986 sRGBtoLinear16_5_16(c.x); 1987 sRGBtoLinear16_6_16(c.y); 1988 sRGBtoLinear16_5_16(c.z); 1989 } 1990 else 1991 { 1992 for(int i = 0; i < textureComponentCount(); i++) 1993 { 1994 if(isRGBComponent(i)) 1995 { 1996 sRGBtoLinear16_8_16(c[i]); 1997 } 1998 } 1999 } 2000 } 2001 2002 return c; 2003 } 2004 sampleTexel(Short4 & uuuu,Short4 & vvvv,Short4 & wwww,Vector4f & offset,Pointer<Byte> & mipmap,Pointer<Byte> buffer[4],SamplerFunction function)2005 Vector4s SamplerCore::sampleTexel(Short4 &uuuu, Short4 &vvvv, Short4 &wwww, Vector4f &offset, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function) 2006 { 2007 Vector4s c; 2008 2009 UInt index[4]; 2010 computeIndices(index, uuuu, vvvv, wwww, offset, mipmap, function); 2011 2012 if(hasYuvFormat()) 2013 { 2014 // Generic YPbPr to RGB transformation 2015 // R = Y + 2 * (1 - Kr) * Pr 2016 // G = Y - 2 * Kb * (1 - Kb) / Kg * Pb - 2 * Kr * (1 - Kr) / Kg * Pr 2017 // B = Y + 2 * (1 - Kb) * Pb 2018 2019 float Kb = 0.114f; 2020 float Kr = 0.299f; 2021 int studioSwing = 1; 2022 2023 switch(state.textureFormat) 2024 { 2025 case FORMAT_YV12_BT601: 2026 Kb = 0.114f; 2027 Kr = 0.299f; 2028 studioSwing = 1; 2029 break; 2030 case FORMAT_YV12_BT709: 2031 Kb = 0.0722f; 2032 Kr = 0.2126f; 2033 studioSwing = 1; 2034 break; 2035 case FORMAT_YV12_JFIF: 2036 Kb = 0.114f; 2037 Kr = 0.299f; 2038 studioSwing = 0; 2039 break; 2040 default: 2041 ASSERT(false); 2042 } 2043 2044 const float Kg = 1.0f - Kr - Kb; 2045 2046 const float Rr = 2 * (1 - Kr); 2047 const float Gb = -2 * Kb * (1 - Kb) / Kg; 2048 const float Gr = -2 * Kr * (1 - Kr) / Kg; 2049 const float Bb = 2 * (1 - Kb); 2050 2051 // Scaling and bias for studio-swing range: Y = [16 .. 235], U/V = [16 .. 240] 2052 const float Yy = studioSwing ? 255.0f / (235 - 16) : 1.0f; 2053 const float Uu = studioSwing ? 255.0f / (240 - 16) : 1.0f; 2054 const float Vv = studioSwing ? 255.0f / (240 - 16) : 1.0f; 2055 2056 const float Rv = Vv * Rr; 2057 const float Gu = Uu * Gb; 2058 const float Gv = Vv * Gr; 2059 const float Bu = Uu * Bb; 2060 2061 const float R0 = (studioSwing * -16 * Yy - 128 * Rv) / 255; 2062 const float G0 = (studioSwing * -16 * Yy - 128 * Gu - 128 * Gv) / 255; 2063 const float B0 = (studioSwing * -16 * Yy - 128 * Bu) / 255; 2064 2065 Int c0 = Int(buffer[0][index[0]]); 2066 Int c1 = Int(buffer[0][index[1]]); 2067 Int c2 = Int(buffer[0][index[2]]); 2068 Int c3 = Int(buffer[0][index[3]]); 2069 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24); 2070 UShort4 Y = As<UShort4>(Unpack(As<Byte4>(c0))); 2071 2072 computeIndices(index, uuuu, vvvv, wwww, offset, mipmap + sizeof(Mipmap), function); 2073 c0 = Int(buffer[1][index[0]]); 2074 c1 = Int(buffer[1][index[1]]); 2075 c2 = Int(buffer[1][index[2]]); 2076 c3 = Int(buffer[1][index[3]]); 2077 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24); 2078 UShort4 V = As<UShort4>(Unpack(As<Byte4>(c0))); 2079 2080 c0 = Int(buffer[2][index[0]]); 2081 c1 = Int(buffer[2][index[1]]); 2082 c2 = Int(buffer[2][index[2]]); 2083 c3 = Int(buffer[2][index[3]]); 2084 c0 = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24); 2085 UShort4 U = As<UShort4>(Unpack(As<Byte4>(c0))); 2086 2087 const UShort4 yY = UShort4(iround(Yy * 0x4000)); 2088 const UShort4 rV = UShort4(iround(Rv * 0x4000)); 2089 const UShort4 gU = UShort4(iround(-Gu * 0x4000)); 2090 const UShort4 gV = UShort4(iround(-Gv * 0x4000)); 2091 const UShort4 bU = UShort4(iround(Bu * 0x4000)); 2092 2093 const UShort4 r0 = UShort4(iround(-R0 * 0x4000)); 2094 const UShort4 g0 = UShort4(iround(G0 * 0x4000)); 2095 const UShort4 b0 = UShort4(iround(-B0 * 0x4000)); 2096 2097 UShort4 y = MulHigh(Y, yY); 2098 UShort4 r = SubSat(y + MulHigh(V, rV), r0); 2099 UShort4 g = SubSat(y + g0, MulHigh(U, gU) + MulHigh(V, gV)); 2100 UShort4 b = SubSat(y + MulHigh(U, bU), b0); 2101 2102 c.x = Min(r, UShort4(0x3FFF)) << 2; 2103 c.y = Min(g, UShort4(0x3FFF)) << 2; 2104 c.z = Min(b, UShort4(0x3FFF)) << 2; 2105 } 2106 else 2107 { 2108 return sampleTexel(index, buffer); 2109 } 2110 2111 return c; 2112 } 2113 sampleTexel(Int4 & uuuu,Int4 & vvvv,Int4 & wwww,Float4 & z,Pointer<Byte> & mipmap,Pointer<Byte> buffer[4],SamplerFunction function)2114 Vector4f SamplerCore::sampleTexel(Int4 &uuuu, Int4 &vvvv, Int4 &wwww, Float4 &z, Pointer<Byte> &mipmap, Pointer<Byte> buffer[4], SamplerFunction function) 2115 { 2116 Vector4f c; 2117 2118 UInt index[4]; 2119 computeIndices(index, uuuu, vvvv, wwww, mipmap, function); 2120 2121 if(hasFloatTexture() || has32bitIntegerTextureComponents()) 2122 { 2123 int f0 = state.textureType == TEXTURE_CUBE ? 0 : 0; 2124 int f1 = state.textureType == TEXTURE_CUBE ? 1 : 0; 2125 int f2 = state.textureType == TEXTURE_CUBE ? 2 : 0; 2126 int f3 = state.textureType == TEXTURE_CUBE ? 3 : 0; 2127 2128 // Read texels 2129 switch(textureComponentCount()) 2130 { 2131 case 4: 2132 c.x = *Pointer<Float4>(buffer[f0] + index[0] * 16, 16); 2133 c.y = *Pointer<Float4>(buffer[f1] + index[1] * 16, 16); 2134 c.z = *Pointer<Float4>(buffer[f2] + index[2] * 16, 16); 2135 c.w = *Pointer<Float4>(buffer[f3] + index[3] * 16, 16); 2136 transpose4x4(c.x, c.y, c.z, c.w); 2137 break; 2138 case 3: 2139 c.x = *Pointer<Float4>(buffer[f0] + index[0] * 16, 16); 2140 c.y = *Pointer<Float4>(buffer[f1] + index[1] * 16, 16); 2141 c.z = *Pointer<Float4>(buffer[f2] + index[2] * 16, 16); 2142 c.w = *Pointer<Float4>(buffer[f3] + index[3] * 16, 16); 2143 transpose4x3(c.x, c.y, c.z, c.w); 2144 break; 2145 case 2: 2146 // FIXME: Optimal shuffling? 2147 c.x.xy = *Pointer<Float4>(buffer[f0] + index[0] * 8); 2148 c.x.zw = *Pointer<Float4>(buffer[f1] + index[1] * 8 - 8); 2149 c.z.xy = *Pointer<Float4>(buffer[f2] + index[2] * 8); 2150 c.z.zw = *Pointer<Float4>(buffer[f3] + index[3] * 8 - 8); 2151 c.y = c.x; 2152 c.x = Float4(c.x.xz, c.z.xz); 2153 c.y = Float4(c.y.yw, c.z.yw); 2154 break; 2155 case 1: 2156 // FIXME: Optimal shuffling? 2157 c.x.x = *Pointer<Float>(buffer[f0] + index[0] * 4); 2158 c.x.y = *Pointer<Float>(buffer[f1] + index[1] * 4); 2159 c.x.z = *Pointer<Float>(buffer[f2] + index[2] * 4); 2160 c.x.w = *Pointer<Float>(buffer[f3] + index[3] * 4); 2161 break; 2162 default: 2163 ASSERT(false); 2164 } 2165 2166 if(state.compare != COMPARE_BYPASS) 2167 { 2168 Float4 ref = z; 2169 2170 if(!hasFloatTexture()) 2171 { 2172 ref = Min(Max(ref, Float4(0.0f)), Float4(1.0f)); 2173 } 2174 2175 Int4 boolean; 2176 2177 switch(state.compare) 2178 { 2179 case COMPARE_LESSEQUAL: boolean = CmpLE(ref, c.x); break; 2180 case COMPARE_GREATEREQUAL: boolean = CmpNLT(ref, c.x); break; 2181 case COMPARE_LESS: boolean = CmpLT(ref, c.x); break; 2182 case COMPARE_GREATER: boolean = CmpNLE(ref, c.x); break; 2183 case COMPARE_EQUAL: boolean = CmpEQ(ref, c.x); break; 2184 case COMPARE_NOTEQUAL: boolean = CmpNEQ(ref, c.x); break; 2185 case COMPARE_ALWAYS: boolean = Int4(-1); break; 2186 case COMPARE_NEVER: boolean = Int4(0); break; 2187 default: ASSERT(false); 2188 } 2189 2190 c.x = As<Float4>(boolean & As<Int4>(Float4(1.0f))); 2191 c.y = Float4(0.0f); 2192 c.z = Float4(0.0f); 2193 c.w = Float4(1.0f); 2194 } 2195 } 2196 else 2197 { 2198 ASSERT(!hasYuvFormat()); 2199 2200 Vector4s cs = sampleTexel(index, buffer); 2201 2202 bool isInteger = Surface::isNonNormalizedInteger(state.textureFormat); 2203 int componentCount = textureComponentCount(); 2204 for(int n = 0; n < componentCount; n++) 2205 { 2206 if(hasUnsignedTextureComponent(n)) 2207 { 2208 if(isInteger) 2209 { 2210 c[n] = As<Float4>(Int4(As<UShort4>(cs[n]))); 2211 } 2212 else 2213 { 2214 c[n] = Float4(As<UShort4>(cs[n])); 2215 } 2216 } 2217 else 2218 { 2219 if(isInteger) 2220 { 2221 c[n] = As<Float4>(Int4(cs[n])); 2222 } 2223 else 2224 { 2225 c[n] = Float4(cs[n]); 2226 } 2227 } 2228 } 2229 } 2230 2231 return c; 2232 } 2233 selectMipmap(Pointer<Byte> & texture,Pointer<Byte> buffer[4],Pointer<Byte> & mipmap,Float & lod,Int face[4],bool secondLOD)2234 void SamplerCore::selectMipmap(Pointer<Byte> &texture, Pointer<Byte> buffer[4], Pointer<Byte> &mipmap, Float &lod, Int face[4], bool secondLOD) 2235 { 2236 if(state.mipmapFilter == MIPMAP_NONE) 2237 { 2238 mipmap = texture + OFFSET(Texture,mipmap[0]); 2239 } 2240 else 2241 { 2242 Int ilod; 2243 2244 if(state.mipmapFilter == MIPMAP_POINT) 2245 { 2246 ilod = RoundInt(lod); 2247 } 2248 else // MIPMAP_LINEAR 2249 { 2250 ilod = Int(lod); 2251 } 2252 2253 mipmap = texture + OFFSET(Texture,mipmap) + ilod * sizeof(Mipmap) + secondLOD * sizeof(Mipmap); 2254 } 2255 2256 if(state.textureType != TEXTURE_CUBE) 2257 { 2258 buffer[0] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[0])); 2259 2260 if(hasYuvFormat()) 2261 { 2262 buffer[1] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[1])); 2263 buffer[2] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer[2])); 2264 } 2265 } 2266 else 2267 { 2268 for(int i = 0; i < 4; i++) 2269 { 2270 buffer[i] = *Pointer<Pointer<Byte> >(mipmap + OFFSET(Mipmap,buffer) + face[i] * sizeof(void*)); 2271 } 2272 } 2273 } 2274 computeFilterOffset(Float & lod)2275 Int4 SamplerCore::computeFilterOffset(Float &lod) 2276 { 2277 Int4 filter = -1; 2278 2279 if(state.textureFilter == FILTER_POINT) 2280 { 2281 filter = 0; 2282 } 2283 else if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT) 2284 { 2285 filter = CmpNLE(Float4(lod), Float4(0.0f)); 2286 } 2287 else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR) 2288 { 2289 filter = CmpLE(Float4(lod), Float4(0.0f)); 2290 } 2291 2292 return filter; 2293 } 2294 address(Float4 & uw,AddressingMode addressingMode,Pointer<Byte> & mipmap)2295 Short4 SamplerCore::address(Float4 &uw, AddressingMode addressingMode, Pointer<Byte> &mipmap) 2296 { 2297 if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY) 2298 { 2299 return Short4(); // Unused 2300 } 2301 else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY) 2302 { 2303 return Min(Max(Short4(RoundInt(uw)), Short4(0)), *Pointer<Short4>(mipmap + OFFSET(Mipmap, depth)) - Short4(1)); 2304 } 2305 else if(addressingMode == ADDRESSING_CLAMP || addressingMode == ADDRESSING_BORDER) 2306 { 2307 Float4 clamp = Min(Max(uw, Float4(0.0f)), Float4(65535.0f / 65536.0f)); 2308 2309 return Short4(Int4(clamp * Float4(1 << 16))); 2310 } 2311 else if(addressingMode == ADDRESSING_MIRROR) 2312 { 2313 Int4 convert = Int4(uw * Float4(1 << 16)); 2314 Int4 mirror = (convert << 15) >> 31; 2315 2316 convert ^= mirror; 2317 2318 return Short4(convert); 2319 } 2320 else if(addressingMode == ADDRESSING_MIRRORONCE) 2321 { 2322 // Absolute value 2323 Int4 convert = Int4(Abs(uw * Float4(1 << 16))); 2324 2325 // Clamp 2326 convert -= Int4(0x00008000, 0x00008000, 0x00008000, 0x00008000); 2327 convert = As<Int4>(PackSigned(convert, convert)); 2328 2329 return As<Short4>(Int2(convert)) + Short4(0x8000u); 2330 } 2331 else // Wrap 2332 { 2333 return Short4(Int4(uw * Float4(1 << 16))); 2334 } 2335 } 2336 address(Float4 & uvw,Int4 & xyz0,Int4 & xyz1,Float4 & f,Pointer<Byte> & mipmap,Float4 & texOffset,Int4 & filter,int whd,AddressingMode addressingMode,SamplerFunction function)2337 void SamplerCore::address(Float4 &uvw, Int4 &xyz0, Int4 &xyz1, Float4 &f, Pointer<Byte> &mipmap, Float4 &texOffset, Int4 &filter, int whd, AddressingMode addressingMode, SamplerFunction function) 2338 { 2339 if(addressingMode == ADDRESSING_LAYER && state.textureType != TEXTURE_2D_ARRAY) 2340 { 2341 return; // Unused 2342 } 2343 2344 Int4 dim = Int4(*Pointer<Short4>(mipmap + whd, 16)); 2345 Int4 maxXYZ = dim - Int4(1); 2346 2347 if(function == Fetch) 2348 { 2349 xyz0 = Min(Max(((function.option == Offset) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ); 2350 } 2351 else if(addressingMode == ADDRESSING_LAYER && state.textureType == TEXTURE_2D_ARRAY) // Note: Offset does not apply to array layers 2352 { 2353 xyz0 = Min(Max(RoundInt(uvw), Int4(0)), maxXYZ); 2354 } 2355 else 2356 { 2357 const int halfBits = 0x3EFFFFFF; // Value just under 0.5f 2358 const int oneBits = 0x3F7FFFFF; // Value just under 1.0f 2359 const int twoBits = 0x3FFFFFFF; // Value just under 2.0f 2360 2361 bool pointFilter = state.textureFilter == FILTER_POINT || 2362 state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR || 2363 state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT; 2364 2365 Float4 coord = uvw; 2366 2367 if(state.textureType == TEXTURE_RECTANGLE) 2368 { 2369 // According to https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_rectangle.txt 2370 // "CLAMP_TO_EDGE causes the s coordinate to be clamped to the range[0.5, wt - 0.5]. 2371 // CLAMP_TO_EDGE causes the t coordinate to be clamped to the range[0.5, ht - 0.5]." 2372 // Unless SwiftShader implements support for ADDRESSING_BORDER, other modes should be equivalent 2373 // to CLAMP_TO_EDGE. Rectangle textures have no support for any MIRROR or REPEAT modes. 2374 coord = Min(Max(coord, Float4(0.5f)), Float4(dim) - Float4(0.5f)); 2375 } 2376 else 2377 { 2378 switch(addressingMode) 2379 { 2380 case ADDRESSING_CLAMP: 2381 case ADDRESSING_BORDER: 2382 case ADDRESSING_SEAMLESS: 2383 // Linear filtering of cube doesn't require clamping because the coordinates 2384 // are already in [0, 1] range and numerical imprecision is tolerated. 2385 if(addressingMode != ADDRESSING_SEAMLESS || pointFilter) 2386 { 2387 Float4 one = As<Float4>(Int4(oneBits)); 2388 coord = Min(Max(coord, Float4(0.0f)), one); 2389 } 2390 break; 2391 case ADDRESSING_MIRROR: 2392 { 2393 Float4 half = As<Float4>(Int4(halfBits)); 2394 Float4 one = As<Float4>(Int4(oneBits)); 2395 Float4 two = As<Float4>(Int4(twoBits)); 2396 coord = one - Abs(two * Frac(coord * half) - one); 2397 } 2398 break; 2399 case ADDRESSING_MIRRORONCE: 2400 { 2401 Float4 half = As<Float4>(Int4(halfBits)); 2402 Float4 one = As<Float4>(Int4(oneBits)); 2403 Float4 two = As<Float4>(Int4(twoBits)); 2404 coord = one - Abs(two * Frac(Min(Max(coord, -one), two) * half) - one); 2405 } 2406 break; 2407 default: // Wrap 2408 coord = Frac(coord); 2409 break; 2410 } 2411 2412 coord = coord * Float4(dim); 2413 } 2414 2415 if(state.textureFilter == FILTER_POINT || 2416 state.textureFilter == FILTER_GATHER) 2417 { 2418 xyz0 = Int4(coord); 2419 } 2420 else 2421 { 2422 if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR || 2423 state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT) 2424 { 2425 coord -= As<Float4>(As<Int4>(Float4(0.5f)) & filter); 2426 } 2427 else 2428 { 2429 coord -= Float4(0.5f); 2430 } 2431 2432 Float4 floor = Floor(coord); 2433 xyz0 = Int4(floor); 2434 f = coord - floor; 2435 } 2436 2437 if(function.option == Offset) 2438 { 2439 xyz0 += As<Int4>(texOffset); 2440 } 2441 2442 if(addressingMode == ADDRESSING_SEAMLESS) 2443 { 2444 xyz0 += Int4(1); 2445 } 2446 2447 xyz1 = xyz0 - filter; // Increment 2448 2449 if(function.option == Offset) 2450 { 2451 switch(addressingMode) 2452 { 2453 case ADDRESSING_SEAMLESS: 2454 ASSERT(false); // Cube sampling doesn't support offset. 2455 case ADDRESSING_MIRROR: 2456 case ADDRESSING_MIRRORONCE: 2457 case ADDRESSING_BORDER: 2458 // FIXME: Implement ADDRESSING_MIRROR, ADDRESSING_MIRRORONCE, and ADDRESSING_BORDER. 2459 // Fall through to Clamp. 2460 case ADDRESSING_CLAMP: 2461 xyz0 = Min(Max(xyz0, Int4(0)), maxXYZ); 2462 xyz1 = Min(Max(xyz1, Int4(0)), maxXYZ); 2463 break; 2464 default: // Wrap 2465 xyz0 = (xyz0 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim; 2466 xyz1 = (xyz1 + dim * Int4(-MIN_PROGRAM_TEXEL_OFFSET)) % dim; 2467 break; 2468 } 2469 } 2470 else if(state.textureFilter != FILTER_POINT) 2471 { 2472 switch(addressingMode) 2473 { 2474 case ADDRESSING_SEAMLESS: 2475 break; 2476 case ADDRESSING_MIRROR: 2477 case ADDRESSING_MIRRORONCE: 2478 case ADDRESSING_BORDER: 2479 case ADDRESSING_CLAMP: 2480 xyz0 = Max(xyz0, Int4(0)); 2481 xyz1 = Min(xyz1, maxXYZ); 2482 break; 2483 default: // Wrap 2484 { 2485 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 2490 } 2491 break; 2492 } 2493 } 2494 } 2495 } 2496 convertFixed12(Short4 & cs,Float4 & cf)2497 void SamplerCore::convertFixed12(Short4 &cs, Float4 &cf) 2498 { 2499 cs = RoundShort4(cf * Float4(0x1000)); 2500 } 2501 convertFixed12(Vector4s & cs,Vector4f & cf)2502 void SamplerCore::convertFixed12(Vector4s &cs, Vector4f &cf) 2503 { 2504 convertFixed12(cs.x, cf.x); 2505 convertFixed12(cs.y, cf.y); 2506 convertFixed12(cs.z, cf.z); 2507 convertFixed12(cs.w, cf.w); 2508 } 2509 convertSigned12(Float4 & cf,Short4 & cs)2510 void SamplerCore::convertSigned12(Float4 &cf, Short4 &cs) 2511 { 2512 cf = Float4(cs) * Float4(1.0f / 0x0FFE); 2513 } 2514 2515 // void SamplerCore::convertSigned12(Vector4f &cf, Vector4s &cs) 2516 // { 2517 // convertSigned12(cf.x, cs.x); 2518 // convertSigned12(cf.y, cs.y); 2519 // convertSigned12(cf.z, cs.z); 2520 // convertSigned12(cf.w, cs.w); 2521 // } 2522 convertSigned15(Float4 & cf,Short4 & cs)2523 void SamplerCore::convertSigned15(Float4 &cf, Short4 &cs) 2524 { 2525 cf = Float4(cs) * Float4(1.0f / 0x7FFF); 2526 } 2527 convertUnsigned16(Float4 & cf,Short4 & cs)2528 void SamplerCore::convertUnsigned16(Float4 &cf, Short4 &cs) 2529 { 2530 cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF); 2531 } 2532 sRGBtoLinear16_8_16(Short4 & c)2533 void SamplerCore::sRGBtoLinear16_8_16(Short4 &c) 2534 { 2535 c = As<UShort4>(c) >> 8; 2536 2537 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear8_16)); 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 sRGBtoLinear16_6_16(Short4 & c)2545 void SamplerCore::sRGBtoLinear16_6_16(Short4 &c) 2546 { 2547 c = As<UShort4>(c) >> 10; 2548 2549 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear6_16)); 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 sRGBtoLinear16_5_16(Short4 & c)2557 void SamplerCore::sRGBtoLinear16_5_16(Short4 &c) 2558 { 2559 c = As<UShort4>(c) >> 11; 2560 2561 Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants,sRGBtoLinear5_16)); 2562 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 hasFloatTexture() const2569 bool SamplerCore::hasFloatTexture() const 2570 { 2571 return Surface::isFloatFormat(state.textureFormat); 2572 } 2573 hasUnnormalizedIntegerTexture() const2574 bool SamplerCore::hasUnnormalizedIntegerTexture() const 2575 { 2576 return Surface::isNonNormalizedInteger(state.textureFormat); 2577 } 2578 hasUnsignedTextureComponent(int component) const2579 bool SamplerCore::hasUnsignedTextureComponent(int component) const 2580 { 2581 return Surface::isUnsignedComponent(state.textureFormat, component); 2582 } 2583 textureComponentCount() const2584 int SamplerCore::textureComponentCount() const 2585 { 2586 return Surface::componentCount(state.textureFormat); 2587 } 2588 hasThirdCoordinate() const2589 bool SamplerCore::hasThirdCoordinate() const 2590 { 2591 return (state.textureType == TEXTURE_3D) || (state.textureType == TEXTURE_2D_ARRAY); 2592 } 2593 has16bitTextureFormat() const2594 bool SamplerCore::has16bitTextureFormat() const 2595 { 2596 switch(state.textureFormat) 2597 { 2598 case FORMAT_R5G6B5: 2599 return true; 2600 case FORMAT_R8_SNORM: 2601 case FORMAT_G8R8_SNORM: 2602 case FORMAT_X8B8G8R8_SNORM: 2603 case FORMAT_A8B8G8R8_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: 2620 case FORMAT_G8R8: 2621 case FORMAT_X8R8G8B8: 2622 case FORMAT_X8B8G8R8: 2623 case FORMAT_A8R8G8B8: 2624 case FORMAT_A8B8G8R8: 2625 case FORMAT_SRGB8_X8: 2626 case FORMAT_SRGB8_A8: 2627 case FORMAT_V8U8: 2628 case FORMAT_Q8W8V8U8: 2629 case FORMAT_X8L8V8U8: 2630 case FORMAT_R32F: 2631 case FORMAT_G32R32F: 2632 case FORMAT_X32B32G32R32F: 2633 case FORMAT_A32B32G32R32F: 2634 case FORMAT_X32B32G32R32F_UNSIGNED: 2635 case FORMAT_A8: 2636 case FORMAT_R8: 2637 case FORMAT_L8: 2638 case FORMAT_A8L8: 2639 case FORMAT_D32F_LOCKABLE: 2640 case FORMAT_D32FS8_TEXTURE: 2641 case FORMAT_D32F_SHADOW: 2642 case FORMAT_D32FS8_SHADOW: 2643 case FORMAT_L16: 2644 case FORMAT_G16R16: 2645 case FORMAT_A16B16G16R16: 2646 case FORMAT_V16U16: 2647 case FORMAT_A16W16V16U16: 2648 case FORMAT_Q16W16V16U16: 2649 case FORMAT_R16I: 2650 case FORMAT_R16UI: 2651 case FORMAT_G16R16I: 2652 case FORMAT_G16R16UI: 2653 case FORMAT_X16B16G16R16I: 2654 case FORMAT_X16B16G16R16UI: 2655 case FORMAT_A16B16G16R16I: 2656 case FORMAT_A16B16G16R16UI: 2657 case FORMAT_YV12_BT601: 2658 case FORMAT_YV12_BT709: 2659 case FORMAT_YV12_JFIF: 2660 return false; 2661 default: 2662 ASSERT(false); 2663 } 2664 2665 return false; 2666 } 2667 has8bitTextureComponents() const2668 bool SamplerCore::has8bitTextureComponents() const 2669 { 2670 switch(state.textureFormat) 2671 { 2672 case FORMAT_G8R8: 2673 case FORMAT_X8R8G8B8: 2674 case FORMAT_X8B8G8R8: 2675 case FORMAT_A8R8G8B8: 2676 case FORMAT_A8B8G8R8: 2677 case FORMAT_SRGB8_X8: 2678 case FORMAT_SRGB8_A8: 2679 case FORMAT_V8U8: 2680 case FORMAT_Q8W8V8U8: 2681 case FORMAT_X8L8V8U8: 2682 case FORMAT_A8: 2683 case FORMAT_R8: 2684 case FORMAT_L8: 2685 case FORMAT_A8L8: 2686 case FORMAT_R8_SNORM: 2687 case FORMAT_G8R8_SNORM: 2688 case FORMAT_X8B8G8R8_SNORM: 2689 case FORMAT_A8B8G8R8_SNORM: 2690 case FORMAT_R8I: 2691 case FORMAT_R8UI: 2692 case FORMAT_G8R8I: 2693 case FORMAT_G8R8UI: 2694 case FORMAT_X8B8G8R8I: 2695 case FORMAT_X8B8G8R8UI: 2696 case FORMAT_A8B8G8R8I: 2697 case FORMAT_A8B8G8R8UI: 2698 return true; 2699 case FORMAT_R5G6B5: 2700 case FORMAT_R32F: 2701 case FORMAT_G32R32F: 2702 case FORMAT_X32B32G32R32F: 2703 case FORMAT_A32B32G32R32F: 2704 case FORMAT_X32B32G32R32F_UNSIGNED: 2705 case FORMAT_D32F_LOCKABLE: 2706 case FORMAT_D32FS8_TEXTURE: 2707 case FORMAT_D32F_SHADOW: 2708 case FORMAT_D32FS8_SHADOW: 2709 case FORMAT_L16: 2710 case FORMAT_G16R16: 2711 case FORMAT_A16B16G16R16: 2712 case FORMAT_V16U16: 2713 case FORMAT_A16W16V16U16: 2714 case FORMAT_Q16W16V16U16: 2715 case FORMAT_R32I: 2716 case FORMAT_R32UI: 2717 case FORMAT_G32R32I: 2718 case FORMAT_G32R32UI: 2719 case FORMAT_X32B32G32R32I: 2720 case FORMAT_X32B32G32R32UI: 2721 case FORMAT_A32B32G32R32I: 2722 case FORMAT_A32B32G32R32UI: 2723 case FORMAT_R16I: 2724 case FORMAT_R16UI: 2725 case FORMAT_G16R16I: 2726 case FORMAT_G16R16UI: 2727 case FORMAT_X16B16G16R16I: 2728 case FORMAT_X16B16G16R16UI: 2729 case FORMAT_A16B16G16R16I: 2730 case FORMAT_A16B16G16R16UI: 2731 case FORMAT_YV12_BT601: 2732 case FORMAT_YV12_BT709: 2733 case FORMAT_YV12_JFIF: 2734 return false; 2735 default: 2736 ASSERT(false); 2737 } 2738 2739 return false; 2740 } 2741 has16bitTextureComponents() const2742 bool SamplerCore::has16bitTextureComponents() const 2743 { 2744 switch(state.textureFormat) 2745 { 2746 case FORMAT_R5G6B5: 2747 case FORMAT_R8_SNORM: 2748 case FORMAT_G8R8_SNORM: 2749 case FORMAT_X8B8G8R8_SNORM: 2750 case FORMAT_A8B8G8R8_SNORM: 2751 case FORMAT_R8I: 2752 case FORMAT_R8UI: 2753 case FORMAT_G8R8I: 2754 case FORMAT_G8R8UI: 2755 case FORMAT_X8B8G8R8I: 2756 case FORMAT_X8B8G8R8UI: 2757 case FORMAT_A8B8G8R8I: 2758 case FORMAT_A8B8G8R8UI: 2759 case FORMAT_R32I: 2760 case FORMAT_R32UI: 2761 case FORMAT_G32R32I: 2762 case FORMAT_G32R32UI: 2763 case FORMAT_X32B32G32R32I: 2764 case FORMAT_X32B32G32R32UI: 2765 case FORMAT_A32B32G32R32I: 2766 case FORMAT_A32B32G32R32UI: 2767 case FORMAT_G8R8: 2768 case FORMAT_X8R8G8B8: 2769 case FORMAT_X8B8G8R8: 2770 case FORMAT_A8R8G8B8: 2771 case FORMAT_A8B8G8R8: 2772 case FORMAT_SRGB8_X8: 2773 case FORMAT_SRGB8_A8: 2774 case FORMAT_V8U8: 2775 case FORMAT_Q8W8V8U8: 2776 case FORMAT_X8L8V8U8: 2777 case FORMAT_R32F: 2778 case FORMAT_G32R32F: 2779 case FORMAT_X32B32G32R32F: 2780 case FORMAT_A32B32G32R32F: 2781 case FORMAT_X32B32G32R32F_UNSIGNED: 2782 case FORMAT_A8: 2783 case FORMAT_R8: 2784 case FORMAT_L8: 2785 case FORMAT_A8L8: 2786 case FORMAT_D32F_LOCKABLE: 2787 case FORMAT_D32FS8_TEXTURE: 2788 case FORMAT_D32F_SHADOW: 2789 case FORMAT_D32FS8_SHADOW: 2790 case FORMAT_YV12_BT601: 2791 case FORMAT_YV12_BT709: 2792 case FORMAT_YV12_JFIF: 2793 return false; 2794 case FORMAT_L16: 2795 case FORMAT_G16R16: 2796 case FORMAT_A16B16G16R16: 2797 case FORMAT_R16I: 2798 case FORMAT_R16UI: 2799 case FORMAT_G16R16I: 2800 case FORMAT_G16R16UI: 2801 case FORMAT_X16B16G16R16I: 2802 case FORMAT_X16B16G16R16UI: 2803 case FORMAT_A16B16G16R16I: 2804 case FORMAT_A16B16G16R16UI: 2805 case FORMAT_V16U16: 2806 case FORMAT_A16W16V16U16: 2807 case FORMAT_Q16W16V16U16: 2808 return true; 2809 default: 2810 ASSERT(false); 2811 } 2812 2813 return false; 2814 } 2815 has32bitIntegerTextureComponents() const2816 bool SamplerCore::has32bitIntegerTextureComponents() const 2817 { 2818 switch(state.textureFormat) 2819 { 2820 case FORMAT_R5G6B5: 2821 case FORMAT_R8_SNORM: 2822 case FORMAT_G8R8_SNORM: 2823 case FORMAT_X8B8G8R8_SNORM: 2824 case FORMAT_A8B8G8R8_SNORM: 2825 case FORMAT_R8I: 2826 case FORMAT_R8UI: 2827 case FORMAT_G8R8I: 2828 case FORMAT_G8R8UI: 2829 case FORMAT_X8B8G8R8I: 2830 case FORMAT_X8B8G8R8UI: 2831 case FORMAT_A8B8G8R8I: 2832 case FORMAT_A8B8G8R8UI: 2833 case FORMAT_G8R8: 2834 case FORMAT_X8R8G8B8: 2835 case FORMAT_X8B8G8R8: 2836 case FORMAT_A8R8G8B8: 2837 case FORMAT_A8B8G8R8: 2838 case FORMAT_SRGB8_X8: 2839 case FORMAT_SRGB8_A8: 2840 case FORMAT_V8U8: 2841 case FORMAT_Q8W8V8U8: 2842 case FORMAT_X8L8V8U8: 2843 case FORMAT_L16: 2844 case FORMAT_G16R16: 2845 case FORMAT_A16B16G16R16: 2846 case FORMAT_R16I: 2847 case FORMAT_R16UI: 2848 case FORMAT_G16R16I: 2849 case FORMAT_G16R16UI: 2850 case FORMAT_X16B16G16R16I: 2851 case FORMAT_X16B16G16R16UI: 2852 case FORMAT_A16B16G16R16I: 2853 case FORMAT_A16B16G16R16UI: 2854 case FORMAT_V16U16: 2855 case FORMAT_A16W16V16U16: 2856 case FORMAT_Q16W16V16U16: 2857 case FORMAT_R32F: 2858 case FORMAT_G32R32F: 2859 case FORMAT_X32B32G32R32F: 2860 case FORMAT_A32B32G32R32F: 2861 case FORMAT_X32B32G32R32F_UNSIGNED: 2862 case FORMAT_A8: 2863 case FORMAT_R8: 2864 case FORMAT_L8: 2865 case FORMAT_A8L8: 2866 case FORMAT_D32F_LOCKABLE: 2867 case FORMAT_D32FS8_TEXTURE: 2868 case FORMAT_D32F_SHADOW: 2869 case FORMAT_D32FS8_SHADOW: 2870 case FORMAT_YV12_BT601: 2871 case FORMAT_YV12_BT709: 2872 case FORMAT_YV12_JFIF: 2873 return false; 2874 case FORMAT_R32I: 2875 case FORMAT_R32UI: 2876 case FORMAT_G32R32I: 2877 case FORMAT_G32R32UI: 2878 case FORMAT_X32B32G32R32I: 2879 case FORMAT_X32B32G32R32UI: 2880 case FORMAT_A32B32G32R32I: 2881 case FORMAT_A32B32G32R32UI: 2882 return true; 2883 default: 2884 ASSERT(false); 2885 } 2886 2887 return false; 2888 } 2889 hasYuvFormat() const2890 bool SamplerCore::hasYuvFormat() const 2891 { 2892 switch(state.textureFormat) 2893 { 2894 case FORMAT_YV12_BT601: 2895 case FORMAT_YV12_BT709: 2896 case FORMAT_YV12_JFIF: 2897 return true; 2898 case FORMAT_R5G6B5: 2899 case FORMAT_R8_SNORM: 2900 case FORMAT_G8R8_SNORM: 2901 case FORMAT_X8B8G8R8_SNORM: 2902 case FORMAT_A8B8G8R8_SNORM: 2903 case FORMAT_R8I: 2904 case FORMAT_R8UI: 2905 case FORMAT_G8R8I: 2906 case FORMAT_G8R8UI: 2907 case FORMAT_X8B8G8R8I: 2908 case FORMAT_X8B8G8R8UI: 2909 case FORMAT_A8B8G8R8I: 2910 case FORMAT_A8B8G8R8UI: 2911 case FORMAT_R32I: 2912 case FORMAT_R32UI: 2913 case FORMAT_G32R32I: 2914 case FORMAT_G32R32UI: 2915 case FORMAT_X32B32G32R32I: 2916 case FORMAT_X32B32G32R32UI: 2917 case FORMAT_A32B32G32R32I: 2918 case FORMAT_A32B32G32R32UI: 2919 case FORMAT_G8R8: 2920 case FORMAT_X8R8G8B8: 2921 case FORMAT_X8B8G8R8: 2922 case FORMAT_A8R8G8B8: 2923 case FORMAT_A8B8G8R8: 2924 case FORMAT_SRGB8_X8: 2925 case FORMAT_SRGB8_A8: 2926 case FORMAT_V8U8: 2927 case FORMAT_Q8W8V8U8: 2928 case FORMAT_X8L8V8U8: 2929 case FORMAT_R32F: 2930 case FORMAT_G32R32F: 2931 case FORMAT_X32B32G32R32F: 2932 case FORMAT_A32B32G32R32F: 2933 case FORMAT_X32B32G32R32F_UNSIGNED: 2934 case FORMAT_A8: 2935 case FORMAT_R8: 2936 case FORMAT_L8: 2937 case FORMAT_A8L8: 2938 case FORMAT_D32F_LOCKABLE: 2939 case FORMAT_D32FS8_TEXTURE: 2940 case FORMAT_D32F_SHADOW: 2941 case FORMAT_D32FS8_SHADOW: 2942 case FORMAT_L16: 2943 case FORMAT_G16R16: 2944 case FORMAT_A16B16G16R16: 2945 case FORMAT_R16I: 2946 case FORMAT_R16UI: 2947 case FORMAT_G16R16I: 2948 case FORMAT_G16R16UI: 2949 case FORMAT_X16B16G16R16I: 2950 case FORMAT_X16B16G16R16UI: 2951 case FORMAT_A16B16G16R16I: 2952 case FORMAT_A16B16G16R16UI: 2953 case FORMAT_V16U16: 2954 case FORMAT_A16W16V16U16: 2955 case FORMAT_Q16W16V16U16: 2956 return false; 2957 default: 2958 ASSERT(false); 2959 } 2960 2961 return false; 2962 } 2963 isRGBComponent(int component) const2964 bool SamplerCore::isRGBComponent(int component) const 2965 { 2966 switch(state.textureFormat) 2967 { 2968 case FORMAT_R5G6B5: return component < 3; 2969 case FORMAT_R8_SNORM: return component < 1; 2970 case FORMAT_G8R8_SNORM: return component < 2; 2971 case FORMAT_X8B8G8R8_SNORM: return component < 3; 2972 case FORMAT_A8B8G8R8_SNORM: return component < 3; 2973 case FORMAT_R8I: return component < 1; 2974 case FORMAT_R8UI: return component < 1; 2975 case FORMAT_G8R8I: return component < 2; 2976 case FORMAT_G8R8UI: return component < 2; 2977 case FORMAT_X8B8G8R8I: return component < 3; 2978 case FORMAT_X8B8G8R8UI: return component < 3; 2979 case FORMAT_A8B8G8R8I: return component < 3; 2980 case FORMAT_A8B8G8R8UI: return component < 3; 2981 case FORMAT_R32I: return component < 1; 2982 case FORMAT_R32UI: return component < 1; 2983 case FORMAT_G32R32I: return component < 2; 2984 case FORMAT_G32R32UI: return component < 2; 2985 case FORMAT_X32B32G32R32I: return component < 3; 2986 case FORMAT_X32B32G32R32UI: return component < 3; 2987 case FORMAT_A32B32G32R32I: return component < 3; 2988 case FORMAT_A32B32G32R32UI: return component < 3; 2989 case FORMAT_G8R8: return component < 2; 2990 case FORMAT_X8R8G8B8: return component < 3; 2991 case FORMAT_X8B8G8R8: return component < 3; 2992 case FORMAT_A8R8G8B8: return component < 3; 2993 case FORMAT_A8B8G8R8: return component < 3; 2994 case FORMAT_SRGB8_X8: return component < 3; 2995 case FORMAT_SRGB8_A8: return component < 3; 2996 case FORMAT_V8U8: return false; 2997 case FORMAT_Q8W8V8U8: return false; 2998 case FORMAT_X8L8V8U8: return false; 2999 case FORMAT_R32F: return component < 1; 3000 case FORMAT_G32R32F: return component < 2; 3001 case FORMAT_X32B32G32R32F: return component < 3; 3002 case FORMAT_A32B32G32R32F: return component < 3; 3003 case FORMAT_X32B32G32R32F_UNSIGNED: return component < 3; 3004 case FORMAT_A8: return false; 3005 case FORMAT_R8: return component < 1; 3006 case FORMAT_L8: return component < 1; 3007 case FORMAT_A8L8: return component < 1; 3008 case FORMAT_D32F_LOCKABLE: return false; 3009 case FORMAT_D32FS8_TEXTURE: return false; 3010 case FORMAT_D32F_SHADOW: return false; 3011 case FORMAT_D32FS8_SHADOW: return false; 3012 case FORMAT_L16: return component < 1; 3013 case FORMAT_G16R16: return component < 2; 3014 case FORMAT_A16B16G16R16: return component < 3; 3015 case FORMAT_R16I: return component < 1; 3016 case FORMAT_R16UI: return component < 1; 3017 case FORMAT_G16R16I: return component < 2; 3018 case FORMAT_G16R16UI: return component < 2; 3019 case FORMAT_X16B16G16R16I: return component < 3; 3020 case FORMAT_X16B16G16R16UI: return component < 3; 3021 case FORMAT_A16B16G16R16I: return component < 3; 3022 case FORMAT_A16B16G16R16UI: return component < 3; 3023 case FORMAT_V16U16: return false; 3024 case FORMAT_A16W16V16U16: return false; 3025 case FORMAT_Q16W16V16U16: return false; 3026 case FORMAT_YV12_BT601: return component < 3; 3027 case FORMAT_YV12_BT709: return component < 3; 3028 case FORMAT_YV12_JFIF: return component < 3; 3029 default: 3030 ASSERT(false); 3031 } 3032 3033 return false; 3034 } 3035 } 3036