HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Oreo
|
8.0.0_r4
下载
查看原文件
收藏
根目录
external
swiftshader
src
Shader
SamplerCore.cpp
// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "SamplerCore.hpp" #include "Constants.hpp" #include "Debug.hpp" namespace { void applySwizzle(sw::SwizzleType swizzle, sw::Short4& s, const sw::Vector4s& c) { switch(swizzle) { case sw::SWIZZLE_RED: s = c.x; break; case sw::SWIZZLE_GREEN: s = c.y; break; case sw::SWIZZLE_BLUE: s = c.z; break; case sw::SWIZZLE_ALPHA: s = c.w; break; case sw::SWIZZLE_ZERO: s = sw::Short4(0x0000, 0x0000, 0x0000, 0x0000); break; case sw::SWIZZLE_ONE: s = sw::Short4(0x1000, 0x1000, 0x1000, 0x1000); break; default: ASSERT(false); } } void applySwizzle(sw::SwizzleType swizzle, sw::Float4& f, const sw::Vector4f& c) { switch(swizzle) { case sw::SWIZZLE_RED: f = c.x; break; case sw::SWIZZLE_GREEN: f = c.y; break; case sw::SWIZZLE_BLUE: f = c.z; break; case sw::SWIZZLE_ALPHA: f = c.w; break; case sw::SWIZZLE_ZERO: f = sw::Float4(0.0f, 0.0f, 0.0f, 0.0f); break; case sw::SWIZZLE_ONE: f = sw::Float4(1.0f, 1.0f, 1.0f, 1.0f); break; default: ASSERT(false); } } } namespace sw { SamplerCore::SamplerCore(Pointer
&constants, const Sampler::State &state) : constants(constants), state(state) { } void SamplerCore::sampleTexture(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, SamplerMethod method) { sampleTexture(texture, c, u, v, w, q, dsx, dsy, method, true); } void SamplerCore::sampleTexture(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, SamplerMethod method, bool fixed12) { #if PERF_PROFILE AddAtomic(Pointer
(&profiler.texOperations), 4); if(state.compressedFormat) { AddAtomic(Pointer
(&profiler.compressedTex), 4); } #endif Float4 uuuu = u; Float4 vvvv = v; Float4 wwww = w; if(state.textureType == TEXTURE_NULL) { c.x = Short4(0x0000, 0x0000, 0x0000, 0x0000); c.y = Short4(0x0000, 0x0000, 0x0000, 0x0000); c.z = Short4(0x0000, 0x0000, 0x0000, 0x0000); if(fixed12) // FIXME: Convert to fixed12 at higher level, when required { c.w = Short4(0x1000, 0x1000, 0x1000, 0x1000); } else { c.w = Short4((short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF); // FIXME } } else { Int face[4]; Float4 lodX; Float4 lodY; Float4 lodZ; if(state.textureType == TEXTURE_CUBE) { cubeFace(face, uuuu, vvvv, lodX, lodY, lodZ, u, v, w); } Float lod; Float anisotropy; Float4 uDelta; Float4 vDelta; if(state.textureType != TEXTURE_3D) { if(state.textureType != TEXTURE_CUBE) { computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, q.x, dsx, dsy, method); } else { computeLodCube(texture, lod, lodX, lodY, lodZ, q.x, dsx, dsy, method); } } else { computeLod3D(texture, lod, uuuu, vvvv, wwww, q.x, dsx, dsy, method); } if(!hasFloatTexture()) { sampleFilter(texture, c, uuuu, vvvv, wwww, lod, anisotropy, uDelta, vDelta, face, method); } else { Vector4f cf; sampleFloatFilter(texture, cf, uuuu, vvvv, wwww, lod, anisotropy, uDelta, vDelta, face, method); convertFixed12(c, cf); } if(fixed12 && !hasFloatTexture()) { if(has16bitTextureFormat()) { switch(state.textureFormat) { case FORMAT_R5G6B5: if(state.sRGB) { sRGBtoLinear16_5_12(c.x); sRGBtoLinear16_6_12(c.y); sRGBtoLinear16_5_12(c.z); } else { c.x = MulHigh(As
(c.x), UShort4(0x10000000 / 0xF800)); c.y = MulHigh(As
(c.y), UShort4(0x10000000 / 0xFC00)); c.z = MulHigh(As
(c.z), UShort4(0x10000000 / 0xF800)); } break; default: ASSERT(false); } } else { for(int component = 0; component < textureComponentCount(); component++) { if(state.sRGB && isRGBComponent(component)) { sRGBtoLinear16_8_12(c[component]); // FIXME: Perform linearization at surface level for read-only textures } else { if(hasUnsignedTextureComponent(component)) { c[component] = As
(c[component]) >> 4; } else { c[component] = c[component] >> 3; } } } } } if(fixed12 && state.textureFilter != FILTER_GATHER) { int componentCount = textureComponentCount(); switch(state.textureFormat) { case FORMAT_R8I_SNORM: case FORMAT_G8R8I_SNORM: case FORMAT_X8B8G8R8I_SNORM: case FORMAT_A8B8G8R8I_SNORM: case FORMAT_R8: case FORMAT_R5G6B5: case FORMAT_G8R8: case FORMAT_R8I: case FORMAT_R8UI: case FORMAT_G8R8I: case FORMAT_G8R8UI: case FORMAT_X8B8G8R8I: case FORMAT_X8B8G8R8UI: case FORMAT_A8B8G8R8I: case FORMAT_A8B8G8R8UI: case FORMAT_R16I: case FORMAT_R16UI: case FORMAT_G16R16: case FORMAT_G16R16I: case FORMAT_G16R16UI: case FORMAT_X16B16G16R16I: case FORMAT_X16B16G16R16UI: case FORMAT_A16B16G16R16: case FORMAT_A16B16G16R16I: case FORMAT_A16B16G16R16UI: case FORMAT_R32I: case FORMAT_R32UI: case FORMAT_G32R32I: case FORMAT_G32R32UI: case FORMAT_X32B32G32R32I: case FORMAT_X32B32G32R32UI: case FORMAT_A32B32G32R32I: case FORMAT_A32B32G32R32UI: case FORMAT_X8R8G8B8: case FORMAT_X8B8G8R8: case FORMAT_A8R8G8B8: case FORMAT_A8B8G8R8: case FORMAT_SRGB8_X8: case FORMAT_SRGB8_A8: case FORMAT_V8U8: case FORMAT_Q8W8V8U8: case FORMAT_X8L8V8U8: case FORMAT_V16U16: case FORMAT_A16W16V16U16: case FORMAT_Q16W16V16U16: case FORMAT_YV12_BT601: case FORMAT_YV12_BT709: case FORMAT_YV12_JFIF: if(componentCount < 2) c.y = Short4(0x1000, 0x1000, 0x1000, 0x1000); if(componentCount < 3) c.z = Short4(0x1000, 0x1000, 0x1000, 0x1000); if(componentCount < 4) c.w = Short4(0x1000, 0x1000, 0x1000, 0x1000); break; case FORMAT_A8: c.w = c.x; c.x = Short4(0x0000, 0x0000, 0x0000, 0x0000); c.y = Short4(0x0000, 0x0000, 0x0000, 0x0000); c.z = Short4(0x0000, 0x0000, 0x0000, 0x0000); break; case FORMAT_L8: case FORMAT_L16: c.y = c.x; c.z = c.x; c.w = Short4(0x1000, 0x1000, 0x1000, 0x1000); break; case FORMAT_A8L8: c.w = c.y; c.y = c.x; c.z = c.x; break; case FORMAT_R32F: c.y = Short4(0x1000, 0x1000, 0x1000, 0x1000); case FORMAT_G32R32F: c.z = Short4(0x1000, 0x1000, 0x1000, 0x1000); case FORMAT_X32B32G32R32F: c.w = Short4(0x1000, 0x1000, 0x1000, 0x1000); case FORMAT_A32B32G32R32F: break; case FORMAT_D32F: case FORMAT_D32F_LOCKABLE: case FORMAT_D32FS8_TEXTURE: case FORMAT_D32FS8_SHADOW: c.y = c.x; c.z = c.x; c.w = c.x; break; default: ASSERT(false); } } } if(fixed12 && ((state.swizzleR != SWIZZLE_RED) || (state.swizzleG != SWIZZLE_GREEN) || (state.swizzleB != SWIZZLE_BLUE) || (state.swizzleA != SWIZZLE_ALPHA))) { const Vector4s col(c); applySwizzle(state.swizzleR, c.x, col); applySwizzle(state.swizzleG, c.y, col); applySwizzle(state.swizzleB, c.z, col); applySwizzle(state.swizzleA, c.w, col); } } void SamplerCore::sampleTexture(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, SamplerMethod method) { #if PERF_PROFILE AddAtomic(Pointer
(&profiler.texOperations), 4); if(state.compressedFormat) { AddAtomic(Pointer
(&profiler.compressedTex), 4); } #endif if(state.textureType == TEXTURE_NULL) { c.x = Float4(0.0f); c.y = Float4(0.0f); c.z = Float4(0.0f); c.w = Float4(1.0f); } else { if(hasFloatTexture()) // FIXME: Mostly identical to integer sampling { Float4 uuuu = u; Float4 vvvv = v; Float4 wwww = w; Int face[4]; Float4 lodX; Float4 lodY; Float4 lodZ; if(state.textureType == TEXTURE_CUBE) { cubeFace(face, uuuu, vvvv, lodX, lodY, lodZ, u, v, w); } Float lod; Float anisotropy; Float4 uDelta; Float4 vDelta; if(state.textureType != TEXTURE_3D) { if(state.textureType != TEXTURE_CUBE) { computeLod(texture, lod, anisotropy, uDelta, vDelta, uuuu, vvvv, q.x, dsx, dsy, method); } else { computeLodCube(texture, lod, lodX, lodY, lodZ, q.x, dsx, dsy, method); } } else { computeLod3D(texture, lod, uuuu, vvvv, wwww, q.x, dsx, dsy, method); } sampleFloatFilter(texture, c, uuuu, vvvv, wwww, lod, anisotropy, uDelta, vDelta, face, method); } else { Vector4s cs; sampleTexture(texture, cs, u, v, w, q, dsx, dsy, method, false); for(int component = 0; component < textureComponentCount(); component++) { if(has16bitTextureFormat()) { switch(state.textureFormat) { case FORMAT_R5G6B5: if(state.sRGB) { sRGBtoLinear16_5_12(cs.x); sRGBtoLinear16_6_12(cs.y); sRGBtoLinear16_5_12(cs.z); convertSigned12(c.x, cs.x); convertSigned12(c.y, cs.y); convertSigned12(c.z, cs.z); } else { c.x = Float4(As
(cs.x)) * Float4(1.0f / 0xF800); c.y = Float4(As
(cs.y)) * Float4(1.0f / 0xFC00); c.z = Float4(As
(cs.z)) * Float4(1.0f / 0xF800); } break; default: ASSERT(false); } } else { switch(state.textureFormat) { case FORMAT_R8I: case FORMAT_G8R8I: case FORMAT_X8B8G8R8I: case FORMAT_A8B8G8R8I: c[component] = As
(Int4(cs[component]) >> 8); break; case FORMAT_R8UI: case FORMAT_G8R8UI: case FORMAT_X8B8G8R8UI: case FORMAT_A8B8G8R8UI: c[component] = As
(Int4(As
(cs[component]) >> 8)); break; case FORMAT_R16I: case FORMAT_G16R16I: case FORMAT_X16B16G16R16I: case FORMAT_A16B16G16R16I: c[component] = As
(Int4(cs[component])); break; case FORMAT_R16UI: case FORMAT_G16R16UI: case FORMAT_X16B16G16R16UI: case FORMAT_A16B16G16R16UI: c[component] = As
(Int4(As
(cs[component]))); break; default: // Normalized integer formats if(state.sRGB && isRGBComponent(component)) { sRGBtoLinear16_8_12(cs[component]); // FIXME: Perform linearization at surface level for read-only textures convertSigned12(c[component], cs[component]); } else { if(hasUnsignedTextureComponent(component)) { convertUnsigned16(c[component], cs[component]); } else { convertSigned15(c[component], cs[component]); } } break; } } } } int componentCount = textureComponentCount(); if(state.textureFilter != FILTER_GATHER) { switch(state.textureFormat) { case FORMAT_R8I: case FORMAT_R8UI: case FORMAT_R16I: case FORMAT_R16UI: case FORMAT_R32I: case FORMAT_R32UI: c.y = As
(UInt4(0)); case FORMAT_G8R8I: case FORMAT_G8R8UI: case FORMAT_G16R16I: case FORMAT_G16R16UI: case FORMAT_G32R32I: case FORMAT_G32R32UI: c.z = As
(UInt4(0)); case FORMAT_X8B8G8R8I: case FORMAT_X8B8G8R8UI: case FORMAT_X16B16G16R16I: case FORMAT_X16B16G16R16UI: case FORMAT_X32B32G32R32I: case FORMAT_X32B32G32R32UI: c.w = As
(UInt4(1)); case FORMAT_A8B8G8R8I: case FORMAT_A8B8G8R8UI: case FORMAT_A16B16G16R16I: case FORMAT_A16B16G16R16UI: case FORMAT_A32B32G32R32I: case FORMAT_A32B32G32R32UI: break; case FORMAT_R8I_SNORM: case FORMAT_G8R8I_SNORM: case FORMAT_X8B8G8R8I_SNORM: case FORMAT_A8B8G8R8I_SNORM: case FORMAT_R8: case FORMAT_R5G6B5: case FORMAT_G8R8: case FORMAT_G16R16: case FORMAT_A16B16G16R16: case FORMAT_X8R8G8B8: case FORMAT_X8B8G8R8: case FORMAT_A8R8G8B8: case FORMAT_A8B8G8R8: case FORMAT_SRGB8_X8: case FORMAT_SRGB8_A8: case FORMAT_V8U8: case FORMAT_Q8W8V8U8: case FORMAT_X8L8V8U8: case FORMAT_V16U16: case FORMAT_A16W16V16U16: case FORMAT_Q16W16V16U16: if(componentCount < 2) c.y = Float4(1.0f); if(componentCount < 3) c.z = Float4(1.0f); if(componentCount < 4) c.w = Float4(1.0f); break; case FORMAT_A8: c.w = c.x; c.x = Float4(0.0f); c.y = Float4(0.0f); c.z = Float4(0.0f); break; case FORMAT_L8: case FORMAT_L16: c.y = c.x; c.z = c.x; c.w = Float4(1.0f); break; case FORMAT_A8L8: c.w = c.y; c.y = c.x; c.z = c.x; break; case FORMAT_R32F: c.y = Float4(1.0f); case FORMAT_G32R32F: c.z = Float4(1.0f); case FORMAT_X32B32G32R32F: c.w = Float4(1.0f); case FORMAT_A32B32G32R32F: break; case FORMAT_D32F: case FORMAT_D32F_LOCKABLE: case FORMAT_D32FS8_TEXTURE: case FORMAT_D32FS8_SHADOW: c.y = c.x; c.z = c.x; c.w = c.x; break; default: ASSERT(false); } } } if((state.swizzleR != SWIZZLE_RED) || (state.swizzleG != SWIZZLE_GREEN) || (state.swizzleB != SWIZZLE_BLUE) || (state.swizzleA != SWIZZLE_ALPHA)) { const Vector4f col(c); applySwizzle(state.swizzleR, c.x, col); applySwizzle(state.swizzleG, c.y, col); applySwizzle(state.swizzleB, c.z, col); applySwizzle(state.swizzleA, c.w, col); } } void SamplerCore::border(Short4 &mask, Float4 &coordinates) { Int4 border = As
(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f))); mask = As
(Int2(As
(Pack(border, border)))); } void SamplerCore::border(Int4 &mask, Float4 &coordinates) { mask = As
(CmpLT(Abs(coordinates - Float4(0.5f)), Float4(0.5f))); } Short4 SamplerCore::offsetSample(Short4 &uvw, Pointer
&mipmap, int halfOffset, bool wrap, int count, Float &lod) { Short4 offset = *Pointer
(mipmap + halfOffset); if(state.textureFilter == FILTER_MIN_LINEAR_MAG_POINT) { offset &= Short4(CmpNLE(Float4(lod), Float4(0.0f))); } else if(state.textureFilter == FILTER_MIN_POINT_MAG_LINEAR) { offset &= Short4(CmpLE(Float4(lod), Float4(0.0f))); } if(wrap) { switch(count) { case -1: return uvw - offset; case 0: return uvw; case +1: return uvw + offset; case 2: return uvw + offset + offset; } } else // Clamp or mirror { switch(count) { case -1: return SubSat(As
(uvw), As
(offset)); case 0: return uvw; case +1: return AddSat(As
(uvw), As
(offset)); case 2: return AddSat(AddSat(As
(uvw), As
(offset)), As
(offset)); } } return uvw; } void SamplerCore::sampleFilter(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerMethod method) { sampleAniso(texture, c, u, v, w, lod, anisotropy, uDelta, vDelta, face, false, method); if(state.mipmapFilter > MIPMAP_POINT) { Vector4s cc; sampleAniso(texture, cc, u, v, w, lod, anisotropy, uDelta, vDelta, face, true, method); lod *= Float(1 << 16); UShort4 utri = UShort4(Float4(lod)); // FIXME: Optimize Short4 stri = utri >> 1; // FIXME: Optimize if(hasUnsignedTextureComponent(0)) cc.x = MulHigh(As
(cc.x), utri); else cc.x = MulHigh(cc.x, stri); if(hasUnsignedTextureComponent(1)) cc.y = MulHigh(As
(cc.y), utri); else cc.y = MulHigh(cc.y, stri); if(hasUnsignedTextureComponent(2)) cc.z = MulHigh(As
(cc.z), utri); else cc.z = MulHigh(cc.z, stri); if(hasUnsignedTextureComponent(3)) cc.w = MulHigh(As
(cc.w), utri); else cc.w = MulHigh(cc.w, stri); utri = ~utri; stri = Short4(0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF) - stri; if(hasUnsignedTextureComponent(0)) c.x = MulHigh(As
(c.x), utri); else c.x = MulHigh(c.x, stri); if(hasUnsignedTextureComponent(1)) c.y = MulHigh(As
(c.y), utri); else c.y = MulHigh(c.y, stri); if(hasUnsignedTextureComponent(2)) c.z = MulHigh(As
(c.z), utri); else c.z = MulHigh(c.z, stri); if(hasUnsignedTextureComponent(3)) c.w = MulHigh(As
(c.w), utri); else c.w = MulHigh(c.w, stri); c.x += cc.x; c.y += cc.y; c.z += cc.z; c.w += cc.w; if(!hasUnsignedTextureComponent(0)) c.x += c.x; if(!hasUnsignedTextureComponent(1)) c.y += c.y; if(!hasUnsignedTextureComponent(2)) c.z += c.z; if(!hasUnsignedTextureComponent(3)) c.w += c.w; } Short4 borderMask; if(state.addressingModeU == ADDRESSING_BORDER) { Short4 u0; border(u0, u); borderMask = u0; } if(state.addressingModeV == ADDRESSING_BORDER) { Short4 v0; border(v0, v); if(state.addressingModeU == ADDRESSING_BORDER) { borderMask &= v0; } else { borderMask = v0; } } if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D) { Short4 s0; border(s0, w); if(state.addressingModeU == ADDRESSING_BORDER || state.addressingModeV == ADDRESSING_BORDER) { borderMask &= s0; } else { borderMask = s0; } } if(state.addressingModeU == ADDRESSING_BORDER || state.addressingModeV == ADDRESSING_BORDER || (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)) { Short4 b; c.x = borderMask & c.x | ~borderMask & (*Pointer
(texture + OFFSET(Texture,borderColor4[0])) >> (hasUnsignedTextureComponent(0) ? 0 : 1)); c.y = borderMask & c.y | ~borderMask & (*Pointer
(texture + OFFSET(Texture,borderColor4[1])) >> (hasUnsignedTextureComponent(1) ? 0 : 1)); c.z = borderMask & c.z | ~borderMask & (*Pointer
(texture + OFFSET(Texture,borderColor4[2])) >> (hasUnsignedTextureComponent(2) ? 0 : 1)); c.w = borderMask & c.w | ~borderMask & (*Pointer
(texture + OFFSET(Texture,borderColor4[3])) >> (hasUnsignedTextureComponent(3) ? 0 : 1)); } } void SamplerCore::sampleAniso(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerMethod method) { if(state.textureFilter != FILTER_ANISOTROPIC || method == Lod) { sampleQuad(texture, c, u, v, w, lod, face, secondLOD); } else { Int a = RoundInt(anisotropy); Vector4s cSum; cSum.x = Short4(0, 0, 0, 0); cSum.y = Short4(0, 0, 0, 0); cSum.z = Short4(0, 0, 0, 0); cSum.w = Short4(0, 0, 0, 0); Float4 A = *Pointer
(constants + OFFSET(Constants,uvWeight) + 16 * a); Float4 B = *Pointer
(constants + OFFSET(Constants,uvStart) + 16 * a); UShort4 cw = *Pointer
(constants + OFFSET(Constants,cWeight) + 8 * a); Short4 sw = Short4(cw >> 1); Float4 du = uDelta; Float4 dv = vDelta; Float4 u0 = u + B * du; Float4 v0 = v + B * dv; du *= A; dv *= A; Int i = 0; Do { sampleQuad(texture, c, u0, v0, w, lod, face, secondLOD); u0 += du; v0 += dv; if(hasUnsignedTextureComponent(0)) cSum.x += As
(MulHigh(As
(c.x), cw)); else cSum.x += MulHigh(c.x, sw); if(hasUnsignedTextureComponent(1)) cSum.y += As
(MulHigh(As
(c.y), cw)); else cSum.y += MulHigh(c.y, sw); if(hasUnsignedTextureComponent(2)) cSum.z += As
(MulHigh(As
(c.z), cw)); else cSum.z += MulHigh(c.z, sw); if(hasUnsignedTextureComponent(3)) cSum.w += As
(MulHigh(As
(c.w), cw)); else cSum.w += MulHigh(c.w, sw); i++; } Until(i >= a) if(hasUnsignedTextureComponent(0)) c.x = cSum.x; else c.x = AddSat(cSum.x, cSum.x); if(hasUnsignedTextureComponent(1)) c.y = cSum.y; else c.y = AddSat(cSum.y, cSum.y); if(hasUnsignedTextureComponent(2)) c.z = cSum.z; else c.z = AddSat(cSum.z, cSum.z); if(hasUnsignedTextureComponent(3)) c.w = cSum.w; else c.w = AddSat(cSum.w, cSum.w); } } void SamplerCore::sampleQuad(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Int face[4], bool secondLOD) { if(state.textureType != TEXTURE_3D) { sampleQuad2D(texture, c, u, v, w, lod, face, secondLOD); } else { sample3D(texture, c, u, v, w, lod, secondLOD); } } void SamplerCore::sampleQuad2D(Pointer
&texture, Vector4s &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Int face[4], bool secondLOD) { int componentCount = textureComponentCount(); bool gather = state.textureFilter == FILTER_GATHER; Pointer
mipmap; Pointer
buffer[4]; selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); Short4 uuuu = address(u, state.addressingModeU, mipmap); Short4 vvvv = address(v, state.addressingModeV, mipmap); Short4 wwww = address(w, state.addressingModeW, mipmap); if(state.textureFilter == FILTER_POINT) { sampleTexel(c, uuuu, vvvv, wwww, mipmap, buffer); } else { Vector4s c0; Vector4s c1; Vector4s c2; Vector4s c3; Short4 uuuu0 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 0 : -1, lod); Short4 vvvv0 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 0 : -1, lod); Short4 uuuu1 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 2 : +1, lod); Short4 vvvv1 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 2 : +1, lod); sampleTexel(c0, uuuu0, vvvv0, wwww, mipmap, buffer); sampleTexel(c1, uuuu1, vvvv0, wwww, mipmap, buffer); sampleTexel(c2, uuuu0, vvvv1, wwww, mipmap, buffer); sampleTexel(c3, uuuu1, vvvv1, wwww, mipmap, buffer); if(!gather) // Blend { // Fractions UShort4 f0u = uuuu0; UShort4 f0v = vvvv0; if(!state.hasNPOTTexture) { f0u = f0u << *Pointer
(mipmap + OFFSET(Mipmap,uInt)); // .u f0v = f0v << *Pointer
(mipmap + OFFSET(Mipmap,vInt)); // .v } else { f0u = f0u * *Pointer
(mipmap + OFFSET(Mipmap,width)); f0v = f0v * *Pointer
(mipmap + OFFSET(Mipmap,height)); } UShort4 f1u = ~f0u; UShort4 f1v = ~f0v; UShort4 f0u0v = MulHigh(f0u, f0v); UShort4 f1u0v = MulHigh(f1u, f0v); UShort4 f0u1v = MulHigh(f0u, f1v); UShort4 f1u1v = MulHigh(f1u, f1v); // Signed fractions Short4 f1u1vs; Short4 f0u1vs; Short4 f1u0vs; Short4 f0u0vs; if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3)) { f1u1vs = f1u1v >> 1; f0u1vs = f0u1v >> 1; f1u0vs = f1u0v >> 1; f0u0vs = f0u0v >> 1; } // Bilinear interpolation if(componentCount >= 1) { if(has16bitTextureComponents() && hasUnsignedTextureComponent(0)) { c0.x = As
(c0.x) - MulHigh(As
(c0.x), f0u) + MulHigh(As
(c1.x), f0u); c2.x = As
(c2.x) - MulHigh(As
(c2.x), f0u) + MulHigh(As
(c3.x), f0u); c.x = As
(c0.x) - MulHigh(As
(c0.x), f0v) + MulHigh(As
(c2.x), f0v); } else { if(hasUnsignedTextureComponent(0)) { c0.x = MulHigh(As
(c0.x), f1u1v); c1.x = MulHigh(As
(c1.x), f0u1v); c2.x = MulHigh(As
(c2.x), f1u0v); c3.x = MulHigh(As
(c3.x), f0u0v); } else { c0.x = MulHigh(c0.x, f1u1vs); c1.x = MulHigh(c1.x, f0u1vs); c2.x = MulHigh(c2.x, f1u0vs); c3.x = MulHigh(c3.x, f0u0vs); } c.x = (c0.x + c1.x) + (c2.x + c3.x); if(!hasUnsignedTextureComponent(0)) c.x = AddSat(c.x, c.x); // Correct for signed fractions } } if(componentCount >= 2) { if(has16bitTextureComponents() && hasUnsignedTextureComponent(1)) { c0.y = As
(c0.y) - MulHigh(As
(c0.y), f0u) + MulHigh(As
(c1.y), f0u); c2.y = As
(c2.y) - MulHigh(As
(c2.y), f0u) + MulHigh(As
(c3.y), f0u); c.y = As
(c0.y) - MulHigh(As
(c0.y), f0v) + MulHigh(As
(c2.y), f0v); } else { if(hasUnsignedTextureComponent(1)) { c0.y = MulHigh(As
(c0.y), f1u1v); c1.y = MulHigh(As
(c1.y), f0u1v); c2.y = MulHigh(As
(c2.y), f1u0v); c3.y = MulHigh(As
(c3.y), f0u0v); } else { c0.y = MulHigh(c0.y, f1u1vs); c1.y = MulHigh(c1.y, f0u1vs); c2.y = MulHigh(c2.y, f1u0vs); c3.y = MulHigh(c3.y, f0u0vs); } c.y = (c0.y + c1.y) + (c2.y + c3.y); if(!hasUnsignedTextureComponent(1)) c.y = AddSat(c.y, c.y); // Correct for signed fractions } } if(componentCount >= 3) { if(has16bitTextureComponents() && hasUnsignedTextureComponent(2)) { c0.z = As
(c0.z) - MulHigh(As
(c0.z), f0u) + MulHigh(As
(c1.z), f0u); c2.z = As
(c2.z) - MulHigh(As
(c2.z), f0u) + MulHigh(As
(c3.z), f0u); c.z = As
(c0.z) - MulHigh(As
(c0.z), f0v) + MulHigh(As
(c2.z), f0v); } else { if(hasUnsignedTextureComponent(2)) { c0.z = MulHigh(As
(c0.z), f1u1v); c1.z = MulHigh(As
(c1.z), f0u1v); c2.z = MulHigh(As
(c2.z), f1u0v); c3.z = MulHigh(As
(c3.z), f0u0v); } else { c0.z = MulHigh(c0.z, f1u1vs); c1.z = MulHigh(c1.z, f0u1vs); c2.z = MulHigh(c2.z, f1u0vs); c3.z = MulHigh(c3.z, f0u0vs); } c.z = (c0.z + c1.z) + (c2.z + c3.z); if(!hasUnsignedTextureComponent(2)) c.z = AddSat(c.z, c.z); // Correct for signed fractions } } if(componentCount >= 4) { if(has16bitTextureComponents() && hasUnsignedTextureComponent(3)) { c0.w = As
(c0.w) - MulHigh(As
(c0.w), f0u) + MulHigh(As
(c1.w), f0u); c2.w = As
(c2.w) - MulHigh(As
(c2.w), f0u) + MulHigh(As
(c3.w), f0u); c.w = As
(c0.w) - MulHigh(As
(c0.w), f0v) + MulHigh(As
(c2.w), f0v); } else { if(hasUnsignedTextureComponent(3)) { c0.w = MulHigh(As
(c0.w), f1u1v); c1.w = MulHigh(As
(c1.w), f0u1v); c2.w = MulHigh(As
(c2.w), f1u0v); c3.w = MulHigh(As
(c3.w), f0u0v); } else { c0.w = MulHigh(c0.w, f1u1vs); c1.w = MulHigh(c1.w, f0u1vs); c2.w = MulHigh(c2.w, f1u0vs); c3.w = MulHigh(c3.w, f0u0vs); } c.w = (c0.w + c1.w) + (c2.w + c3.w); if(!hasUnsignedTextureComponent(3)) c.w = AddSat(c.w, c.w); // Correct for signed fractions } } } else { c.x = c1.x; c.y = c2.x; c.z = c3.x; c.w = c0.x; } } } void SamplerCore::sample3D(Pointer
&texture, Vector4s &c_, Float4 &u_, Float4 &v_, Float4 &w_, Float &lod, bool secondLOD) { int componentCount = textureComponentCount(); Pointer
mipmap; Pointer
buffer[4]; Int face[4]; selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); Short4 uuuu = address(u_, state.addressingModeU, mipmap); Short4 vvvv = address(v_, state.addressingModeV, mipmap); Short4 wwww = address(w_, state.addressingModeW, mipmap); if(state.textureFilter == FILTER_POINT) { sampleTexel(c_, uuuu, vvvv, wwww, mipmap, buffer); } else { Vector4s c[2][2][2]; Short4 u[2][2][2]; Short4 v[2][2][2]; Short4 s[2][2][2]; for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { for(int k = 0; k < 2; k++) { u[i][j][k] = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, i * 2 - 1, lod); v[i][j][k] = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, j * 2 - 1, lod); s[i][j][k] = offsetSample(wwww, mipmap, OFFSET(Mipmap,wHalf), state.addressingModeW == ADDRESSING_WRAP, k * 2 - 1, lod); } } } // Fractions UShort4 f[2][2][2]; Short4 fs[2][2][2]; UShort4 f0u; UShort4 f0v; UShort4 f0s; if(!state.hasNPOTTexture) { f0u = As
(u[0][0][0]) << *Pointer
(mipmap + OFFSET(Mipmap,uInt)); f0v = As
(v[0][0][0]) << *Pointer
(mipmap + OFFSET(Mipmap,vInt)); f0s = As
(s[0][0][0]) << *Pointer
(mipmap + OFFSET(Mipmap,wInt)); } else { f0u = As
(u[0][0][0]) * *Pointer
(mipmap + OFFSET(Mipmap,width)); f0v = As
(v[0][0][0]) * *Pointer
(mipmap + OFFSET(Mipmap,height)); f0s = As
(s[0][0][0]) * *Pointer
(mipmap + OFFSET(Mipmap,depth)); } UShort4 f1u = ~f0u; UShort4 f1v = ~f0v; UShort4 f1s = ~f0s; f[1][1][1] = MulHigh(f1u, f1v); f[0][1][1] = MulHigh(f0u, f1v); f[1][0][1] = MulHigh(f1u, f0v); f[0][0][1] = MulHigh(f0u, f0v); f[1][1][0] = MulHigh(f1u, f1v); f[0][1][0] = MulHigh(f0u, f1v); f[1][0][0] = MulHigh(f1u, f0v); f[0][0][0] = MulHigh(f0u, f0v); f[1][1][1] = MulHigh(f[1][1][1], f1s); f[0][1][1] = MulHigh(f[0][1][1], f1s); f[1][0][1] = MulHigh(f[1][0][1], f1s); f[0][0][1] = MulHigh(f[0][0][1], f1s); f[1][1][0] = MulHigh(f[1][1][0], f0s); f[0][1][0] = MulHigh(f[0][1][0], f0s); f[1][0][0] = MulHigh(f[1][0][0], f0s); f[0][0][0] = MulHigh(f[0][0][0], f0s); // Signed fractions if(!hasUnsignedTextureComponent(0) || !hasUnsignedTextureComponent(1) || !hasUnsignedTextureComponent(2) || !hasUnsignedTextureComponent(3)) { fs[0][0][0] = f[0][0][0] >> 1; fs[0][0][1] = f[0][0][1] >> 1; fs[0][1][0] = f[0][1][0] >> 1; fs[0][1][1] = f[0][1][1] >> 1; fs[1][0][0] = f[1][0][0] >> 1; fs[1][0][1] = f[1][0][1] >> 1; fs[1][1][0] = f[1][1][0] >> 1; fs[1][1][1] = f[1][1][1] >> 1; } for(int i = 0; i < 2; i++) { for(int j = 0; j < 2; j++) { for(int k = 0; k < 2; k++) { sampleTexel(c[i][j][k], u[i][j][k], v[i][j][k], s[i][j][k], mipmap, buffer); if(componentCount >= 1) { if(hasUnsignedTextureComponent(0)) c[i][j][k].x = MulHigh(As
(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]); } if(componentCount >= 2) { if(hasUnsignedTextureComponent(1)) c[i][j][k].y = MulHigh(As
(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]); } if(componentCount >= 3) { if(hasUnsignedTextureComponent(2)) c[i][j][k].z = MulHigh(As
(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]); } if(componentCount >= 4) { if(hasUnsignedTextureComponent(3)) c[i][j][k].w = MulHigh(As
(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]); } if(i != 0 || j != 0 || k != 0) { if(componentCount >= 1) c[0][0][0].x += c[i][j][k].x; if(componentCount >= 2) c[0][0][0].y += c[i][j][k].y; if(componentCount >= 3) c[0][0][0].z += c[i][j][k].z; if(componentCount >= 4) c[0][0][0].w += c[i][j][k].w; } } } } if(componentCount >= 1) c_.x = c[0][0][0].x; if(componentCount >= 2) c_.y = c[0][0][0].y; if(componentCount >= 3) c_.z = c[0][0][0].z; if(componentCount >= 4) c_.w = c[0][0][0].w; // Correct for signed fractions if(componentCount >= 1) if(!hasUnsignedTextureComponent(0)) c_.x = AddSat(c_.x, c_.x); if(componentCount >= 2) if(!hasUnsignedTextureComponent(1)) c_.y = AddSat(c_.y, c_.y); if(componentCount >= 3) if(!hasUnsignedTextureComponent(2)) c_.z = AddSat(c_.z, c_.z); if(componentCount >= 4) if(!hasUnsignedTextureComponent(3)) c_.w = AddSat(c_.w, c_.w); } } void SamplerCore::sampleFloatFilter(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], SamplerMethod method) { sampleFloatAniso(texture, c, u, v, w, lod, anisotropy, uDelta, vDelta, face, false, method); if(state.mipmapFilter > MIPMAP_POINT) { Vector4f cc; sampleFloatAniso(texture, cc, u, v, w, lod, anisotropy, uDelta, vDelta, face, true, method); Float4 lod4 = Float4(Frac(lod)); c.x = (cc.x - c.x) * lod4 + c.x; c.y = (cc.y - c.y) * lod4 + c.y; c.z = (cc.z - c.z) * lod4 + c.z; c.w = (cc.w - c.w) * lod4 + c.w; } Int4 borderMask; if(state.addressingModeU == ADDRESSING_BORDER) { Int4 u0; border(u0, u); borderMask = u0; } if(state.addressingModeV == ADDRESSING_BORDER) { Int4 v0; border(v0, v); if(state.addressingModeU == ADDRESSING_BORDER) { borderMask &= v0; } else { borderMask = v0; } } if(state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D) { Int4 s0; border(s0, w); if(state.addressingModeU == ADDRESSING_BORDER || state.addressingModeV == ADDRESSING_BORDER) { borderMask &= s0; } else { borderMask = s0; } } if(state.addressingModeU == ADDRESSING_BORDER || state.addressingModeV == ADDRESSING_BORDER || (state.addressingModeW == ADDRESSING_BORDER && state.textureType == TEXTURE_3D)) { Int4 b; c.x = As
(borderMask & As
(c.x) | ~borderMask & *Pointer
(texture + OFFSET(Texture,borderColorF[0]))); c.y = As
(borderMask & As
(c.y) | ~borderMask & *Pointer
(texture + OFFSET(Texture,borderColorF[1]))); c.z = As
(borderMask & As
(c.z) | ~borderMask & *Pointer
(texture + OFFSET(Texture,borderColorF[2]))); c.w = As
(borderMask & As
(c.w) | ~borderMask & *Pointer
(texture + OFFSET(Texture,borderColorF[3]))); } } void SamplerCore::sampleFloatAniso(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Int face[4], bool secondLOD, SamplerMethod method) { if(state.textureFilter != FILTER_ANISOTROPIC || method == Lod) { sampleFloat(texture, c, u, v, w, lod, face, secondLOD); } else { Int a = RoundInt(anisotropy); Vector4f cSum; cSum.x = Float4(0.0f); cSum.y = Float4(0.0f); cSum.z = Float4(0.0f); cSum.w = Float4(0.0f); Float4 A = *Pointer
(constants + OFFSET(Constants,uvWeight) + 16 * a); Float4 B = *Pointer
(constants + OFFSET(Constants,uvStart) + 16 * a); Float4 du = uDelta; Float4 dv = vDelta; Float4 u0 = u + B * du; Float4 v0 = v + B * dv; du *= A; dv *= A; Int i = 0; Do { sampleFloat(texture, c, u0, v0, w, lod, face, secondLOD); u0 += du; v0 += dv; cSum.x += c.x * A; cSum.y += c.y * A; cSum.z += c.z * A; cSum.w += c.w * A; i++; } Until(i >= a) c.x = cSum.x; c.y = cSum.y; c.z = cSum.z; c.w = cSum.w; } } void SamplerCore::sampleFloat(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Int face[4], bool secondLOD) { if(state.textureType != TEXTURE_3D) { sampleFloat2D(texture, c, u, v, w, lod, face, secondLOD); } else { sampleFloat3D(texture, c, u, v, w, lod, secondLOD); } } void SamplerCore::sampleFloat2D(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, Int face[4], bool secondLOD) { int componentCount = textureComponentCount(); bool gather = state.textureFilter == FILTER_GATHER; Pointer
mipmap; Pointer
buffer[4]; selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); Short4 uuuu = address(u, state.addressingModeU, mipmap); Short4 vvvv = address(v, state.addressingModeV, mipmap); Short4 wwww = address(w, state.addressingModeW, mipmap); if(state.textureFilter == FILTER_POINT) { sampleTexel(c, uuuu, vvvv, wwww, w, mipmap, buffer); } else { Vector4f c0; Vector4f c1; Vector4f c2; Vector4f c3; Short4 uuuu0 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 0 : -1, lod); Short4 vvvv0 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 0 : -1, lod); Short4 uuuu1 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, gather ? 2 : +1, lod); Short4 vvvv1 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, gather ? 2 : +1, lod); sampleTexel(c0, uuuu0, vvvv0, wwww, w, mipmap, buffer); sampleTexel(c1, uuuu1, vvvv0, wwww, w, mipmap, buffer); sampleTexel(c2, uuuu0, vvvv1, wwww, w, mipmap, buffer); sampleTexel(c3, uuuu1, vvvv1, wwww, w, mipmap, buffer); if(!gather) // Blend { // Fractions Float4 fu = Frac(Float4(As
(uuuu0)) * *Pointer
(mipmap + OFFSET(Mipmap,fWidth))); Float4 fv = Frac(Float4(As
(vvvv0)) * *Pointer
(mipmap + OFFSET(Mipmap,fHeight))); if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x); if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y); if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z); if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w); if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x); if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y); if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z); if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w); if(componentCount >= 1) c.x = c0.x + fv * (c2.x - c0.x); if(componentCount >= 2) c.y = c0.y + fv * (c2.y - c0.y); if(componentCount >= 3) c.z = c0.z + fv * (c2.z - c0.z); if(componentCount >= 4) c.w = c0.w + fv * (c2.w - c0.w); } else { c.x = c1.x; c.y = c2.x; c.z = c3.x; c.w = c0.x; } } } void SamplerCore::sampleFloat3D(Pointer
&texture, Vector4f &c, Float4 &u, Float4 &v, Float4 &w, Float &lod, bool secondLOD) { int componentCount = textureComponentCount(); Pointer
mipmap; Pointer
buffer[4]; Int face[4]; selectMipmap(texture, buffer, mipmap, lod, face, secondLOD); Short4 uuuu = address(u, state.addressingModeU, mipmap); Short4 vvvv = address(v, state.addressingModeV, mipmap); Short4 wwww = address(w, state.addressingModeW, mipmap); if(state.textureFilter == FILTER_POINT) { sampleTexel(c, uuuu, vvvv, wwww, w, mipmap, buffer); } else { Vector4f &c0 = c; Vector4f c1; Vector4f c2; Vector4f c3; Vector4f c4; Vector4f c5; Vector4f c6; Vector4f c7; Short4 uuuu0 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, -1, lod); Short4 vvvv0 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, -1, lod); Short4 wwww0 = offsetSample(wwww, mipmap, OFFSET(Mipmap,wHalf), state.addressingModeW == ADDRESSING_WRAP, -1, lod); Short4 uuuu1 = offsetSample(uuuu, mipmap, OFFSET(Mipmap,uHalf), state.addressingModeU == ADDRESSING_WRAP, +1, lod); Short4 vvvv1 = offsetSample(vvvv, mipmap, OFFSET(Mipmap,vHalf), state.addressingModeV == ADDRESSING_WRAP, +1, lod); Short4 wwww1 = offsetSample(wwww, mipmap, OFFSET(Mipmap,wHalf), state.addressingModeW == ADDRESSING_WRAP, +1, lod); sampleTexel(c0, uuuu0, vvvv0, wwww0, w, mipmap, buffer); sampleTexel(c1, uuuu1, vvvv0, wwww0, w, mipmap, buffer); sampleTexel(c2, uuuu0, vvvv1, wwww0, w, mipmap, buffer); sampleTexel(c3, uuuu1, vvvv1, wwww0, w, mipmap, buffer); sampleTexel(c4, uuuu0, vvvv0, wwww1, w, mipmap, buffer); sampleTexel(c5, uuuu1, vvvv0, wwww1, w, mipmap, buffer); sampleTexel(c6, uuuu0, vvvv1, wwww1, w, mipmap, buffer); sampleTexel(c7, uuuu1, vvvv1, wwww1, w, mipmap, buffer); // Fractions Float4 fu = Frac(Float4(As
(uuuu0)) * *Pointer
(mipmap + OFFSET(Mipmap,fWidth))); Float4 fv = Frac(Float4(As
(vvvv0)) * *Pointer
(mipmap + OFFSET(Mipmap,fHeight))); Float4 fw = Frac(Float4(As
(wwww0)) * *Pointer
(mipmap + OFFSET(Mipmap,fDepth))); // Blend first slice if(componentCount >= 1) c0.x = c0.x + fu * (c1.x - c0.x); if(componentCount >= 2) c0.y = c0.y + fu * (c1.y - c0.y); if(componentCount >= 3) c0.z = c0.z + fu * (c1.z - c0.z); if(componentCount >= 4) c0.w = c0.w + fu * (c1.w - c0.w); if(componentCount >= 1) c2.x = c2.x + fu * (c3.x - c2.x); if(componentCount >= 2) c2.y = c2.y + fu * (c3.y - c2.y); if(componentCount >= 3) c2.z = c2.z + fu * (c3.z - c2.z); if(componentCount >= 4) c2.w = c2.w + fu * (c3.w - c2.w); if(componentCount >= 1) c0.x = c0.x + fv * (c2.x - c0.x); if(componentCount >= 2) c0.y = c0.y + fv * (c2.y - c0.y); if(componentCount >= 3) c0.z = c0.z + fv * (c2.z - c0.z); if(componentCount >= 4) c0.w = c0.w + fv * (c2.w - c0.w); // Blend second slice if(componentCount >= 1) c4.x = c4.x + fu * (c5.x - c4.x); if(componentCount >= 2) c4.y = c4.y + fu * (c5.y - c4.y); if(componentCount >= 3) c4.z = c4.z + fu * (c5.z - c4.z); if(componentCount >= 4) c4.w = c4.w + fu * (c5.w - c4.w); if(componentCount >= 1) c6.x = c6.x + fu * (c7.x - c6.x); if(componentCount >= 2) c6.y = c6.y + fu * (c7.y - c6.y); if(componentCount >= 3) c6.z = c6.z + fu * (c7.z - c6.z); if(componentCount >= 4) c6.w = c6.w + fu * (c7.w - c6.w); if(componentCount >= 1) c4.x = c4.x + fv * (c6.x - c4.x); if(componentCount >= 2) c4.y = c4.y + fv * (c6.y - c4.y); if(componentCount >= 3) c4.z = c4.z + fv * (c6.z - c4.z); if(componentCount >= 4) c4.w = c4.w + fv * (c6.w - c4.w); // Blend slices if(componentCount >= 1) c0.x = c0.x + fw * (c4.x - c0.x); if(componentCount >= 2) c0.y = c0.y + fw * (c4.y - c0.y); if(componentCount >= 3) c0.z = c0.z + fw * (c4.z - c0.z); if(componentCount >= 4) c0.w = c0.w + fw * (c4.w - c0.w); } } void SamplerCore::computeLod(Pointer
&texture, Float &lod, Float &anisotropy, Float4 &uDelta, Float4 &vDelta, Float4 &uuuu, Float4 &vvvv, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerMethod method) { if(method != Lod) { Float4 duvdxy; if(method != Grad) { duvdxy = Float4(uuuu.yz, vvvv.yz) - Float4(uuuu.xx, vvvv.xx); } else { Float4 dudxy = Float4(dsx.x.xx, dsy.x.xx); Float4 dvdxy = Float4(dsx.y.xx, dsy.y.xx); duvdxy = Float4(dudxy.xz, dvdxy.xz); } // Scale by texture dimensions and LOD Float4 dUVdxy = duvdxy * *Pointer
(texture + OFFSET(Texture,widthHeightLOD)); Float4 dUV2dxy = dUVdxy * dUVdxy; Float4 dUV2 = dUV2dxy.xy + dUV2dxy.zw; lod = Max(Float(dUV2.x), Float(dUV2.y)); // Square length of major axis if(state.textureFilter == FILTER_ANISOTROPIC) { Float det = Abs(Float(dUVdxy.x) * Float(dUVdxy.w) - Float(dUVdxy.y) * Float(dUVdxy.z)); Float4 dudx = duvdxy.xxxx; Float4 dudy = duvdxy.yyyy; Float4 dvdx = duvdxy.zzzz; Float4 dvdy = duvdxy.wwww; Int4 mask = As
(CmpNLT(dUV2.x, dUV2.y)); uDelta = As
(As
(dudx) & mask | As
(dudy) & ~mask); vDelta = As
(As
(dvdx) & mask | As
(dvdy) & ~mask); anisotropy = lod * Rcp_pp(det); anisotropy = Min(anisotropy, *Pointer
(texture + OFFSET(Texture,maxAnisotropy))); lod *= Rcp_pp(anisotropy * anisotropy); } // log2(sqrt(lod)) lod = Float(As
(lod)); lod -= Float(0x3F800000); lod *= As
(Int(0x33800000)); if(method == Bias) { lod += lodBias; } } else { lod = lodBias + *Pointer
(texture + OFFSET(Texture,LOD)); } lod = Max(lod, 0.0f); lod = Min(lod, Float(MIPMAP_LEVELS - 2)); // Trilinear accesses lod+1 } void SamplerCore::computeLodCube(Pointer
&texture, Float &lod, Float4 &u, Float4 &v, Float4 &s, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerMethod method) { if(method != Lod) { if(method != Grad) { Float4 dudxy = u.ywyw - u; Float4 dvdxy = v.ywyw - v; Float4 dsdxy = s.ywyw - s; // Scale by texture dimensions and LOD dudxy *= *Pointer
(texture + OFFSET(Texture,widthLOD)); dvdxy *= *Pointer
(texture + OFFSET(Texture,widthLOD)); dsdxy *= *Pointer
(texture + OFFSET(Texture,widthLOD)); dudxy *= dudxy; dvdxy *= dvdxy; dsdxy *= dsdxy; dudxy += dvdxy; dudxy += dsdxy; lod = Max(Float(dudxy.x), Float(dudxy.y)); // FIXME: Max(dudxy.x, dudxy.y); } else { Float4 dudxy = Float4(dsx.x.xx, dsy.x.xx); Float4 dvdxy = Float4(dsx.y.xx, dsy.y.xx); Float4 duvdxy = Float4(dudxy.xz, dvdxy.xz); // Scale by texture dimensions and LOD Float4 dUVdxy = duvdxy * *Pointer
(texture + OFFSET(Texture,widthLOD)); Float4 dUV2dxy = dUVdxy * dUVdxy; Float4 dUV2 = dUV2dxy.xy + dUV2dxy.zw; lod = Max(Float(dUV2.x), Float(dUV2.y)); // Square length of major axis } // log2(sqrt(lod)) lod = Float(As
(lod)); lod -= Float(0x3F800000); lod *= As
(Int(0x33800000)); if(method == Bias) { lod += lodBias; } } else { lod = lodBias + *Pointer
(texture + OFFSET(Texture,LOD)); } lod = Max(lod, 0.0f); lod = Min(lod, Float(MIPMAP_LEVELS - 2)); // Trilinear accesses lod+1 } void SamplerCore::computeLod3D(Pointer
&texture, Float &lod, Float4 &uuuu, Float4 &vvvv, Float4 &wwww, const Float &lodBias, Vector4f &dsx, Vector4f &dsy, SamplerMethod method) { if(state.mipmapFilter == MIPMAP_NONE) { } else // Point and linear filter { if(method != Lod) { Float4 dudxy; Float4 dvdxy; Float4 dsdxy; if(method != Grad) { dudxy = uuuu.ywyw - uuuu; dvdxy = vvvv.ywyw - vvvv; dsdxy = wwww.ywyw - wwww; } else { dudxy = dsx.x; dvdxy = dsx.y; dsdxy = dsx.z; dudxy = Float4(dudxy.xx, dsy.x.xx); dvdxy = Float4(dvdxy.xx, dsy.y.xx); dsdxy = Float4(dsdxy.xx, dsy.z.xx); dudxy = Float4(dudxy.xz, dudxy.xz); dvdxy = Float4(dvdxy.xz, dvdxy.xz); dsdxy = Float4(dsdxy.xz, dsdxy.xz); } // Scale by texture dimensions and LOD dudxy *= *Pointer
(texture + OFFSET(Texture,widthLOD)); dvdxy *= *Pointer
(texture + OFFSET(Texture,heightLOD)); dsdxy *= *Pointer
(texture + OFFSET(Texture,depthLOD)); dudxy *= dudxy; dvdxy *= dvdxy; dsdxy *= dsdxy; dudxy += dvdxy; dudxy += dsdxy; lod = Max(Float(dudxy.x), Float(dudxy.y)); // FIXME: Max(dudxy.x, dudxy.y); // log2(sqrt(lod)) lod = Float(As
(lod)); lod -= Float(0x3F800000); lod *= As
(Int(0x33800000)); if(method == Bias) { lod += lodBias; } } else { lod = lodBias + *Pointer
(texture + OFFSET(Texture,LOD)); } lod = Max(lod, Float(0.0f)); // FIXME lod = Min(lod, Float(MIPMAP_LEVELS - 2)); // Trilinear accesses lod+1 } } void SamplerCore::cubeFace(Int face[4], Float4 &U, Float4 &V, Float4 &lodX, Float4 &lodY, Float4 &lodZ, Float4 &x, Float4 &y, Float4 &z) { Int4 xn = CmpLT(x, Float4(0.0f)); // x < 0 Int4 yn = CmpLT(y, Float4(0.0f)); // y < 0 Int4 zn = CmpLT(z, Float4(0.0f)); // z < 0 Float4 absX = Abs(x); Float4 absY = Abs(y); Float4 absZ = Abs(z); Int4 xy = CmpNLE(absX, absY); // abs(x) > abs(y) Int4 yz = CmpNLE(absY, absZ); // abs(y) > abs(z) Int4 zx = CmpNLE(absZ, absX); // abs(z) > abs(x) Int4 xMajor = xy & ~zx; // abs(x) > abs(y) && abs(x) > abs(z) Int4 yMajor = yz & ~xy; // abs(y) > abs(z) && abs(y) > abs(x) Int4 zMajor = zx & ~yz; // abs(z) > abs(x) && abs(z) > abs(y) // FACE_POSITIVE_X = 000b // FACE_NEGATIVE_X = 001b // FACE_POSITIVE_Y = 010b // FACE_NEGATIVE_Y = 011b // FACE_POSITIVE_Z = 100b // FACE_NEGATIVE_Z = 101b Int yAxis = SignMask(yMajor); Int zAxis = SignMask(zMajor); Int4 n = ((xn & xMajor) | (yn & yMajor) | (zn & zMajor)) & Int4(0x80000000); Int negative = SignMask(n); face[0] = *Pointer
(constants + OFFSET(Constants,transposeBit0) + negative * 4); face[0] |= *Pointer
(constants + OFFSET(Constants,transposeBit1) + yAxis * 4); face[0] |= *Pointer
(constants + OFFSET(Constants,transposeBit2) + zAxis * 4); face[1] = (face[0] >> 4) & 0x7; face[2] = (face[0] >> 8) & 0x7; face[3] = (face[0] >> 12) & 0x7; face[0] &= 0x7; Float4 M = Max(Max(absX, absY), absZ); // U = xMajor ? (neg ^ -z) : (zMajor & neg) ^ x) U = As
((xMajor & (n ^ As
(-z))) | (~xMajor & ((zMajor & n) ^ As
(x)))); // V = !yMajor ? -y : (n ^ z) V = As
((~yMajor & As
(-y)) | (yMajor & (n ^ As
(z)))); M = reciprocal(M) * Float4(0.5f); U = U * M + Float4(0.5f); V = V * M + Float4(0.5f); lodX = x * M; lodY = y * M; lodZ = z * M; } void SamplerCore::computeIndices(Int index[4], Short4 uuuu, Short4 vvvv, Short4 wwww, const Pointer
&mipmap) { Short4 uuu2; if(!state.hasNPOTTexture && !hasFloatTexture()) { vvvv = As
(vvvv) >> *Pointer
(mipmap + OFFSET(Mipmap,vFrac)); uuu2 = uuuu; uuuu = As
(UnpackLow(uuuu, vvvv)); uuu2 = As
(UnpackHigh(uuu2, vvvv)); uuuu = As
(As
(uuuu) >> *Pointer
(mipmap + OFFSET(Mipmap,uFrac))); uuu2 = As
(As
(uuu2) >> *Pointer
(mipmap + OFFSET(Mipmap,uFrac))); } else { uuuu = MulHigh(As
(uuuu), *Pointer
(mipmap + OFFSET(Mipmap,width))); vvvv = MulHigh(As
(vvvv), *Pointer
(mipmap + OFFSET(Mipmap,height))); uuu2 = uuuu; uuuu = As
(UnpackLow(uuuu, vvvv)); uuu2 = As
(UnpackHigh(uuu2, vvvv)); uuuu = As
(MulAdd(uuuu, *Pointer
(mipmap + OFFSET(Mipmap,onePitchP)))); uuu2 = As
(MulAdd(uuu2, *Pointer
(mipmap + OFFSET(Mipmap,onePitchP)))); } if((state.textureType == TEXTURE_3D) || (state.textureType == TEXTURE_2D_ARRAY)) { if(state.textureType != TEXTURE_2D_ARRAY) { wwww = MulHigh(As
(wwww), *Pointer
(mipmap + OFFSET(Mipmap, depth))); } Short4 www2 = wwww; wwww = As
(UnpackLow(wwww, Short4(0x0000, 0x0000, 0x0000, 0x0000))); www2 = As
(UnpackHigh(www2, Short4(0x0000, 0x0000, 0x0000, 0x0000))); wwww = As
(MulAdd(wwww, *Pointer
(mipmap + OFFSET(Mipmap,sliceP)))); www2 = As
(MulAdd(www2, *Pointer
(mipmap + OFFSET(Mipmap,sliceP)))); uuuu = As
(As
(uuuu) + As
(wwww)); uuu2 = As
(As
(uuu2) + As
(www2)); } index[0] = Extract(As
(uuuu), 0); index[1] = Extract(As
(uuuu), 1); index[2] = Extract(As
(uuu2), 0); index[3] = Extract(As
(uuu2), 1); } void SamplerCore::sampleTexel(Vector4s &c, Short4 &uuuu, Short4 &vvvv, Short4 &wwww, Pointer
&mipmap, Pointer
buffer[4]) { Int index[4]; computeIndices(index, uuuu, vvvv, wwww, mipmap); int f0 = state.textureType == TEXTURE_CUBE ? 0 : 0; int f1 = state.textureType == TEXTURE_CUBE ? 1 : 0; int f2 = state.textureType == TEXTURE_CUBE ? 2 : 0; int f3 = state.textureType == TEXTURE_CUBE ? 3 : 0; if(has16bitTextureFormat()) { c.x = Insert(c.x, *Pointer
(buffer[f0] + 2 * index[0]), 0); c.x = Insert(c.x, *Pointer