1/**
2 **
3 ** Copyright 2011, 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 <stack>
19
20#include "src/pixelflinger2/pixelflinger2.h"
21
22#include <llvm/Support/IRBuilder.h>
23#include <llvm/Module.h>
24
25#include "src/pixelflinger2/llvm_helper.h"
26
27using namespace llvm;
28
29// texture data is int pointer to surface (will cast to short for 16bpp), index is linear texel index,
30// format is GGLPixelFormat for surface, return type is <4 x i32> rgba
31static Value * pointSample(IRBuilder<> & builder, Value * textureData, Value * index, const GGLPixelFormat format)
32{
33   Value * texel = NULL;
34   switch (format) {
35   case GGL_PIXEL_FORMAT_RGBA_8888:
36      textureData = builder.CreateGEP(textureData, index);
37      texel = builder.CreateLoad(textureData, "texel");
38      break;
39   case GGL_PIXEL_FORMAT_RGBX_8888:
40      textureData = builder.CreateGEP(textureData, index);
41      texel = builder.CreateLoad(textureData, "texel");
42      texel = builder.CreateOr(texel, builder.getInt32(0xff000000));
43      break;
44   case GGL_PIXEL_FORMAT_RGB_565: {
45      textureData = builder.CreateBitCast(textureData, PointerType::get(builder.getInt16Ty(), 0));
46      textureData = builder.CreateGEP(textureData, index);
47      texel = builder.CreateLoad(textureData, "texel565");
48      texel = builder.CreateZExt(texel, Type::getInt32Ty(builder.getContext()));
49
50      Value * b = builder.CreateAnd(texel, builder.getInt32(0x1f));
51      b = builder.CreateShl(b, builder.getInt32(3));
52      b = builder.CreateOr(b, builder.CreateLShr(b, builder.getInt32(5)));
53
54      Value * g = builder.CreateAnd(texel, builder.getInt32(0x7e0));
55      g = builder.CreateShl(g, builder.getInt32(5));
56      g = builder.CreateOr(g, builder.CreateLShr(g, builder.getInt32(6)));
57      g = builder.CreateAnd(g, builder.getInt32(0xff00));
58
59      Value * r = builder.CreateAnd(texel, builder.getInt32(0xF800));
60      r = builder.CreateShl(r, builder.getInt32(8));
61      r = builder.CreateOr(r, builder.CreateLShr(r, builder.getInt32(5)));
62      r = builder.CreateAnd(r, builder.getInt32(0xff0000));
63
64      texel = builder.CreateOr(r, builder.CreateOr(g, b));
65      texel = builder.CreateOr(texel, builder.getInt32(0xff000000), name("texel"));
66      break;
67   }
68   case GGL_PIXEL_FORMAT_A_8: {
69      textureData = builder.CreateBitCast(textureData, PointerType::get(builder.getInt8Ty(),0));
70      textureData = builder.CreateGEP(textureData, index);
71      texel = builder.CreateLoad(textureData, "texel_a8");
72      texel = builder.CreateZExt(texel, builder.getInt32Ty());
73      texel = builder.CreateShl(texel, builder.getInt32(24));
74      break;
75   }
76   case GGL_PIXEL_FORMAT_L_8: {
77      textureData = builder.CreateBitCast(textureData, PointerType::get(builder.getInt8Ty(),0));
78      textureData = builder.CreateGEP(textureData, index);
79      texel = builder.CreateLoad(textureData, "texel_l8");
80      texel = builder.CreateZExt(texel, builder.getInt32Ty());
81      texel = builder.CreateOr(texel, builder.CreateShl(texel, 8));
82      texel = builder.CreateOr(texel, builder.CreateShl(texel, 8));
83      texel = builder.CreateOr(texel, builder.getInt32(0xff000000));
84      break;
85   }
86   case GGL_PIXEL_FORMAT_LA_88: {
87      textureData = builder.CreateBitCast(textureData, PointerType::get(builder.getInt16Ty(),0));
88      textureData = builder.CreateGEP(textureData, index);
89      texel = builder.CreateLoad(textureData, "texel_la8");
90      texel = builder.CreateZExt(texel, builder.getInt32Ty());
91      Value * alpha = builder.CreateAnd(texel, builder.getInt32(0xff00));
92      texel = builder.CreateAnd(texel, builder.getInt32(0xff));
93      texel = builder.CreateOr(texel, builder.CreateShl(texel, 8));
94      texel = builder.CreateOr(texel, builder.CreateShl(texel, 8));
95      texel = builder.CreateOr(texel, builder.CreateShl(alpha, 16));
96      break;
97   }
98   case GGL_PIXEL_FORMAT_UNKNOWN: // usually means texture not set yet
99      LOGD("pf2: pointSample: unknown format, default to 0xffff00ff \n");
100      texel = builder.getInt32(0xffff00ff);
101      break;
102   default:
103      assert(0);
104      break;
105   }
106   Value * channels = Constant::getNullValue(intVecType(builder));
107
108//   if (dstDesc && dstDesc->IsInt32Color()) {
109//      channels = builder.CreateInsertElement(channels, texel, builder.getInt32(0));
110//      channels = builder.CreateBitCast(channels, floatVecType(builder));
111//      return channels;
112//   } else if (!dstDesc || dstDesc->IsVectorType()) {
113   channels = builder.CreateInsertElement(channels, texel, builder.getInt32(0));
114   channels = builder.CreateInsertElement(channels, texel, builder.getInt32(1));
115   channels = builder.CreateInsertElement(channels, texel, builder.getInt32(2));
116   channels = builder.CreateInsertElement(channels, texel, builder.getInt32(3));
117//      if (dstDesc && dstDesc->IsVectorType(Fixed8)) {
118//         channels = builder.CreateLShr(channels, constIntVec(builder, 0, 8, 16, 24));
119//         channels = builder.CreateAnd(channels, constIntVec(builder, 0xff, 0xff, 0xff, 0xff));
120//         channels = builder.CreateBitCast(channels, floatVecType(builder));
121//      } else if (dstDesc && dstDesc->IsVectorType(Fixed16)) {
122//         channels = builder.CreateShl(channels, constIntVec(builder, 8, 0, 0, 0));
123//         channels = builder.CreateLShr(channels, constIntVec(builder, 0, 0, 8, 16));
124//         channels = builder.CreateAnd(channels, constIntVec(builder, 0xff00, 0xff00, 0xff00, 0xff00));
125//         channels = builder.CreateBitCast(channels, floatVecType(builder));
126//      } else if (!dstDesc || dstDesc->IsVectorType(Float)) { // no analysis done in vertex shader, so use default float [0,1] output
127   channels = builder.CreateLShr(channels, constIntVec(builder, 0, 8, 16, 24));
128   channels = builder.CreateAnd(channels, constIntVec(builder, 0xff, 0xff, 0xff, 0xff));
129//   channels = builder.CreateUIToFP(channels, floatVecType(builder));
130//   channels = builder.CreateFMul(channels, constFloatVec(builder, 1 / 255.0f,  1 / 255.0f,
131//                                 1 / 255.0f, 1 / 255.0f));
132//      } else
133//         assert(0);
134//   } else
135//      assert(0);
136
137   return channels;
138}
139
140static const unsigned SHIFT = 16;
141
142// w  = width - 1, h = height - 1; similar to pointSample; returns <4 x i32> rgba
143static Value * linearSample(IRBuilder<> & builder, Value * textureData, Value * indexOffset,
144                            Value * x0, Value * y0, Value * xLerp, Value * yLerp,
145                            Value * w, Value * h,  Value * width, Value * height,
146                            const GGLPixelFormat format/*, const RegDesc * dstDesc*/)
147{
148   // TODO: linear filtering needs to be fixed for texcoord outside of [0,1]
149   Value * x1 = builder.CreateAdd(x0, builder.getInt32(1));
150   x1 = minIntScalar(builder, x1, w);
151   Value * y1 = builder.CreateAdd(y0, builder.getInt32(1));
152   y1 = minIntScalar(builder, y1, h);
153
154//   RegDesc regDesc;
155//   regDesc.SetVectorType(Fixed8);
156
157   Value * index = builder.CreateMul(y0, width);
158   index = builder.CreateAdd(index, x0);
159   index = builder.CreateAdd(index, indexOffset);
160   Value * s0 = pointSample(builder, textureData, index, format/*, &regDesc*/);
161//   s0 = builder.CreateBitCast(s0, intVecType(builder));
162
163   index = builder.CreateMul(y0, width);
164   index = builder.CreateAdd(index, x1);
165   index = builder.CreateAdd(index, indexOffset);
166   Value * s1 = pointSample(builder, textureData, index, format/*, &regDesc*/);
167//   s1 = builder.CreateBitCast(s1, intVecType(builder));
168
169   index = builder.CreateMul(y1, width);
170   index = builder.CreateAdd(index, x1);
171   index = builder.CreateAdd(index, indexOffset);
172   Value * s2 = pointSample(builder, textureData, index, format/*, &regDesc*/);
173//   s2 = builder.CreateBitCast(s2, intVecType(builder));
174
175   index = builder.CreateMul(y1, width);
176   index = builder.CreateAdd(index, x0);
177   index = builder.CreateAdd(index, indexOffset);
178   Value * s3 = pointSample(builder, textureData, index, format/*, &regDesc*/);
179//   s3 = builder.CreateBitCast(s3, intVecType(builder));
180
181   Value * xLerpVec = intVec(builder, xLerp, xLerp, xLerp, xLerp);
182
183   Value * h0 = builder.CreateMul(builder.CreateSub(s1, s0), xLerpVec);
184   // arithmetic shift right, since it's the result of subtraction, which could be negative
185   h0 = builder.CreateAShr(h0, constIntVec(builder, SHIFT, SHIFT, SHIFT, SHIFT));
186   h0 = builder.CreateAdd(h0, s0);
187
188   Value * h1 = builder.CreateMul(builder.CreateSub(s2, s3), xLerpVec);
189   h1 = builder.CreateAShr(h1, constIntVec(builder, SHIFT, SHIFT, SHIFT, SHIFT));
190   h1 = builder.CreateAdd(h1, s3);
191
192   Value * sample = builder.CreateMul(builder.CreateSub(h1, h0),
193                                      intVec(builder, yLerp, yLerp, yLerp, yLerp));
194   sample = builder.CreateAShr(sample, constIntVec(builder, SHIFT, SHIFT, SHIFT, SHIFT));
195   sample = builder.CreateAdd(sample, h0);
196
197   return sample;
198//   if (!dstDesc || dstDesc->IsVectorType(Float)) {
199//      sample = builder.CreateUIToFP(sample, floatVecType(builder));
200//      return builder.CreateFMul(sample, constFloatVec(builder, 1 / 255.0f,  1 / 255.0f,
201//                                1 / 255.0f, 1 / 255.0f));
202//   } else if (dstDesc && dstDesc->IsVectorType(Fixed16)) {
203//      sample = builder.CreateShl(sample, constIntVec(builder, 8, 8, 8, 8));
204//      return builder.CreateBitCast(sample, floatVecType(builder));
205//   } else if (dstDesc && dstDesc->IsVectorType(Fixed8))
206//      return builder.CreateBitCast(sample, floatVecType(builder));
207//   else if (dstDesc && dstDesc->IsInt32Color()) {
208//      sample = builder.CreateShl(sample, constIntVec(builder, 0, 8, 16, 24));
209//      std::vector<llvm::Value*> samples = extractVector(sample);
210//      samples[0] = builder.CreateOr(samples[0], samples[1]);
211//      samples[0] = builder.CreateOr(samples[0], samples[2]);
212//      samples[0] = builder.CreateOr(samples[0], samples[3]);
213//      sample = builder.CreateInsertElement(sample, samples[0], builder.getInt32(0));
214//      return builder.CreateBitCast(sample, floatVecType(builder));
215//   } else
216//      assert(0);
217}
218
219// dim is size - 1, since [0.0f,1.0f]->[0, size - 1]
220static Value * texcoordWrap(IRBuilder<> & builder, const unsigned wrap,
221                            /*const ChannelType type,*/ Value * r, Value * size, Value * dim,
222                            Value ** texelLerp)
223{
224   Type * intType = Type::getInt32Ty(builder.getContext());
225   Value * tc = NULL;
226   Value * odd = NULL;
227//   if (Float == type) {
228   // convert float to fixed16 so that 16LSB are the remainder, and bit 16 is one
229   // mantissa is the amount between two texels, used for linear interpolation
230   tc = ConstantFP::get(builder.getContext(), APFloat(float(1 << SHIFT)));
231   tc = builder.CreateFMul(tc, r);
232   tc = builder.CreateFPToSI(tc, intType);
233//   } else if (Fixed16 == type) {
234//      assert(16 == SHIFT);
235//      tc = builder.CreateBitCast(r, Type::getInt32Ty(builder.getContext()));
236//   } else
237//      assert(0);
238
239   odd = builder.CreateAnd(tc, builder.getInt32(1 << SHIFT), name("tc_odd"));
240
241   if (0 == wrap || 2 == wrap) // just the mantissa for wrap and mirrored
242      tc = builder.CreateAnd(tc, builder.getInt32((1 << SHIFT) - 1));
243
244   tc = builder.CreateMul(tc, dim);
245
246   *texelLerp = builder.CreateAnd(tc, builder.getInt32((1 << SHIFT) - 1));
247
248   tc = builder.CreateLShr(tc, builder.getInt32(SHIFT));
249
250   if (0 == wrap) // GL_REPEAT
251   { } else if (1 == wrap) { // GL_CLAMP_TO_EDGE
252      tc = maxIntScalar(builder, tc, builder.getInt32(0));
253      tc = minIntScalar(builder, tc, dim);
254   } else if (2 == wrap) { // GL_MIRRORER_REPEAT
255      Value * tcPtr = builder.CreateAlloca(intType);
256      builder.CreateStore(tc, tcPtr);
257      odd = builder.CreateICmpNE(odd, builder.getInt32(0));
258
259      CondBranch condBranch(builder);
260      condBranch.ifCond(odd);
261
262      tc = builder.CreateSub(dim, tc, name("tc_mirrored"));
263      builder.CreateStore(tc, tcPtr);
264
265      condBranch.endif();
266
267      tc = builder.CreateLoad(tcPtr);
268   } else
269      assert(0);
270
271   return tc;
272}
273
274Value * tex2D(IRBuilder<> & builder, Value * in1, const unsigned sampler,
275              /*const RegDesc * in1Desc, const RegDesc * dstDesc,*/
276              const GGLState * gglCtx)
277{
278   Type * intType = builder.getInt32Ty();
279   PointerType * intPointerType = PointerType::get(intType, 0);
280
281   llvm::Module * module = builder.GetInsertBlock()->getParent()->getParent();
282   std::vector<Value * > texcoords = extractVector(builder, in1);
283
284   Value * textureDimensions = module->getGlobalVariable(_PF2_TEXTURE_DIMENSIONS_NAME_);
285   if (!textureDimensions)
286      textureDimensions = new GlobalVariable(*module, intType, true,
287                                             GlobalValue::ExternalLinkage,
288                                             NULL, _PF2_TEXTURE_DIMENSIONS_NAME_);
289   Value * textureWidth = builder.CreateConstInBoundsGEP1_32(textureDimensions,
290                          sampler * 2);
291   textureWidth = builder.CreateLoad(textureWidth, name("textureWidth"));
292   Value * textureHeight = builder.CreateConstInBoundsGEP1_32(textureDimensions,
293                           sampler * 2 + 1);
294   textureHeight = builder.CreateLoad(textureHeight, name("textureHeight"));
295   Value * textureW = builder.CreateSub(textureWidth, builder.getInt32(1));
296   Value * textureH = builder.CreateSub(textureHeight, builder.getInt32(1));
297//   ChannelType sType = Float, tType = Float;
298//   if (in1Desc) {
299//      sType = in1Desc->channels[0];
300//      tType = in1Desc->channels[1];
301//   }
302
303   Value * xLerp = NULL, * yLerp = NULL;
304   Value * x = texcoordWrap(builder, gglCtx->textureState.textures[sampler].wrapS,
305                            /*sType, */texcoords[0], textureWidth, textureW, &xLerp);
306   Value * y = texcoordWrap(builder, gglCtx->textureState.textures[sampler].wrapT,
307                            /*tType, */texcoords[1], textureHeight, textureH, &yLerp);
308
309   Value * index = builder.CreateMul(y, textureWidth);
310   index = builder.CreateAdd(index, x);
311
312   Value * textureData = module->getGlobalVariable(_PF2_TEXTURE_DATA_NAME_);
313   if (!textureData)
314      textureData = new GlobalVariable(*module, intPointerType,
315                                       true, GlobalValue::ExternalLinkage,
316                                       NULL, _PF2_TEXTURE_DATA_NAME_);
317
318   textureData = builder.CreateConstInBoundsGEP1_32(textureData, sampler);
319   textureData = builder.CreateLoad(textureData);
320
321   if (0 == gglCtx->textureState.textures[sampler].minFilter &&
322         0 == gglCtx->textureState.textures[sampler].magFilter) { // GL_NEAREST
323      Value * ret = pointSample(builder, textureData, index,
324                                gglCtx->textureState.textures[sampler].format/*, dstDesc*/);
325      return intColorVecToFloatColorVec(builder, ret);
326   } else if (1 == gglCtx->textureState.textures[sampler].minFilter &&
327              1 == gglCtx->textureState.textures[sampler].magFilter) { // GL_LINEAR
328      Value * ret = linearSample(builder, textureData, builder.getInt32(0), x, y, xLerp, yLerp,
329                                 textureW, textureH,  textureWidth, textureHeight,
330                                 gglCtx->textureState.textures[sampler].format/*, dstDesc*/);
331      return intColorVecToFloatColorVec(builder, ret);
332   } else
333      assert(!"unsupported texture filter");
334   return NULL;
335}
336
337// only positive float; used in cube map since major axis is positive
338static Value * FCmpGT(IRBuilder<> & builder, Value * lhs, Value * rhs)
339{
340   Type * const intType = Type::getInt32Ty(builder.getContext());
341   lhs = builder.CreateBitCast(lhs, intType);
342   rhs = builder.CreateBitCast(rhs, intType);
343   return builder.CreateICmpUGT(lhs, rhs);
344}
345
346static Value * FPositive(IRBuilder<> & builder, Value * val)
347{
348   // float cmp faster here
349   return builder.CreateFCmpOGE(val, Constant::getNullValue(builder.getFloatTy()));
350   //val = builder.CreateBitCast(val, Type::getInt32Ty(builder.getContext()));
351   //return builder.CreateICmpSGE(val, storage->constantInt(0));
352   //val = builder.CreateAnd(val, storage->constantInt(0x80000000));
353   //return builder.CreateICmpNE(val, storage->constantInt(0));
354}
355
356static Value * Fabs(IRBuilder<> & builder, Value * val)
357{
358   val = builder.CreateBitCast(val, builder.getInt32Ty());
359   val = builder.CreateAnd(val, builder.getInt32(~0x80000000));
360   return builder.CreateBitCast(val, builder.getFloatTy());
361   //return builder.CreateICmpSGE(val, storage->constantInt(0));
362}
363
364Value * texCube(IRBuilder<> & builder, Value * in1, const unsigned sampler,
365                /*const RegDesc * in1Desc, const RegDesc * dstDesc,*/
366                const GGLState * gglCtx)
367{
368//   if (in1Desc) // the major axis determination code is only float for now
369//      assert(in1Desc->IsVectorType(Float));
370
371   Type * const intType = builder.getInt32Ty();
372   PointerType * const intPointerType = PointerType::get(intType, 0);
373   Type * const floatType = builder.getFloatTy();
374
375   Constant * const float1 = constFloat(builder, 1.0f);
376   Constant * const float0_5 = constFloat(builder, 0.5f);
377
378   Module * module = builder.GetInsertBlock()->getParent()->getParent();
379   std::vector<Value * > texcoords = extractVector(builder, in1);
380
381   Value * textureDimensions = module->getGlobalVariable(_PF2_TEXTURE_DIMENSIONS_NAME_);
382   if (!textureDimensions)
383      textureDimensions = new GlobalVariable(*module, intType, true,
384                                             GlobalValue::ExternalLinkage,
385                                             NULL, _PF2_TEXTURE_DIMENSIONS_NAME_);
386   Value * textureWidth = builder.CreateConstInBoundsGEP1_32(textureDimensions,
387                          sampler * 2);
388   textureWidth = builder.CreateLoad(textureWidth, name("textureWidth"));
389   Value * textureHeight = builder.CreateConstInBoundsGEP1_32(textureDimensions,
390                           sampler * 2 + 1);
391   textureHeight = builder.CreateLoad(textureHeight, name("textureHeight"));
392   Value * textureW = builder.CreateSub(textureWidth, builder.getInt32(1));
393   Value * textureH = builder.CreateSub(textureHeight, builder.getInt32(1));
394
395   Value * mx = Fabs(builder, texcoords[0]), * my = Fabs(builder, texcoords[1]);
396   Value * mz = Fabs(builder, texcoords[2]);
397   Value * sPtr = builder.CreateAlloca(floatType);
398   Value * tPtr = builder.CreateAlloca(floatType);
399   Value * maPtr = builder.CreateAlloca(floatType);
400   Value * facePtr = builder.CreateAlloca(intType);
401
402   Value * mxGmyCmp = FCmpGT(builder, mx, my);
403   Value * mxGmzCmp = FCmpGT(builder, mx, mz);
404
405   CondBranch condBranch(builder);
406   condBranch.ifCond(builder.CreateAnd(mxGmyCmp, mxGmzCmp)); // if (mx > my && mx > mz)
407//   m_storage->setCurrentBlock(currentBlock(), false);
408   {
409      condBranch.ifCond(FPositive(builder, texcoords[0]));
410//      m_storage->setCurrentBlock(currentBlock(), false);
411      {
412         builder.CreateStore(builder.CreateFNeg(texcoords[2]), sPtr);
413         builder.CreateStore(builder.CreateFNeg(texcoords[1]), tPtr);
414         builder.CreateStore(builder.getInt32(0), facePtr);
415      }
416      condBranch.elseop();
417//      m_storage->setCurrentBlock(currentBlock(), false);
418      {
419         builder.CreateStore((texcoords[2]), sPtr);
420         builder.CreateStore(builder.CreateFNeg(texcoords[1]), tPtr);
421         builder.CreateStore(builder.getInt32(1), facePtr);
422      }
423      condBranch.endif(); // end if (x >= 0)
424//      m_storage->setCurrentBlock(currentBlock(), false);
425
426      builder.CreateStore(mx, maPtr);
427   }
428   condBranch.elseop(); // !(mx > my && mx > mz)
429//   m_storage->setCurrentBlock(currentBlock(), false);
430   {
431      Value * myGmxCmp = FCmpGT(builder, my, mx);
432      Value * myGmzCmp = FCmpGT(builder, my, mz);
433      condBranch.ifCond(builder.CreateAnd(myGmxCmp, myGmzCmp)); // my > mx && my > mz
434//      m_storage->setCurrentBlock(currentBlock(), false);
435      {
436         condBranch.ifCond(FPositive(builder, texcoords[1]));
437//         m_storage->setCurrentBlock(currentBlock(), false);
438         {
439            builder.CreateStore((texcoords[0]), sPtr);
440            builder.CreateStore((texcoords[2]), tPtr);
441            builder.CreateStore(builder.getInt32(2), facePtr);
442         }
443         condBranch.elseop();
444//         m_storage->setCurrentBlock(currentBlock(), false);
445         {
446            builder.CreateStore(texcoords[0], sPtr);
447            builder.CreateStore(builder.CreateFNeg(texcoords[2]), tPtr);
448            builder.CreateStore(builder.getInt32(3), facePtr);
449         }
450         condBranch.endif();
451//         m_storage->setCurrentBlock(currentBlock(), false);
452
453         builder.CreateStore(my, maPtr);
454      }
455      condBranch.elseop(); // !(my > mx && my > mz)
456//      m_storage->setCurrentBlock(currentBlock(), false);
457      {
458         //ifCond(builder.CreateFCmpOGE(texcoords[2], float0, name("zPositive")));
459         condBranch.ifCond(FPositive(builder, texcoords[2]));
460//         m_storage->setCurrentBlock(currentBlock(), false);
461         {
462            builder.CreateStore((texcoords[0]), sPtr);
463            builder.CreateStore(builder.CreateFNeg(texcoords[1]), tPtr);
464            builder.CreateStore(builder.getInt32(4), facePtr);
465         }
466         condBranch.elseop();
467//        m_storage->setCurrentBlock(currentBlock(), false);
468         {
469            builder.CreateStore(builder.CreateFNeg(texcoords[0]), sPtr);
470            builder.CreateStore(builder.CreateFNeg(texcoords[1]), tPtr);
471            builder.CreateStore(builder.getInt32(5), facePtr);
472         }
473         condBranch.endif(); // end if (x >= 0)
474//         m_storage->setCurrentBlock(currentBlock(), false);
475
476         builder.CreateStore(mz, maPtr);
477      }
478      condBranch.endif();
479//      m_storage->setCurrentBlock(currentBlock(), false);
480   }
481   condBranch.endif();
482//   m_storage->setCurrentBlock(currentBlock(), false);
483
484
485   Value * s = builder.CreateLoad(sPtr);
486   Value * t = builder.CreateLoad(tPtr);
487   Value * ma = builder.CreateLoad(maPtr);
488   Value * face = builder.CreateLoad(facePtr);
489
490   s = builder.CreateFDiv(s, ma);
491   s = builder.CreateFAdd(s, float1);
492   s = builder.CreateFMul(s, float0_5);
493
494   t = builder.CreateFDiv(t, ma);
495   t = builder.CreateFAdd(t, float1);
496   t = builder.CreateFMul(t, float0_5);
497
498//   ChannelType sType = Float, tType = Float;
499   Value * xLerp = NULL, * yLerp = NULL;
500   Value * x = texcoordWrap(builder, gglCtx->textureState.textures[sampler].wrapS,
501                            /*sType, */s, textureWidth, textureW, &xLerp);
502   Value * y = texcoordWrap(builder, gglCtx->textureState.textures[sampler].wrapT,
503                            /*tType, */t, textureHeight, textureH, &yLerp);
504   Value * indexOffset = builder.CreateMul(builder.CreateMul(textureHeight, textureWidth), face);
505   Value * index = builder.CreateAdd(builder.CreateMul(y, textureWidth), x);
506
507   Value * textureData = module->getGlobalVariable(_PF2_TEXTURE_DATA_NAME_);
508   if (!textureData)
509      textureData = new GlobalVariable(*module, intPointerType,
510                                       true, GlobalValue::ExternalLinkage,
511                                       NULL, _PF2_TEXTURE_DATA_NAME_);
512
513   textureData = builder.CreateConstInBoundsGEP1_32(textureData, sampler);
514   textureData = builder.CreateLoad(textureData);
515
516   if (0 == gglCtx->textureState.textures[sampler].minFilter &&
517         0 == gglCtx->textureState.textures[sampler].magFilter) { // GL_NEAREST
518      textureData = pointSample(builder, textureData, builder.CreateAdd(indexOffset, index),
519                                gglCtx->textureState.textures[sampler].format/*, dstDesc*/);
520      return intColorVecToFloatColorVec(builder, textureData);
521
522   } else if (1 == gglCtx->textureState.textures[sampler].minFilter &&
523              1 == gglCtx->textureState.textures[sampler].magFilter) { // GL_LINEAR
524      textureData = linearSample(builder, textureData, indexOffset, x, y, xLerp, yLerp,
525                                 textureW, textureH,  textureWidth, textureHeight,
526                                 gglCtx->textureState.textures[sampler].format/*, dstDesc*/);
527      return intColorVecToFloatColorVec(builder, textureData);
528   } else
529      assert(!"unsupported texture filter");
530   return NULL;
531}
532