• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 
29 #include "pipe/p_defines.h"
30 
31 #include "util/u_format.h"
32 #include "util/u_memory.h"
33 #include "util/u_string.h"
34 
35 #include "lp_bld_type.h"
36 #include "lp_bld_const.h"
37 #include "lp_bld_conv.h"
38 #include "lp_bld_swizzle.h"
39 #include "lp_bld_gather.h"
40 #include "lp_bld_debug.h"
41 #include "lp_bld_format.h"
42 
43 
44 void
lp_build_format_swizzle_soa(const struct util_format_description * format_desc,struct lp_build_context * bld,const LLVMValueRef * unswizzled,LLVMValueRef swizzled_out[4])45 lp_build_format_swizzle_soa(const struct util_format_description *format_desc,
46                             struct lp_build_context *bld,
47                             const LLVMValueRef *unswizzled,
48                             LLVMValueRef swizzled_out[4])
49 {
50    assert(UTIL_FORMAT_SWIZZLE_0 == PIPE_SWIZZLE_ZERO);
51    assert(UTIL_FORMAT_SWIZZLE_1 == PIPE_SWIZZLE_ONE);
52 
53    if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
54       /*
55        * Return zzz1 for depth-stencil formats.
56        *
57        * XXX: Allow to control the depth swizzle with an additional parameter,
58        * as the caller may wish another depth swizzle, or retain the stencil
59        * value.
60        */
61       enum util_format_swizzle swizzle = format_desc->swizzle[0];
62       LLVMValueRef depth = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle);
63       swizzled_out[2] = swizzled_out[1] = swizzled_out[0] = depth;
64       swizzled_out[3] = bld->one;
65    }
66    else {
67       unsigned chan;
68       for (chan = 0; chan < 4; ++chan) {
69          enum util_format_swizzle swizzle = format_desc->swizzle[chan];
70          swizzled_out[chan] = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle);
71       }
72    }
73 }
74 
75 
76 /**
77  * Unpack several pixels in SoA.
78  *
79  * It takes a vector of packed pixels:
80  *
81  *   packed = {P0, P1, P2, P3, ..., Pn}
82  *
83  * And will produce four vectors:
84  *
85  *   red    = {R0, R1, R2, R3, ..., Rn}
86  *   green  = {G0, G1, G2, G3, ..., Gn}
87  *   blue   = {B0, B1, B2, B3, ..., Bn}
88  *   alpha  = {A0, A1, A2, A3, ..., An}
89  *
90  * It requires that a packed pixel fits into an element of the output
91  * channels. The common case is when converting pixel with a depth of 32 bit or
92  * less into floats.
93  *
94  * \param format_desc  the format of the 'packed' incoming pixel vector
95  * \param type  the desired type for rgba_out (type.length = n, above)
96  * \param packed  the incoming vector of packed pixels
97  * \param rgba_out  returns the SoA R,G,B,A vectors
98  */
99 void
lp_build_unpack_rgba_soa(struct gallivm_state * gallivm,const struct util_format_description * format_desc,struct lp_type type,LLVMValueRef packed,LLVMValueRef rgba_out[4])100 lp_build_unpack_rgba_soa(struct gallivm_state *gallivm,
101                          const struct util_format_description *format_desc,
102                          struct lp_type type,
103                          LLVMValueRef packed,
104                          LLVMValueRef rgba_out[4])
105 {
106    LLVMBuilderRef builder = gallivm->builder;
107    struct lp_build_context bld;
108    LLVMValueRef inputs[4];
109    unsigned start;
110    unsigned chan;
111 
112    assert(format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN);
113    assert(format_desc->block.width == 1);
114    assert(format_desc->block.height == 1);
115    assert(format_desc->block.bits <= type.width);
116    /* FIXME: Support more output types */
117    assert(type.floating);
118    assert(type.width == 32);
119 
120    lp_build_context_init(&bld, gallivm, type);
121 
122    /* Decode the input vector components */
123    start = 0;
124    for (chan = 0; chan < format_desc->nr_channels; ++chan) {
125       const unsigned width = format_desc->channel[chan].size;
126       const unsigned stop = start + width;
127       LLVMValueRef input;
128 
129       input = packed;
130 
131       switch(format_desc->channel[chan].type) {
132       case UTIL_FORMAT_TYPE_VOID:
133          input = lp_build_undef(gallivm, type);
134          break;
135 
136       case UTIL_FORMAT_TYPE_UNSIGNED:
137          /*
138           * Align the LSB
139           */
140 
141          if (start) {
142             input = LLVMBuildLShr(builder, input, lp_build_const_int_vec(gallivm, type, start), "");
143          }
144 
145          /*
146           * Zero the MSBs
147           */
148 
149          if (stop < format_desc->block.bits) {
150             unsigned mask = ((unsigned long long)1 << width) - 1;
151             input = LLVMBuildAnd(builder, input, lp_build_const_int_vec(gallivm, type, mask), "");
152          }
153 
154          /*
155           * Type conversion
156           */
157 
158          if (type.floating) {
159             if(format_desc->channel[chan].normalized)
160                input = lp_build_unsigned_norm_to_float(gallivm, width, type, input);
161             else
162                input = LLVMBuildSIToFP(builder, input,
163                                        lp_build_vec_type(gallivm, type), "");
164          }
165          else {
166             /* FIXME */
167             assert(0);
168             input = lp_build_undef(gallivm, type);
169          }
170 
171          break;
172 
173       case UTIL_FORMAT_TYPE_SIGNED:
174          /*
175           * Align the sign bit first.
176           */
177 
178          if (stop < type.width) {
179             unsigned bits = type.width - stop;
180             LLVMValueRef bits_val = lp_build_const_int_vec(gallivm, type, bits);
181             input = LLVMBuildShl(builder, input, bits_val, "");
182          }
183 
184          /*
185           * Align the LSB (with an arithmetic shift to preserve the sign)
186           */
187 
188          if (format_desc->channel[chan].size < type.width) {
189             unsigned bits = type.width - format_desc->channel[chan].size;
190             LLVMValueRef bits_val = lp_build_const_int_vec(gallivm, type, bits);
191             input = LLVMBuildAShr(builder, input, bits_val, "");
192          }
193 
194          /*
195           * Type conversion
196           */
197 
198          if (type.floating) {
199             input = LLVMBuildSIToFP(builder, input, lp_build_vec_type(gallivm, type), "");
200             if (format_desc->channel[chan].normalized) {
201                double scale = 1.0 / ((1 << (format_desc->channel[chan].size - 1)) - 1);
202                LLVMValueRef scale_val = lp_build_const_vec(gallivm, type, scale);
203                input = LLVMBuildFMul(builder, input, scale_val, "");
204             }
205          }
206          else {
207             /* FIXME */
208             assert(0);
209             input = lp_build_undef(gallivm, type);
210          }
211 
212          break;
213 
214       case UTIL_FORMAT_TYPE_FLOAT:
215          if (type.floating) {
216             assert(start == 0);
217             assert(stop == 32);
218             assert(type.width == 32);
219             input = LLVMBuildBitCast(builder, input, lp_build_vec_type(gallivm, type), "");
220          }
221          else {
222             /* FIXME */
223             assert(0);
224             input = lp_build_undef(gallivm, type);
225          }
226          break;
227 
228       case UTIL_FORMAT_TYPE_FIXED:
229          if (type.floating) {
230             double scale = 1.0 / ((1 << (format_desc->channel[chan].size/2)) - 1);
231             LLVMValueRef scale_val = lp_build_const_vec(gallivm, type, scale);
232             input = LLVMBuildSIToFP(builder, input, lp_build_vec_type(gallivm, type), "");
233             input = LLVMBuildFMul(builder, input, scale_val, "");
234          }
235          else {
236             /* FIXME */
237             assert(0);
238             input = lp_build_undef(gallivm, type);
239          }
240          break;
241 
242       default:
243          assert(0);
244          input = lp_build_undef(gallivm, type);
245          break;
246       }
247 
248       inputs[chan] = input;
249 
250       start = stop;
251    }
252 
253    lp_build_format_swizzle_soa(format_desc, &bld, inputs, rgba_out);
254 }
255 
256 
257 void
lp_build_rgba8_to_f32_soa(struct gallivm_state * gallivm,struct lp_type dst_type,LLVMValueRef packed,LLVMValueRef * rgba)258 lp_build_rgba8_to_f32_soa(struct gallivm_state *gallivm,
259                           struct lp_type dst_type,
260                           LLVMValueRef packed,
261                           LLVMValueRef *rgba)
262 {
263    LLVMBuilderRef builder = gallivm->builder;
264    LLVMValueRef mask = lp_build_const_int_vec(gallivm, dst_type, 0xff);
265    unsigned chan;
266 
267    packed = LLVMBuildBitCast(builder, packed,
268                              lp_build_int_vec_type(gallivm, dst_type), "");
269 
270    /* Decode the input vector components */
271    for (chan = 0; chan < 4; ++chan) {
272       unsigned start = chan*8;
273       unsigned stop = start + 8;
274       LLVMValueRef input;
275 
276       input = packed;
277 
278       if (start)
279          input = LLVMBuildLShr(builder, input,
280                                lp_build_const_int_vec(gallivm, dst_type, start), "");
281 
282       if (stop < 32)
283          input = LLVMBuildAnd(builder, input, mask, "");
284 
285       input = lp_build_unsigned_norm_to_float(gallivm, 8, dst_type, input);
286 
287       rgba[chan] = input;
288    }
289 }
290 
291 
292 
293 /**
294  * Fetch a texels from a texture, returning them in SoA layout.
295  *
296  * \param type  the desired return type for 'rgba'.  The vector length
297  *              is the number of texels to fetch
298  *
299  * \param base_ptr  points to start of the texture image block.  For non-
300  *                  compressed formats, this simply points to the texel.
301  *                  For compressed formats, it points to the start of the
302  *                  compressed data block.
303  *
304  * \param i, j  the sub-block pixel coordinates.  For non-compressed formats
305  *              these will always be (0,0).  For compressed formats, i will
306  *              be in [0, block_width-1] and j will be in [0, block_height-1].
307  */
308 void
lp_build_fetch_rgba_soa(struct gallivm_state * gallivm,const struct util_format_description * format_desc,struct lp_type type,LLVMValueRef base_ptr,LLVMValueRef offset,LLVMValueRef i,LLVMValueRef j,LLVMValueRef rgba_out[4])309 lp_build_fetch_rgba_soa(struct gallivm_state *gallivm,
310                         const struct util_format_description *format_desc,
311                         struct lp_type type,
312                         LLVMValueRef base_ptr,
313                         LLVMValueRef offset,
314                         LLVMValueRef i,
315                         LLVMValueRef j,
316                         LLVMValueRef rgba_out[4])
317 {
318    LLVMBuilderRef builder = gallivm->builder;
319 
320    if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
321        (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
322         format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) &&
323        format_desc->block.width == 1 &&
324        format_desc->block.height == 1 &&
325        format_desc->block.bits <= type.width &&
326        (format_desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT ||
327         format_desc->channel[0].size == 32))
328    {
329       /*
330        * The packed pixel fits into an element of the destination format. Put
331        * the packed pixels into a vector and extract each component for all
332        * vector elements in parallel.
333        */
334 
335       LLVMValueRef packed;
336 
337       /*
338        * gather the texels from the texture
339        * Ex: packed = {BGRA, BGRA, BGRA, BGRA}.
340        */
341       packed = lp_build_gather(gallivm,
342                                type.length,
343                                format_desc->block.bits,
344                                type.width,
345                                base_ptr, offset);
346 
347       /*
348        * convert texels to float rgba
349        */
350       lp_build_unpack_rgba_soa(gallivm,
351                                format_desc,
352                                type,
353                                packed, rgba_out);
354       return;
355    }
356 
357    /*
358     * Try calling lp_build_fetch_rgba_aos for all pixels.
359     */
360 
361    if (util_format_fits_8unorm(format_desc) &&
362        type.floating && type.width == 32 &&
363        (type.length == 1 || (type.length % 4 == 0))) {
364       struct lp_type tmp_type;
365       LLVMValueRef tmp;
366 
367       memset(&tmp_type, 0, sizeof tmp_type);
368       tmp_type.width = 8;
369       tmp_type.length = type.length * 4;
370       tmp_type.norm = TRUE;
371 
372       tmp = lp_build_fetch_rgba_aos(gallivm, format_desc, tmp_type,
373                                     base_ptr, offset, i, j);
374 
375       lp_build_rgba8_to_f32_soa(gallivm,
376                                 type,
377                                 tmp,
378                                 rgba_out);
379 
380       return;
381    }
382 
383    /*
384     * Fallback to calling lp_build_fetch_rgba_aos for each pixel.
385     *
386     * This is not the most efficient way of fetching pixels, as we
387     * miss some opportunities to do vectorization, but this is
388     * convenient for formats or scenarios for which there was no
389     * opportunity or incentive to optimize.
390     */
391 
392    {
393       unsigned k, chan;
394       struct lp_type tmp_type;
395 
396       if (gallivm_debug & GALLIVM_DEBUG_PERF) {
397          debug_printf("%s: scalar unpacking of %s\n",
398                       __FUNCTION__, format_desc->short_name);
399       }
400 
401       tmp_type = type;
402       tmp_type.length = 4;
403 
404       for (chan = 0; chan < 4; ++chan) {
405          rgba_out[chan] = lp_build_undef(gallivm, type);
406       }
407 
408       /* loop over number of pixels */
409       for(k = 0; k < type.length; ++k) {
410          LLVMValueRef index = lp_build_const_int32(gallivm, k);
411          LLVMValueRef offset_elem;
412          LLVMValueRef i_elem, j_elem;
413          LLVMValueRef tmp;
414 
415          offset_elem = LLVMBuildExtractElement(builder, offset,
416                                                index, "");
417 
418          i_elem = LLVMBuildExtractElement(builder, i, index, "");
419          j_elem = LLVMBuildExtractElement(builder, j, index, "");
420 
421          /* Get a single float[4]={R,G,B,A} pixel */
422          tmp = lp_build_fetch_rgba_aos(gallivm, format_desc, tmp_type,
423                                        base_ptr, offset_elem,
424                                        i_elem, j_elem);
425 
426          /*
427           * Insert the AoS tmp value channels into the SoA result vectors at
428           * position = 'index'.
429           */
430          for (chan = 0; chan < 4; ++chan) {
431             LLVMValueRef chan_val = lp_build_const_int32(gallivm, chan),
432             tmp_chan = LLVMBuildExtractElement(builder, tmp, chan_val, "");
433             rgba_out[chan] = LLVMBuildInsertElement(builder, rgba_out[chan],
434                                                     tmp_chan, index, "");
435          }
436       }
437    }
438 }
439