1 /** 2 ** 3 ** Copyright 2010, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include "texture.h" 19 20 #include <assert.h> 21 #include <string.h> 22 #include <math.h> 23 24 #include "pixelflinger2.h" 25 26 #if USE_LLVM_EXECUTIONENGINE 27 #include <llvm/Module.h> 28 #include <llvm/ExecutionEngine/JIT.h> 29 #include <llvm/DerivedTypes.h> 30 #endif 31 32 #if !USE_LLVM_TEXTURE_SAMPLER 33 34 const struct GGLContext * textureGGLContext; 35 36 union Pixel { unsigned char channels[4]; unsigned int val; }; 37 38 static inline void PixelRGBAToVector4 (const Pixel *pixel, Vector4 * color) __attribute__((always_inline)); 39 static inline void PixelRGBAToVector4 (const Pixel *pixel, Vector4 * color) 40 { 41 #if defined(__ARM_HAVE_NEON) && USE_NEON 42 int32x4_t c; 43 c = vsetq_lane_s32(pixel->channels[0], c, 0); 44 c = vsetq_lane_s32(pixel->channels[1], c, 1); 45 c = vsetq_lane_s32(pixel->channels[2], c, 2); 46 c = vsetq_lane_s32(pixel->channels[3], c, 3); 47 color->f4 = vcvtq_f32_s32(c); 48 color->f4 = vmulq_n_f32(color->f4, 1 / 255.0f); 49 #else 50 color->r = (float)pixel->channels[0] / 255; 51 color->g = (float)pixel->channels[1] / 255; 52 color->b = (float)pixel->channels[2] / 255; 53 color->a = (float)pixel->channels[3] / 255; 54 #endif 55 } 56 57 static inline void RGBAToVector4(const unsigned int rgba, Vector4 * color) 58 { 59 PixelRGBAToVector4((const Pixel *)&rgba, color); 60 } 61 62 static inline void Lerp(Vec4<int> * a, Vec4<int> * b, int x, Vec4<int> * d) 63 { 64 for (unsigned i = 0; i < 4; i++) 65 { 66 int r = b->i[i] - a->i[i], s = a->i[i]; 67 d->i[i] = (r * x >> 16) + s; 68 } 69 } 70 71 static inline void ToIntVec(Vec4<int> * a) 72 { 73 a->u[3] = a->u[0] >> 24; 74 a->u[2] = (a->u[0] >> 16) & 0xff; 75 a->u[1] = (a->u[0] >> 8) & 0xff; 76 a->u[0] &= 0xff; 77 } 78 79 template<GGLPixelFormat format> 80 static void PointSample(unsigned sample[4], const unsigned * data, const unsigned index) 81 { 82 if (GGL_PIXEL_FORMAT_RGBA_8888 == format) 83 *sample = *(data + index); 84 else if (GGL_PIXEL_FORMAT_RGBX_8888 == format) 85 { 86 *sample = *(data + index); 87 *sample |= 0xff000000; 88 } 89 else if (GGL_PIXEL_FORMAT_RGB_565 == format) 90 { 91 sample[0] = *((const unsigned short *)data + index); 92 sample[1] = (sample[0] & 0x7e0) << 5; 93 sample[2] = (sample[0] & 0xf800) << 8; 94 sample[0] = (sample[0] & 0x1f) << 3; 95 96 sample[0] |= sample[0] >> 5; 97 sample[1] = (sample[1] | (sample[1] >> 6)) & 0xff00; 98 sample[2] = (sample[2] | (sample[2] >> 5)) & 0xff0000; 99 100 sample[0] |= sample[1]; 101 sample[0] |= sample[2]; 102 sample[0] |= 0xff000000; 103 } 104 else if (GGL_PIXEL_FORMAT_UNKNOWN == format) 105 sample[0] = 0xff00ffff; 106 else 107 assert(0); 108 } 109 110 static unsigned texcoordWrap(const unsigned wrap, float r, const unsigned size, 111 unsigned * lerp) 112 { 113 const unsigned shift = 16; 114 unsigned odd = 0; 115 int tc; 116 117 tc = r * (1 << shift); 118 119 odd = tc & (1 << shift); 120 if (0 == wrap || 2 == wrap) // REPEAT or MIRRORED 121 tc &= (1 << shift) - 1; // only take mantissa 122 tc *= size - 1; 123 // TODO DXL linear filtering needs to be fixed for texcoord outside of [0,1] 124 *lerp = tc & ((1 << shift) - 1); 125 tc >>= shift; 126 127 if (0 == wrap) // GL_REPEAT 128 { } 129 else if (1 == wrap) // GL_CLAMP_TO_EDGE 130 tc = MIN2(size - 1, MAX2(0, tc)); 131 else if (2 == wrap) 132 tc = odd ? size - 1 - tc : tc; 133 else 134 assert(0); 135 return tc; 136 } 137 138 template<GGLPixelFormat format, ChannelType output, unsigned minMag, unsigned wrapS, unsigned wrapT> 139 static void tex2d(unsigned sample[4], const float tex_coord[4], const unsigned sampler) 140 { 141 const unsigned * data = (const unsigned *)textureGGLContext->textureState.textureData[sampler]; 142 const unsigned width = textureGGLContext->textureState.textureDimensions[sampler * 2]; 143 const unsigned height = textureGGLContext->textureState.textureDimensions[sampler * 2 + 1]; 144 unsigned xLerp = 0, yLerp = 0; 145 const unsigned x0 = texcoordWrap(wrapS, tex_coord[0], width, &xLerp); 146 const unsigned y0 = texcoordWrap(wrapT, tex_coord[1], height, &yLerp); 147 148 if (0 == minMag) 149 { 150 PointSample<format>(sample, data, y0 * width + x0); 151 sample[1] = (sample[0] & 0xff00) >> 8; 152 sample[2] = (sample[0] & 0xff0000) >> 16; 153 sample[3] = (sample[0] & 0xff000000) >> 24; 154 sample[0] &= 0xff; 155 } 156 else if (1 == minMag) 157 { 158 const unsigned x1 = MIN2(width - 1, x0 + 1), y1 = MIN2(height - 1, y0 + 1); 159 Vec4<int> samples[4] = {0}; 160 PointSample<format>((unsigned *)(samples + 0), data, y0 * width + x0); 161 ToIntVec(samples + 0); 162 PointSample<format>((unsigned *)(samples + 1), data, y0 * width + x1); 163 ToIntVec(samples + 1); 164 PointSample<format>((unsigned *)(samples + 2), data, y1 * width + x1); 165 ToIntVec(samples + 2); 166 PointSample<format>((unsigned *)(samples + 3), data, y1 * width + x0); 167 ToIntVec(samples + 3); 168 169 Lerp(samples + 0, samples + 1, xLerp, samples + 0); 170 Lerp(samples + 3, samples + 2, xLerp, samples + 3); 171 Lerp(samples + 0, samples + 3, yLerp, (Vec4<int> *)sample); 172 } 173 else 174 assert(0); 175 176 if (Fixed0 == output) // i32 non vector 177 sample[0] = (sample[3] << 24) | (sample[2] << 16) | (sample[1] << 8) | sample[0]; 178 else if (Fixed8 == output) // 4 x i32 179 ; // do nothing 180 else if (Fixed16 == output) // 4 x i32 181 { 182 sample[0] <<= 8; sample[1] <<= 8; sample[2] <<= 8; sample[3] <<= 8; 183 } 184 else if (Float == output) // 4 x float 185 { 186 float * fsample = (float *)sample; 187 fsample[0] = sample[0] / 255.0f; fsample[1] = sample[1] / 255.0f; 188 fsample[2] = sample[2] / 255.0f; fsample[3] = sample[3] / 255.0f; 189 } 190 } 191 192 template<GGLPixelFormat format, ChannelType output, unsigned minMag, unsigned wrapS, unsigned wrapT> 193 void texcube(unsigned sample[4], const float tex_coord[4], const unsigned sampler) 194 { 195 float mx = fabs(tex_coord[0]), my = fabs(tex_coord[1]), mz = fabs(tex_coord[2]); 196 float s = 0, t = 0, ma = 0; 197 unsigned face = 0; 198 if (mx > my && mx > mz) 199 { 200 if (tex_coord[0] >= 0) 201 { 202 s = -tex_coord[2]; 203 t = -tex_coord[1]; 204 face = 0; 205 } 206 else 207 { 208 s = tex_coord[2]; 209 t = -tex_coord[1]; 210 face = 1; 211 } 212 ma = mx; 213 } 214 else if (my > mx && my > mz) 215 { 216 if (tex_coord[1] >= 0) 217 { 218 s = tex_coord[0]; 219 t = tex_coord[2]; 220 face = 2; 221 } 222 else 223 { 224 s = tex_coord[0]; 225 t = -tex_coord[2]; 226 face = 3; 227 } 228 ma = my; 229 } 230 else 231 { 232 if (tex_coord[2] >= 0) 233 { 234 s = tex_coord[0]; 235 t = -tex_coord[1]; 236 face = 4; 237 } 238 else 239 { 240 s = -tex_coord[0]; 241 t = -tex_coord[2]; 242 face = 5; 243 } 244 ma = mz; 245 } 246 247 s = (s / ma + 1) * 0.5f; 248 t = (t / ma + 1) * 0.5f; 249 250 const unsigned * data = (const unsigned *)textureGGLContext->textureState.textureData[sampler]; 251 const unsigned width = textureGGLContext->textureState.textureDimensions[sampler * 2]; 252 const unsigned height = textureGGLContext->textureState.textureDimensions[sampler * 2 + 1]; 253 unsigned xLerp = 0, yLerp = 0; 254 const unsigned x0 = texcoordWrap(wrapS, s, width, &xLerp); 255 const unsigned y0 = texcoordWrap(wrapT, t, height, &yLerp); 256 257 if (0 == minMag) 258 { 259 PointSample<format>(sample, data, y0 * width + x0); 260 sample[1] = (sample[0] & 0xff00) >> 8; 261 sample[2] = (sample[0] & 0xff0000) >> 16; 262 sample[3] = (sample[0] & 0xff000000) >> 24; 263 sample[0] &= 0xff; 264 } 265 else if (1 == minMag) 266 { 267 const unsigned x1 = MIN2(width - 1, x0 + 1), y1 = MIN2(height - 1, y0 + 1); 268 Vec4<int> samples[4] = {0}; 269 PointSample<format>((unsigned *)(samples + 0), data, face * width * height + y0 * width + x0); 270 ToIntVec(samples + 0); 271 PointSample<format>((unsigned *)(samples + 1), data, face * width * height + y0 * width + x1); 272 ToIntVec(samples + 1); 273 PointSample<format>((unsigned *)(samples + 2), data, face * width * height + y1 * width + x1); 274 ToIntVec(samples + 2); 275 PointSample<format>((unsigned *)(samples + 3), data, face * width * height + y1 * width + x0); 276 ToIntVec(samples + 3); 277 278 Lerp(samples + 0, samples + 1, xLerp, samples + 0); 279 Lerp(samples + 3, samples + 2, xLerp, samples + 3); 280 Lerp(samples + 0, samples + 3, yLerp, (Vec4<int> *)sample); 281 } 282 else 283 assert(0); 284 285 if (Fixed0 == output) // i32 non vector 286 sample[0] = (sample[3] << 24) | (sample[2] << 16) | (sample[1] << 8) | sample[0]; 287 else if (Fixed8 == output) // 4 x i32 288 ; // do nothing 289 else if (Fixed16 == output) // 4 x i32 290 { 291 sample[0] <<= 8; sample[1] <<= 8; sample[2] <<= 8; sample[3] <<= 8; 292 } 293 else if (Float == output) // 4 x float 294 { 295 float * fsample = (float *)sample; 296 fsample[0] = sample[0] / 255.0f; fsample[1] = sample[1] / 255.0f; 297 fsample[2] = sample[2] / 255.0f; fsample[3] = sample[3] / 255.0f; 298 } 299 300 } 301 302 #define TEXTURE_FUNCTION_ENTRY(target,format,output,filter,wrapS,wrapT) \ 303 { #target"_"#format"_"#output"_"#filter"_"#wrapS"_"#wrapT, \ 304 target<GGL_PIXEL_FORMAT_##format, output, filter, wrapS, wrapT> }, 305 306 #define TEXTURE_FUNCTION_ENTRY_WRAPT(target,format,output,minMag,wrapS) \ 307 TEXTURE_FUNCTION_ENTRY(target,format,output,minMag,wrapS,0) \ 308 TEXTURE_FUNCTION_ENTRY(target,format,output,minMag,wrapS,1) \ 309 TEXTURE_FUNCTION_ENTRY(target,format,output,minMag,wrapS,2) 310 311 #define TEXTURE_FUNCTION_ENTRY_WRAPS(target,format,output,minMag) \ 312 TEXTURE_FUNCTION_ENTRY_WRAPT(target,format,output,minMag,0) \ 313 TEXTURE_FUNCTION_ENTRY_WRAPT(target,format,output,minMag,1) \ 314 TEXTURE_FUNCTION_ENTRY_WRAPT(target,format,output,minMag,2) 315 316 #define TEXTURE_FUNCTION_ENTRY_FILTER(target,format,output) \ 317 TEXTURE_FUNCTION_ENTRY_WRAPS(target,format,output,0) \ 318 TEXTURE_FUNCTION_ENTRY_WRAPS(target,format,output,1) 319 320 #define TEXTURE_FUNCTION_ENTRY_OUTPUT(target,format) \ 321 TEXTURE_FUNCTION_ENTRY_FILTER(target,format,Float) \ 322 TEXTURE_FUNCTION_ENTRY_FILTER(target,format,Fixed16) \ 323 TEXTURE_FUNCTION_ENTRY_FILTER(target,format,Fixed8) \ 324 TEXTURE_FUNCTION_ENTRY_FILTER(target,format,Fixed0) 325 326 #define TEXTURE_FUNCTION_ENTRY_FORMAT(target) \ 327 TEXTURE_FUNCTION_ENTRY_OUTPUT(target,RGBA_8888) \ 328 TEXTURE_FUNCTION_ENTRY_OUTPUT(target,RGBX_8888) \ 329 TEXTURE_FUNCTION_ENTRY_OUTPUT(target,RGB_565) \ 330 TEXTURE_FUNCTION_ENTRY_OUTPUT(target,UNKNOWN) 331 332 #define TEXTURE_FUNCTION_ENTRIES \ 333 TEXTURE_FUNCTION_ENTRY_FORMAT(tex2d) \ 334 TEXTURE_FUNCTION_ENTRY_FORMAT(texcube) 335 336 static struct TextureFunctionMapping 337 { 338 const char * name; 339 void (* function)(unsigned sample[4], const float tex_coord[4], const unsigned int tex_id); 340 } textureFunctionMapping [] = { TEXTURE_FUNCTION_ENTRIES }; 341 342 343 #undef TEXTURE_FUNCTION_ENTRY 344 345 #endif //#if !USE_LLVM_TEXTURE_SAMPLER 346 347 #if USE_LLVM_EXECUTIONENGINE && !USE_LLVM_TEXTURE_SAMPLER 348 349 void DeclareTextureFunctions(llvm::Module * mod) 350 { 351 llvm::LLVMContext & llvm_ctx = mod->getContext(); 352 353 std::vector<const llvm::Type*> funcArgs; 354 llvm::VectorType *vectorType = llvm::VectorType::get(llvm::Type::getFloatTy(llvm_ctx), 4); 355 llvm::PointerType * vectorPtr = llvm::PointerType::get(vectorType, 0); 356 357 funcArgs.push_back(vectorPtr); 358 funcArgs.push_back(vectorPtr); 359 funcArgs.push_back(llvm::Type::getInt32Ty(llvm_ctx)); 360 // void function(float[4], const float[4], unsigned) 361 362 llvm::FunctionType *functionType = llvm::FunctionType::get(llvm::Type::getVoidTy(llvm_ctx), 363 funcArgs, 364 false); 365 366 for (unsigned i = 0; i < sizeof(textureFunctionMapping) / sizeof(*textureFunctionMapping); i++) 367 { 368 llvm::Function * func = llvm::cast<llvm::Function>( 369 mod->getOrInsertFunction(textureFunctionMapping[i].name, functionType)); 370 func->setLinkage(llvm::GlobalValue::ExternalLinkage); 371 func->setCallingConv(llvm::CallingConv::C); 372 } 373 } 374 375 void AddTextureFunctionMappings(llvm::Module * mod, llvm::ExecutionEngine * ee) 376 { 377 if (mod->getFunction("tex2d_soa")) 378 assert(0);//ee->addGlobalMapping(func, (void *)tex2d_soa); 379 380 for (unsigned i = 0; i < sizeof(textureFunctionMapping) / sizeof(*textureFunctionMapping); i++) 381 { 382 llvm::Function * function = mod->getFunction(textureFunctionMapping[i].name); 383 if (function) 384 ee->updateGlobalMapping(function, (void *)textureFunctionMapping[i].function); 385 } 386 } 387 #endif // #if USE_LLVM_EXECUTIONENGINE && !USE_LLVM_TEXTURE_SAMPLER 388 389 static void SetSampler(GGLInterface * iface, const unsigned sampler, GGLTexture * texture) 390 { 391 assert(GGL_MAXCOMBINEDTEXTUREIMAGEUNITS > sampler); 392 GGL_GET_CONTEXT(ctx, iface); 393 if (!texture) 394 SetShaderVerifyFunctions(iface); 395 else if (ctx->state.textureState.textures[sampler].format != texture->format) 396 SetShaderVerifyFunctions(iface); 397 else if (ctx->state.textureState.textures[sampler].wrapS != texture->wrapS) 398 SetShaderVerifyFunctions(iface); 399 else if (ctx->state.textureState.textures[sampler].wrapT != texture->wrapT) 400 SetShaderVerifyFunctions(iface); 401 else if (ctx->state.textureState.textures[sampler].minFilter != texture->minFilter) 402 SetShaderVerifyFunctions(iface); 403 else if (ctx->state.textureState.textures[sampler].magFilter != texture->magFilter) 404 SetShaderVerifyFunctions(iface); 405 406 if (texture) 407 { 408 ctx->state.textureState.textures[sampler] = *texture; // shallow copy, data pointed to must remain valid 409 //ctx->state.textureState.textureData[sampler] = texture->levels[0]; 410 ctx->state.textureState.textureData[sampler] = texture->levels; 411 ctx->state.textureState.textureDimensions[sampler * 2] = texture->width; 412 ctx->state.textureState.textureDimensions[sampler * 2 + 1] = texture->height; 413 } 414 else 415 { 416 memset(ctx->state.textureState.textures + sampler, 0, sizeof(ctx->state.textureState.textures[sampler])); 417 ctx->state.textureState.textureData[sampler] = NULL; 418 ctx->state.textureState.textureDimensions[sampler * 2] = 0; 419 ctx->state.textureState.textureDimensions[sampler * 2 + 1] = 0; 420 } 421 } 422 423 void InitializeTextureFunctions(GGLInterface * iface) 424 { 425 iface->SetSampler = SetSampler; 426 }