lp_bld_format_soa.c revision 92b1908db89f23ee05f8d0da5307529440bc7560
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_sample.h" /* for lp_build_gather */
40#include "lp_bld_format.h"
41
42
43void
44lp_build_format_swizzle_soa(const struct util_format_description *format_desc,
45                            struct lp_build_context *bld,
46                            const LLVMValueRef *unswizzled,
47                            LLVMValueRef swizzled_out[4])
48{
49   assert(UTIL_FORMAT_SWIZZLE_0 == PIPE_SWIZZLE_ZERO);
50   assert(UTIL_FORMAT_SWIZZLE_1 == PIPE_SWIZZLE_ONE);
51
52   if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
53      /*
54       * Return zzz1 for depth-stencil formats.
55       *
56       * XXX: Allow to control the depth swizzle with an additional parameter,
57       * as the caller may wish another depth swizzle, or retain the stencil
58       * value.
59       */
60      enum util_format_swizzle swizzle = format_desc->swizzle[0];
61      LLVMValueRef depth = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle);
62      swizzled_out[2] = swizzled_out[1] = swizzled_out[0] = depth;
63      swizzled_out[3] = bld->one;
64   }
65   else {
66      unsigned chan;
67      for (chan = 0; chan < 4; ++chan) {
68         enum util_format_swizzle swizzle = format_desc->swizzle[chan];
69         swizzled_out[chan] = lp_build_swizzle_soa_channel(bld, unswizzled, swizzle);
70      }
71   }
72}
73
74
75/**
76 * Unpack several pixels in SoA.
77 *
78 * It takes a vector of packed pixels:
79 *
80 *   packed = {P0, P1, P2, P3, ..., Pn}
81 *
82 * And will produce four vectors:
83 *
84 *   red    = {R0, R1, R2, R3, ..., Rn}
85 *   green  = {G0, G1, G2, G3, ..., Gn}
86 *   blue   = {B0, B1, B2, B3, ..., Bn}
87 *   alpha  = {A0, A1, A2, A3, ..., An}
88 *
89 * It requires that a packed pixel fits into an element of the output
90 * channels. The common case is when converting pixel with a depth of 32 bit or
91 * less into floats.
92 */
93void
94lp_build_unpack_rgba_soa(LLVMBuilderRef builder,
95                         const struct util_format_description *format_desc,
96                         struct lp_type type,
97                         LLVMValueRef packed,
98                         LLVMValueRef rgba_out[4])
99{
100   struct lp_build_context bld;
101   LLVMValueRef inputs[4];
102   unsigned start;
103   unsigned chan;
104
105   assert(format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN);
106   assert(format_desc->block.width == 1);
107   assert(format_desc->block.height == 1);
108   assert(format_desc->block.bits <= type.width);
109   /* FIXME: Support more output types */
110   assert(type.floating);
111   assert(type.width == 32);
112
113   lp_build_context_init(&bld, builder, type);
114
115   /* Decode the input vector components */
116   start = 0;
117   for (chan = 0; chan < format_desc->nr_channels; ++chan) {
118      unsigned width = format_desc->channel[chan].size;
119      unsigned stop = start + width;
120      LLVMValueRef input;
121
122      input = packed;
123
124      switch(format_desc->channel[chan].type) {
125      case UTIL_FORMAT_TYPE_VOID:
126         input = lp_build_undef(type);
127         break;
128
129      case UTIL_FORMAT_TYPE_UNSIGNED:
130         /*
131          * Align the LSB
132          */
133
134         if (start) {
135            input = LLVMBuildLShr(builder, input, lp_build_const_int_vec(type, start), "");
136         }
137
138         /*
139          * Zero the MSBs
140          */
141
142         if (stop < format_desc->block.bits) {
143            unsigned mask = ((unsigned long long)1 << width) - 1;
144            input = LLVMBuildAnd(builder, input, lp_build_const_int_vec(type, mask), "");
145         }
146
147         /*
148          * Type conversion
149          */
150
151         if (type.floating) {
152            if(format_desc->channel[chan].normalized)
153               input = lp_build_unsigned_norm_to_float(builder, width, type, input);
154            else
155               input = LLVMBuildSIToFP(builder, input, lp_build_vec_type(type), "");
156         }
157         else {
158            /* FIXME */
159            assert(0);
160            input = lp_build_undef(type);
161         }
162
163         break;
164
165      case UTIL_FORMAT_TYPE_SIGNED:
166         /*
167          * Align the sign bit first.
168          */
169
170         if (stop < type.width) {
171            unsigned bits = type.width - stop;
172            LLVMValueRef bits_val = lp_build_const_int_vec(type, bits);
173            input = LLVMBuildShl(builder, input, bits_val, "");
174         }
175
176         /*
177          * Align the LSB (with an arithmetic shift to preserve the sign)
178          */
179
180         if (format_desc->channel[chan].size < type.width) {
181            unsigned bits = type.width - format_desc->channel[chan].size;
182            LLVMValueRef bits_val = lp_build_const_int_vec(type, bits);
183            input = LLVMBuildAShr(builder, input, bits_val, "");
184         }
185
186         /*
187          * Type conversion
188          */
189
190         if (type.floating) {
191            input = LLVMBuildSIToFP(builder, input, lp_build_vec_type(type), "");
192            if (format_desc->channel[chan].normalized) {
193               double scale = 1.0 / ((1 << (format_desc->channel[chan].size - 1)) - 1);
194               LLVMValueRef scale_val = lp_build_const_vec(type, scale);
195               input = LLVMBuildMul(builder, input, scale_val, "");
196            }
197         }
198         else {
199            /* FIXME */
200            assert(0);
201            input = lp_build_undef(type);
202         }
203
204         break;
205
206      case UTIL_FORMAT_TYPE_FLOAT:
207         if (type.floating) {
208            assert(start == 0);
209            assert(stop == 32);
210            assert(type.width == 32);
211            input = LLVMBuildBitCast(builder, input, lp_build_vec_type(type), "");
212         }
213         else {
214            /* FIXME */
215            assert(0);
216            input = lp_build_undef(type);
217         }
218         break;
219
220      case UTIL_FORMAT_TYPE_FIXED:
221         if (type.floating) {
222            double scale = 1.0 / ((1 << (format_desc->channel[chan].size/2)) - 1);
223            LLVMValueRef scale_val = lp_build_const_vec(type, scale);
224            input = LLVMBuildSIToFP(builder, input, lp_build_vec_type(type), "");
225            input = LLVMBuildMul(builder, input, scale_val, "");
226         }
227         else {
228            /* FIXME */
229            assert(0);
230            input = lp_build_undef(type);
231         }
232         break;
233
234      default:
235         assert(0);
236         input = lp_build_undef(type);
237         break;
238      }
239
240      inputs[chan] = input;
241
242      start = stop;
243   }
244
245   lp_build_format_swizzle_soa(format_desc, &bld, inputs, rgba_out);
246}
247
248
249/**
250 * Fetch a pixel into a SoA.
251 *
252 * \param type  the desired return type for 'rgba'
253 *
254 * \param base_ptr  points to start of the texture image block.  For non-
255 *                  compressed formats, this simply points to the texel.
256 *                  For compressed formats, it points to the start of the
257 *                  compressed data block.
258 *
259 * \param i, j  the sub-block pixel coordinates.  For non-compressed formats
260 *              these will always be (0,0).  For compressed formats, i will
261 *              be in [0, block_width-1] and j will be in [0, block_height-1].
262 */
263void
264lp_build_fetch_rgba_soa(LLVMBuilderRef builder,
265                        const struct util_format_description *format_desc,
266                        struct lp_type type,
267                        LLVMValueRef base_ptr,
268                        LLVMValueRef offset,
269                        LLVMValueRef i,
270                        LLVMValueRef j,
271                        LLVMValueRef rgba_out[4])
272{
273
274   if (format_desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
275       (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
276        format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) &&
277       format_desc->block.width == 1 &&
278       format_desc->block.height == 1 &&
279       format_desc->block.bits <= type.width &&
280       (format_desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT ||
281        format_desc->channel[0].size == 32))
282   {
283      /*
284       * The packed pixel fits into an element of the destination format. Put
285       * the packed pixels into a vector and extract each component for all
286       * vector elements in parallel.
287       */
288
289      LLVMValueRef packed;
290
291      /*
292       * gather the texels from the texture
293       */
294      packed = lp_build_gather(builder,
295                               type.length,
296                               format_desc->block.bits,
297                               type.width,
298                               base_ptr, offset);
299
300      /*
301       * convert texels to float rgba
302       */
303      lp_build_unpack_rgba_soa(builder,
304                               format_desc,
305                               type,
306                               packed, rgba_out);
307   }
308   else {
309      /*
310       * Fallback to calling lp_build_fetch_rgba_aos for each pixel.
311       *
312       * This is not the most efficient way of fetching pixels, as we
313       * miss some opportunities to do vectorization, but this is
314       * convenient for formats or scenarios for which there was no
315       * opportunity or incentive to optimize.
316       */
317
318      unsigned k, chan;
319
320      assert(type.floating);
321
322      for (chan = 0; chan < 4; ++chan) {
323         rgba_out[chan] = lp_build_undef(type);
324      }
325
326      /* loop over number of pixels */
327      for(k = 0; k < type.length; ++k) {
328         LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), k, 0);
329         LLVMValueRef offset_elem;
330         LLVMValueRef ptr;
331         LLVMValueRef i_elem, j_elem;
332         LLVMValueRef tmp;
333
334         offset_elem = LLVMBuildExtractElement(builder, offset, index, "");
335         ptr = LLVMBuildGEP(builder, base_ptr, &offset_elem, 1, "");
336
337         i_elem = LLVMBuildExtractElement(builder, i, index, "");
338         j_elem = LLVMBuildExtractElement(builder, j, index, "");
339
340         /* Get a single float[4]={R,G,B,A} pixel */
341         tmp = lp_build_fetch_rgba_aos(builder, format_desc, ptr,
342                                       i_elem, j_elem);
343
344         /*
345          * Insert the AoS tmp value channels into the SoA result vectors at
346          * position = 'index'.
347          */
348         for (chan = 0; chan < 4; ++chan) {
349            LLVMValueRef chan_val = LLVMConstInt(LLVMInt32Type(), chan, 0),
350            tmp_chan = LLVMBuildExtractElement(builder, tmp, chan_val, "");
351            rgba_out[chan] = LLVMBuildInsertElement(builder, rgba_out[chan],
352                                                    tmp_chan, index, "");
353         }
354      }
355   }
356}
357