• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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));
PixelRGBAToVector4(const Pixel * pixel,Vector4 * color)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 
RGBAToVector4(const unsigned int rgba,Vector4 * color)57 static inline void RGBAToVector4(const unsigned int rgba, Vector4 * color)
58 {
59 	PixelRGBAToVector4((const Pixel *)&rgba, color);
60 }
61 
Lerp(Vec4<int> * a,Vec4<int> * b,int x,Vec4<int> * d)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 
ToIntVec(Vec4<int> * a)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>
PointSample(unsigned sample[4],const unsigned * data,const unsigned index)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 
texcoordWrap(const unsigned wrap,float r,const unsigned size,unsigned * lerp)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>
tex2d(unsigned sample[4],const float tex_coord[4],const unsigned sampler)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>
texcube(unsigned sample[4],const float tex_coord[4],const unsigned sampler)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 
DeclareTextureFunctions(llvm::Module * mod)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 
AddTextureFunctionMappings(llvm::Module * mod,llvm::ExecutionEngine * ee)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 
SetSampler(GGLInterface * iface,const unsigned sampler,GGLTexture * texture)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 
InitializeTextureFunctions(GGLInterface * iface)423 void InitializeTextureFunctions(GGLInterface * iface)
424 {
425     iface->SetSampler = SetSampler;
426 }