• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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   * Authors:
30   *   Keith Whitwell <keith@tungstengraphics.com>
31   */
32 
33 #include "util/u_memory.h"
34 #include "util/u_format.h"
35 #include "util/u_half.h"
36 #include "util/u_math.h"
37 #include "pipe/p_state.h"
38 #include "translate.h"
39 
40 
41 #define DRAW_DBG 0
42 
43 typedef void (*fetch_func)(void *dst,
44                            const uint8_t *src,
45                            unsigned i, unsigned j);
46 typedef void (*emit_func)(const void *attrib, void *ptr);
47 
48 
49 
50 struct translate_generic {
51    struct translate translate;
52 
53    struct {
54       enum translate_element_type type;
55 
56       fetch_func fetch;
57       unsigned buffer;
58       unsigned input_offset;
59       unsigned instance_divisor;
60 
61       emit_func emit;
62       unsigned output_offset;
63 
64       const uint8_t *input_ptr;
65       unsigned input_stride;
66       unsigned max_index;
67 
68       /* this value is set to -1 if this is a normal element with output_format != input_format:
69        * in this case, u_format is used to do a full conversion
70        *
71        * this value is set to the format size in bytes if output_format == input_format or for 32-bit instance ids:
72        * in this case, memcpy is used to copy this amount of bytes
73        */
74       int copy_size;
75 
76    } attrib[PIPE_MAX_ATTRIBS];
77 
78    unsigned nr_attrib;
79 };
80 
81 
translate_generic(struct translate * translate)82 static struct translate_generic *translate_generic( struct translate *translate )
83 {
84    return (struct translate_generic *)translate;
85 }
86 
87 /**
88  * Fetch a dword[4] vertex attribute from memory, doing format/type
89  * conversion as needed.
90  *
91  * This is probably needed/dupliocated elsewhere, eg format
92  * conversion, texture sampling etc.
93  */
94 #define ATTRIB( NAME, SZ, SRCTYPE, DSTTYPE, TO )        \
95 static void						\
96 emit_##NAME(const void *attrib, void *ptr)		\
97 {  \
98    unsigned i;						\
99    SRCTYPE *in = (SRCTYPE *)attrib;                     \
100    DSTTYPE *out = (DSTTYPE *)ptr;			\
101 							\
102    for (i = 0; i < SZ; i++) {				\
103       out[i] = TO(in[i]);				\
104    }							\
105 }
106 
107 
108 #define TO_64_FLOAT(x)   ((double) x)
109 #define TO_32_FLOAT(x)   (x)
110 #define TO_16_FLOAT(x)   util_float_to_half(x)
111 
112 #define TO_8_USCALED(x)  ((unsigned char) x)
113 #define TO_16_USCALED(x) ((unsigned short) x)
114 #define TO_32_USCALED(x) ((unsigned int) x)
115 
116 #define TO_8_SSCALED(x)  ((char) x)
117 #define TO_16_SSCALED(x) ((short) x)
118 #define TO_32_SSCALED(x) ((int) x)
119 
120 #define TO_8_UNORM(x)    ((unsigned char) (x * 255.0f))
121 #define TO_16_UNORM(x)   ((unsigned short) (x * 65535.0f))
122 #define TO_32_UNORM(x)   ((unsigned int) (x * 4294967295.0f))
123 
124 #define TO_8_SNORM(x)    ((char) (x * 127.0f))
125 #define TO_16_SNORM(x)   ((short) (x * 32767.0f))
126 #define TO_32_SNORM(x)   ((int) (x * 2147483647.0f))
127 
128 #define TO_32_FIXED(x)   ((int) (x * 65536.0f))
129 
130 #define TO_INT(x)        (x)
131 
132 
133 ATTRIB( R64G64B64A64_FLOAT,   4, float, double, TO_64_FLOAT )
134 ATTRIB( R64G64B64_FLOAT,      3, float, double, TO_64_FLOAT )
135 ATTRIB( R64G64_FLOAT,         2, float, double, TO_64_FLOAT )
136 ATTRIB( R64_FLOAT,            1, float, double, TO_64_FLOAT )
137 
138 ATTRIB( R32G32B32A32_FLOAT,   4, float, float, TO_32_FLOAT )
139 ATTRIB( R32G32B32_FLOAT,      3, float, float, TO_32_FLOAT )
140 ATTRIB( R32G32_FLOAT,         2, float, float, TO_32_FLOAT )
141 ATTRIB( R32_FLOAT,            1, float, float, TO_32_FLOAT )
142 
143 ATTRIB( R16G16B16A16_FLOAT,   4, float, ushort, TO_16_FLOAT )
144 ATTRIB( R16G16B16_FLOAT,      3, float, ushort, TO_16_FLOAT )
145 ATTRIB( R16G16_FLOAT,         2, float, ushort, TO_16_FLOAT )
146 ATTRIB( R16_FLOAT,            1, float, ushort, TO_16_FLOAT )
147 
148 ATTRIB( R32G32B32A32_USCALED, 4, float, unsigned, TO_32_USCALED )
149 ATTRIB( R32G32B32_USCALED,    3, float, unsigned, TO_32_USCALED )
150 ATTRIB( R32G32_USCALED,       2, float, unsigned, TO_32_USCALED )
151 ATTRIB( R32_USCALED,          1, float, unsigned, TO_32_USCALED )
152 
153 ATTRIB( R32G32B32A32_SSCALED, 4, float, int, TO_32_SSCALED )
154 ATTRIB( R32G32B32_SSCALED,    3, float, int, TO_32_SSCALED )
155 ATTRIB( R32G32_SSCALED,       2, float, int, TO_32_SSCALED )
156 ATTRIB( R32_SSCALED,          1, float, int, TO_32_SSCALED )
157 
158 ATTRIB( R32G32B32A32_UNORM, 4, float, unsigned, TO_32_UNORM )
159 ATTRIB( R32G32B32_UNORM,    3, float, unsigned, TO_32_UNORM )
160 ATTRIB( R32G32_UNORM,       2, float, unsigned, TO_32_UNORM )
161 ATTRIB( R32_UNORM,          1, float, unsigned, TO_32_UNORM )
162 
163 ATTRIB( R32G32B32A32_SNORM, 4, float, int, TO_32_SNORM )
164 ATTRIB( R32G32B32_SNORM,    3, float, int, TO_32_SNORM )
165 ATTRIB( R32G32_SNORM,       2, float, int, TO_32_SNORM )
166 ATTRIB( R32_SNORM,          1, float, int, TO_32_SNORM )
167 
168 ATTRIB( R16G16B16A16_USCALED, 4, float, ushort, TO_16_USCALED )
169 ATTRIB( R16G16B16_USCALED,    3, float, ushort, TO_16_USCALED )
170 ATTRIB( R16G16_USCALED,       2, float, ushort, TO_16_USCALED )
171 ATTRIB( R16_USCALED,          1, float, ushort, TO_16_USCALED )
172 
173 ATTRIB( R16G16B16A16_SSCALED, 4, float, short, TO_16_SSCALED )
174 ATTRIB( R16G16B16_SSCALED,    3, float, short, TO_16_SSCALED )
175 ATTRIB( R16G16_SSCALED,       2, float, short, TO_16_SSCALED )
176 ATTRIB( R16_SSCALED,          1, float, short, TO_16_SSCALED )
177 
178 ATTRIB( R16G16B16A16_UNORM, 4, float, ushort, TO_16_UNORM )
179 ATTRIB( R16G16B16_UNORM,    3, float, ushort, TO_16_UNORM )
180 ATTRIB( R16G16_UNORM,       2, float, ushort, TO_16_UNORM )
181 ATTRIB( R16_UNORM,          1, float, ushort, TO_16_UNORM )
182 
183 ATTRIB( R16G16B16A16_SNORM, 4, float, short, TO_16_SNORM )
184 ATTRIB( R16G16B16_SNORM,    3, float, short, TO_16_SNORM )
185 ATTRIB( R16G16_SNORM,       2, float, short, TO_16_SNORM )
186 ATTRIB( R16_SNORM,          1, float, short, TO_16_SNORM )
187 
188 ATTRIB( R8G8B8A8_USCALED,   4, float, ubyte, TO_8_USCALED )
189 ATTRIB( R8G8B8_USCALED,     3, float, ubyte, TO_8_USCALED )
190 ATTRIB( R8G8_USCALED,       2, float, ubyte, TO_8_USCALED )
191 ATTRIB( R8_USCALED,         1, float, ubyte, TO_8_USCALED )
192 
193 ATTRIB( R8G8B8A8_SSCALED,  4, float, char, TO_8_SSCALED )
194 ATTRIB( R8G8B8_SSCALED,    3, float, char, TO_8_SSCALED )
195 ATTRIB( R8G8_SSCALED,      2, float, char, TO_8_SSCALED )
196 ATTRIB( R8_SSCALED,        1, float, char, TO_8_SSCALED )
197 
198 ATTRIB( R8G8B8A8_UNORM,  4, float, ubyte, TO_8_UNORM )
199 ATTRIB( R8G8B8_UNORM,    3, float, ubyte, TO_8_UNORM )
200 ATTRIB( R8G8_UNORM,      2, float, ubyte, TO_8_UNORM )
201 ATTRIB( R8_UNORM,        1, float, ubyte, TO_8_UNORM )
202 
203 ATTRIB( R8G8B8A8_SNORM,  4, float, char, TO_8_SNORM )
204 ATTRIB( R8G8B8_SNORM,    3, float, char, TO_8_SNORM )
205 ATTRIB( R8G8_SNORM,      2, float, char, TO_8_SNORM )
206 ATTRIB( R8_SNORM,        1, float, char, TO_8_SNORM )
207 
208 ATTRIB( R32G32B32A32_UINT, 4, uint32_t, unsigned, TO_INT )
209 ATTRIB( R32G32B32_UINT,    3, uint32_t, unsigned, TO_INT )
210 ATTRIB( R32G32_UINT,       2, uint32_t, unsigned, TO_INT )
211 ATTRIB( R32_UINT,          1, uint32_t, unsigned, TO_INT )
212 
213 ATTRIB( R16G16B16A16_UINT, 4, uint32_t, ushort, TO_INT )
214 ATTRIB( R16G16B16_UINT,    3, uint32_t, ushort, TO_INT )
215 ATTRIB( R16G16_UINT,       2, uint32_t, ushort, TO_INT )
216 ATTRIB( R16_UINT,          1, uint32_t, ushort, TO_INT )
217 
218 ATTRIB( R8G8B8A8_UINT,   4, uint32_t, ubyte, TO_INT )
219 ATTRIB( R8G8B8_UINT,     3, uint32_t, ubyte, TO_INT )
220 ATTRIB( R8G8_UINT,       2, uint32_t, ubyte, TO_INT )
221 ATTRIB( R8_UINT,         1, uint32_t, ubyte, TO_INT )
222 
223 ATTRIB( R32G32B32A32_SINT, 4, int32_t, int, TO_INT )
224 ATTRIB( R32G32B32_SINT,    3, int32_t, int, TO_INT )
225 ATTRIB( R32G32_SINT,       2, int32_t, int, TO_INT )
226 ATTRIB( R32_SINT,          1, int32_t, int, TO_INT )
227 
228 ATTRIB( R16G16B16A16_SINT, 4, int32_t, short, TO_INT )
229 ATTRIB( R16G16B16_SINT,    3, int32_t, short, TO_INT )
230 ATTRIB( R16G16_SINT,       2, int32_t, short, TO_INT )
231 ATTRIB( R16_SINT,          1, int32_t, short, TO_INT )
232 
233 ATTRIB( R8G8B8A8_SINT,   4, int32_t, char, TO_INT )
234 ATTRIB( R8G8B8_SINT,     3, int32_t, char, TO_INT )
235 ATTRIB( R8G8_SINT,       2, int32_t, char, TO_INT )
236 ATTRIB( R8_SINT,         1, int32_t, char, TO_INT )
237 
238 static void
emit_A8R8G8B8_UNORM(const void * attrib,void * ptr)239 emit_A8R8G8B8_UNORM( const void *attrib, void *ptr)
240 {
241    float *in = (float *)attrib;
242    ubyte *out = (ubyte *)ptr;
243    out[0] = TO_8_UNORM(in[3]);
244    out[1] = TO_8_UNORM(in[0]);
245    out[2] = TO_8_UNORM(in[1]);
246    out[3] = TO_8_UNORM(in[2]);
247 }
248 
249 static void
emit_B8G8R8A8_UNORM(const void * attrib,void * ptr)250 emit_B8G8R8A8_UNORM( const void *attrib, void *ptr)
251 {
252    float *in = (float *)attrib;
253    ubyte *out = (ubyte *)ptr;
254    out[2] = TO_8_UNORM(in[0]);
255    out[1] = TO_8_UNORM(in[1]);
256    out[0] = TO_8_UNORM(in[2]);
257    out[3] = TO_8_UNORM(in[3]);
258 }
259 
260 static void
emit_B10G10R10A2_UNORM(const void * attrib,void * ptr)261 emit_B10G10R10A2_UNORM( const void *attrib, void *ptr )
262 {
263    float *src = (float *)ptr;
264    uint32_t value = 0;
265    value |= ((uint32_t)(CLAMP(src[2], 0, 1) * 0x3ff)) & 0x3ff;
266    value |= (((uint32_t)(CLAMP(src[1], 0, 1) * 0x3ff)) & 0x3ff) << 10;
267    value |= (((uint32_t)(CLAMP(src[0], 0, 1) * 0x3ff)) & 0x3ff) << 20;
268    value |= ((uint32_t)(CLAMP(src[3], 0, 1) * 0x3)) << 30;
269 #ifdef PIPE_ARCH_BIG_ENDIAN
270    value = util_bswap32(value);
271 #endif
272    *(uint32_t *)attrib = value;
273 }
274 
275 static void
emit_B10G10R10A2_USCALED(const void * attrib,void * ptr)276 emit_B10G10R10A2_USCALED( const void *attrib, void *ptr )
277 {
278    float *src = (float *)ptr;
279    uint32_t value = 0;
280    value |= ((uint32_t)CLAMP(src[2], 0, 1023)) & 0x3ff;
281    value |= (((uint32_t)CLAMP(src[1], 0, 1023)) & 0x3ff) << 10;
282    value |= (((uint32_t)CLAMP(src[0], 0, 1023)) & 0x3ff) << 20;
283    value |= ((uint32_t)CLAMP(src[3], 0, 3)) << 30;
284 #ifdef PIPE_ARCH_BIG_ENDIAN
285    value = util_bswap32(value);
286 #endif
287    *(uint32_t *)attrib = value;
288 }
289 
290 static void
emit_B10G10R10A2_SNORM(const void * attrib,void * ptr)291 emit_B10G10R10A2_SNORM( const void *attrib, void *ptr )
292 {
293    float *src = (float *)ptr;
294    uint32_t value = 0;
295    value |= (uint32_t)(((uint32_t)(CLAMP(src[2], -1, 1) * 0x1ff)) & 0x3ff) ;
296    value |= (uint32_t)((((uint32_t)(CLAMP(src[1], -1, 1) * 0x1ff)) & 0x3ff) << 10) ;
297    value |= (uint32_t)((((uint32_t)(CLAMP(src[0], -1, 1) * 0x1ff)) & 0x3ff) << 20) ;
298    value |= (uint32_t)(((uint32_t)(CLAMP(src[3], -1, 1) * 0x1)) << 30) ;
299 #ifdef PIPE_ARCH_BIG_ENDIAN
300    value = util_bswap32(value);
301 #endif
302    *(uint32_t *)attrib = value;
303 }
304 
305 static void
emit_B10G10R10A2_SSCALED(const void * attrib,void * ptr)306 emit_B10G10R10A2_SSCALED( const void *attrib, void *ptr )
307 {
308    float *src = (float *)ptr;
309    uint32_t value = 0;
310    value |= (uint32_t)(((uint32_t)CLAMP(src[2], -512, 511)) & 0x3ff) ;
311    value |= (uint32_t)((((uint32_t)CLAMP(src[1], -512, 511)) & 0x3ff) << 10) ;
312    value |= (uint32_t)((((uint32_t)CLAMP(src[0], -512, 511)) & 0x3ff) << 20) ;
313    value |= (uint32_t)(((uint32_t)CLAMP(src[3], -2, 1)) << 30) ;
314 #ifdef PIPE_ARCH_BIG_ENDIAN
315    value = util_bswap32(value);
316 #endif
317    *(uint32_t *)attrib = value;
318 }
319 
320 static void
emit_R10G10B10A2_UNORM(const void * attrib,void * ptr)321 emit_R10G10B10A2_UNORM( const void *attrib, void *ptr )
322 {
323    float *src = (float *)ptr;
324    uint32_t value = 0;
325    value |= ((uint32_t)(CLAMP(src[0], 0, 1) * 0x3ff)) & 0x3ff;
326    value |= (((uint32_t)(CLAMP(src[1], 0, 1) * 0x3ff)) & 0x3ff) << 10;
327    value |= (((uint32_t)(CLAMP(src[2], 0, 1) * 0x3ff)) & 0x3ff) << 20;
328    value |= ((uint32_t)(CLAMP(src[3], 0, 1) * 0x3)) << 30;
329 #ifdef PIPE_ARCH_BIG_ENDIAN
330    value = util_bswap32(value);
331 #endif
332    *(uint32_t *)attrib = value;
333 }
334 
335 static void
emit_R10G10B10A2_USCALED(const void * attrib,void * ptr)336 emit_R10G10B10A2_USCALED( const void *attrib, void *ptr )
337 {
338    float *src = (float *)ptr;
339    uint32_t value = 0;
340    value |= ((uint32_t)CLAMP(src[0], 0, 1023)) & 0x3ff;
341    value |= (((uint32_t)CLAMP(src[1], 0, 1023)) & 0x3ff) << 10;
342    value |= (((uint32_t)CLAMP(src[2], 0, 1023)) & 0x3ff) << 20;
343    value |= ((uint32_t)CLAMP(src[3], 0, 3)) << 30;
344 #ifdef PIPE_ARCH_BIG_ENDIAN
345    value = util_bswap32(value);
346 #endif
347    *(uint32_t *)attrib = value;
348 }
349 
350 static void
emit_R10G10B10A2_SNORM(const void * attrib,void * ptr)351 emit_R10G10B10A2_SNORM( const void *attrib, void *ptr )
352 {
353    float *src = (float *)ptr;
354    uint32_t value = 0;
355    value |= (uint32_t)(((uint32_t)(CLAMP(src[0], -1, 1) * 0x1ff)) & 0x3ff) ;
356    value |= (uint32_t)((((uint32_t)(CLAMP(src[1], -1, 1) * 0x1ff)) & 0x3ff) << 10) ;
357    value |= (uint32_t)((((uint32_t)(CLAMP(src[2], -1, 1) * 0x1ff)) & 0x3ff) << 20) ;
358    value |= (uint32_t)(((uint32_t)(CLAMP(src[3], -1, 1) * 0x1)) << 30) ;
359 #ifdef PIPE_ARCH_BIG_ENDIAN
360    value = util_bswap32(value);
361 #endif
362    *(uint32_t *)attrib = value;
363 }
364 
365 static void
emit_R10G10B10A2_SSCALED(const void * attrib,void * ptr)366 emit_R10G10B10A2_SSCALED( const void *attrib, void *ptr)
367 {
368    float *src = (float *)ptr;
369    uint32_t value = 0;
370    value |= (uint32_t)(((uint32_t)CLAMP(src[0], -512, 511)) & 0x3ff) ;
371    value |= (uint32_t)((((uint32_t)CLAMP(src[1], -512, 511)) & 0x3ff) << 10) ;
372    value |= (uint32_t)((((uint32_t)CLAMP(src[2], -512, 511)) & 0x3ff) << 20) ;
373    value |= (uint32_t)(((uint32_t)CLAMP(src[3], -2, 1)) << 30) ;
374 #ifdef PIPE_ARCH_BIG_ENDIAN
375    value = util_bswap32(value);
376 #endif
377    *(uint32_t *)attrib = value;
378 }
379 
380 static void
emit_NULL(const void * attrib,void * ptr)381 emit_NULL( const void *attrib, void *ptr )
382 {
383    /* do nothing is the only sensible option */
384 }
385 
get_emit_func(enum pipe_format format)386 static emit_func get_emit_func( enum pipe_format format )
387 {
388    switch (format) {
389    case PIPE_FORMAT_R64_FLOAT:
390       return &emit_R64_FLOAT;
391    case PIPE_FORMAT_R64G64_FLOAT:
392       return &emit_R64G64_FLOAT;
393    case PIPE_FORMAT_R64G64B64_FLOAT:
394       return &emit_R64G64B64_FLOAT;
395    case PIPE_FORMAT_R64G64B64A64_FLOAT:
396       return &emit_R64G64B64A64_FLOAT;
397 
398    case PIPE_FORMAT_R32_FLOAT:
399       return &emit_R32_FLOAT;
400    case PIPE_FORMAT_R32G32_FLOAT:
401       return &emit_R32G32_FLOAT;
402    case PIPE_FORMAT_R32G32B32_FLOAT:
403       return &emit_R32G32B32_FLOAT;
404    case PIPE_FORMAT_R32G32B32A32_FLOAT:
405       return &emit_R32G32B32A32_FLOAT;
406 
407    case PIPE_FORMAT_R16_FLOAT:
408       return &emit_R16_FLOAT;
409    case PIPE_FORMAT_R16G16_FLOAT:
410       return &emit_R16G16_FLOAT;
411    case PIPE_FORMAT_R16G16B16_FLOAT:
412       return &emit_R16G16B16_FLOAT;
413    case PIPE_FORMAT_R16G16B16A16_FLOAT:
414       return &emit_R16G16B16A16_FLOAT;
415 
416    case PIPE_FORMAT_R32_UNORM:
417       return &emit_R32_UNORM;
418    case PIPE_FORMAT_R32G32_UNORM:
419       return &emit_R32G32_UNORM;
420    case PIPE_FORMAT_R32G32B32_UNORM:
421       return &emit_R32G32B32_UNORM;
422    case PIPE_FORMAT_R32G32B32A32_UNORM:
423       return &emit_R32G32B32A32_UNORM;
424 
425    case PIPE_FORMAT_R32_USCALED:
426       return &emit_R32_USCALED;
427    case PIPE_FORMAT_R32G32_USCALED:
428       return &emit_R32G32_USCALED;
429    case PIPE_FORMAT_R32G32B32_USCALED:
430       return &emit_R32G32B32_USCALED;
431    case PIPE_FORMAT_R32G32B32A32_USCALED:
432       return &emit_R32G32B32A32_USCALED;
433 
434    case PIPE_FORMAT_R32_SNORM:
435       return &emit_R32_SNORM;
436    case PIPE_FORMAT_R32G32_SNORM:
437       return &emit_R32G32_SNORM;
438    case PIPE_FORMAT_R32G32B32_SNORM:
439       return &emit_R32G32B32_SNORM;
440    case PIPE_FORMAT_R32G32B32A32_SNORM:
441       return &emit_R32G32B32A32_SNORM;
442 
443    case PIPE_FORMAT_R32_SSCALED:
444       return &emit_R32_SSCALED;
445    case PIPE_FORMAT_R32G32_SSCALED:
446       return &emit_R32G32_SSCALED;
447    case PIPE_FORMAT_R32G32B32_SSCALED:
448       return &emit_R32G32B32_SSCALED;
449    case PIPE_FORMAT_R32G32B32A32_SSCALED:
450       return &emit_R32G32B32A32_SSCALED;
451 
452    case PIPE_FORMAT_R16_UNORM:
453       return &emit_R16_UNORM;
454    case PIPE_FORMAT_R16G16_UNORM:
455       return &emit_R16G16_UNORM;
456    case PIPE_FORMAT_R16G16B16_UNORM:
457       return &emit_R16G16B16_UNORM;
458    case PIPE_FORMAT_R16G16B16A16_UNORM:
459       return &emit_R16G16B16A16_UNORM;
460 
461    case PIPE_FORMAT_R16_USCALED:
462       return &emit_R16_USCALED;
463    case PIPE_FORMAT_R16G16_USCALED:
464       return &emit_R16G16_USCALED;
465    case PIPE_FORMAT_R16G16B16_USCALED:
466       return &emit_R16G16B16_USCALED;
467    case PIPE_FORMAT_R16G16B16A16_USCALED:
468       return &emit_R16G16B16A16_USCALED;
469 
470    case PIPE_FORMAT_R16_SNORM:
471       return &emit_R16_SNORM;
472    case PIPE_FORMAT_R16G16_SNORM:
473       return &emit_R16G16_SNORM;
474    case PIPE_FORMAT_R16G16B16_SNORM:
475       return &emit_R16G16B16_SNORM;
476    case PIPE_FORMAT_R16G16B16A16_SNORM:
477       return &emit_R16G16B16A16_SNORM;
478 
479    case PIPE_FORMAT_R16_SSCALED:
480       return &emit_R16_SSCALED;
481    case PIPE_FORMAT_R16G16_SSCALED:
482       return &emit_R16G16_SSCALED;
483    case PIPE_FORMAT_R16G16B16_SSCALED:
484       return &emit_R16G16B16_SSCALED;
485    case PIPE_FORMAT_R16G16B16A16_SSCALED:
486       return &emit_R16G16B16A16_SSCALED;
487 
488    case PIPE_FORMAT_R8_UNORM:
489       return &emit_R8_UNORM;
490    case PIPE_FORMAT_R8G8_UNORM:
491       return &emit_R8G8_UNORM;
492    case PIPE_FORMAT_R8G8B8_UNORM:
493       return &emit_R8G8B8_UNORM;
494    case PIPE_FORMAT_R8G8B8A8_UNORM:
495       return &emit_R8G8B8A8_UNORM;
496 
497    case PIPE_FORMAT_R8_USCALED:
498       return &emit_R8_USCALED;
499    case PIPE_FORMAT_R8G8_USCALED:
500       return &emit_R8G8_USCALED;
501    case PIPE_FORMAT_R8G8B8_USCALED:
502       return &emit_R8G8B8_USCALED;
503    case PIPE_FORMAT_R8G8B8A8_USCALED:
504       return &emit_R8G8B8A8_USCALED;
505 
506    case PIPE_FORMAT_R8_SNORM:
507       return &emit_R8_SNORM;
508    case PIPE_FORMAT_R8G8_SNORM:
509       return &emit_R8G8_SNORM;
510    case PIPE_FORMAT_R8G8B8_SNORM:
511       return &emit_R8G8B8_SNORM;
512    case PIPE_FORMAT_R8G8B8A8_SNORM:
513       return &emit_R8G8B8A8_SNORM;
514 
515    case PIPE_FORMAT_R8_SSCALED:
516       return &emit_R8_SSCALED;
517    case PIPE_FORMAT_R8G8_SSCALED:
518       return &emit_R8G8_SSCALED;
519    case PIPE_FORMAT_R8G8B8_SSCALED:
520       return &emit_R8G8B8_SSCALED;
521    case PIPE_FORMAT_R8G8B8A8_SSCALED:
522       return &emit_R8G8B8A8_SSCALED;
523 
524    case PIPE_FORMAT_B8G8R8A8_UNORM:
525       return &emit_B8G8R8A8_UNORM;
526 
527    case PIPE_FORMAT_A8R8G8B8_UNORM:
528       return &emit_A8R8G8B8_UNORM;
529 
530    case PIPE_FORMAT_R32_UINT:
531       return &emit_R32_UINT;
532    case PIPE_FORMAT_R32G32_UINT:
533       return &emit_R32G32_UINT;
534    case PIPE_FORMAT_R32G32B32_UINT:
535       return &emit_R32G32B32_UINT;
536    case PIPE_FORMAT_R32G32B32A32_UINT:
537       return &emit_R32G32B32A32_UINT;
538 
539    case PIPE_FORMAT_R16_UINT:
540       return &emit_R16_UINT;
541    case PIPE_FORMAT_R16G16_UINT:
542       return &emit_R16G16_UINT;
543    case PIPE_FORMAT_R16G16B16_UINT:
544       return &emit_R16G16B16_UINT;
545    case PIPE_FORMAT_R16G16B16A16_UINT:
546       return &emit_R16G16B16A16_UINT;
547 
548    case PIPE_FORMAT_R8_UINT:
549       return &emit_R8_UINT;
550    case PIPE_FORMAT_R8G8_UINT:
551       return &emit_R8G8_UINT;
552    case PIPE_FORMAT_R8G8B8_UINT:
553       return &emit_R8G8B8_UINT;
554    case PIPE_FORMAT_R8G8B8A8_UINT:
555       return &emit_R8G8B8A8_UINT;
556 
557    case PIPE_FORMAT_R32_SINT:
558       return &emit_R32_SINT;
559    case PIPE_FORMAT_R32G32_SINT:
560       return &emit_R32G32_SINT;
561    case PIPE_FORMAT_R32G32B32_SINT:
562       return &emit_R32G32B32_SINT;
563    case PIPE_FORMAT_R32G32B32A32_SINT:
564       return &emit_R32G32B32A32_SINT;
565 
566    case PIPE_FORMAT_R16_SINT:
567       return &emit_R16_SINT;
568    case PIPE_FORMAT_R16G16_SINT:
569       return &emit_R16G16_SINT;
570    case PIPE_FORMAT_R16G16B16_SINT:
571       return &emit_R16G16B16_SINT;
572    case PIPE_FORMAT_R16G16B16A16_SINT:
573       return &emit_R16G16B16A16_SINT;
574 
575    case PIPE_FORMAT_R8_SINT:
576       return &emit_R8_SINT;
577    case PIPE_FORMAT_R8G8_SINT:
578       return &emit_R8G8_SINT;
579    case PIPE_FORMAT_R8G8B8_SINT:
580       return &emit_R8G8B8_SINT;
581    case PIPE_FORMAT_R8G8B8A8_SINT:
582       return &emit_R8G8B8A8_SINT;
583 
584    case PIPE_FORMAT_B10G10R10A2_UNORM:
585       return &emit_B10G10R10A2_UNORM;
586    case PIPE_FORMAT_B10G10R10A2_USCALED:
587       return &emit_B10G10R10A2_USCALED;
588    case PIPE_FORMAT_B10G10R10A2_SNORM:
589       return &emit_B10G10R10A2_SNORM;
590    case PIPE_FORMAT_B10G10R10A2_SSCALED:
591       return &emit_B10G10R10A2_SSCALED;
592 
593    case PIPE_FORMAT_R10G10B10A2_UNORM:
594       return &emit_R10G10B10A2_UNORM;
595    case PIPE_FORMAT_R10G10B10A2_USCALED:
596       return &emit_R10G10B10A2_USCALED;
597    case PIPE_FORMAT_R10G10B10A2_SNORM:
598       return &emit_R10G10B10A2_SNORM;
599    case PIPE_FORMAT_R10G10B10A2_SSCALED:
600       return &emit_R10G10B10A2_SSCALED;
601 
602    default:
603       assert(0);
604       return &emit_NULL;
605    }
606 }
607 
generic_run_one(struct translate_generic * tg,unsigned elt,unsigned instance_id,void * vert)608 static ALWAYS_INLINE void PIPE_CDECL generic_run_one( struct translate_generic *tg,
609                                          unsigned elt,
610                                          unsigned instance_id,
611                                          void *vert )
612 {
613    unsigned nr_attrs = tg->nr_attrib;
614    unsigned attr;
615 
616    for (attr = 0; attr < nr_attrs; attr++) {
617       float data[4];
618       uint8_t *dst = (uint8_t *)vert + tg->attrib[attr].output_offset;
619 
620       if (tg->attrib[attr].type == TRANSLATE_ELEMENT_NORMAL) {
621          const uint8_t *src;
622          unsigned index;
623          int copy_size;
624 
625          if (tg->attrib[attr].instance_divisor) {
626             index = instance_id / tg->attrib[attr].instance_divisor;
627             /* XXX we need to clamp the index here too, but to a
628              * per-array max value, not the draw->pt.max_index value
629              * that's being given to us via translate->set_buffer().
630              */
631          }
632          else {
633             index = elt;
634             /* clamp to avoid going out of bounds */
635             index = MIN2(index, tg->attrib[attr].max_index);
636          }
637 
638          src = tg->attrib[attr].input_ptr +
639                tg->attrib[attr].input_stride * index;
640 
641          copy_size = tg->attrib[attr].copy_size;
642          if(likely(copy_size >= 0))
643             memcpy(dst, src, copy_size);
644          else
645          {
646             tg->attrib[attr].fetch( data, src, 0, 0 );
647 
648             if (0)
649                debug_printf("Fetch linear attr %d  from %p  stride %d  index %d: "
650                          " %f, %f, %f, %f \n",
651                          attr,
652                          tg->attrib[attr].input_ptr,
653                          tg->attrib[attr].input_stride,
654                          index,
655                          data[0], data[1],data[2], data[3]);
656 
657             tg->attrib[attr].emit( data, dst );
658          }
659       } else {
660          if(likely(tg->attrib[attr].copy_size >= 0))
661             memcpy(data, &instance_id, 4);
662          else
663          {
664             data[0] = (float)instance_id;
665             tg->attrib[attr].emit( data, dst );
666          }
667       }
668    }
669 }
670 
671 /**
672  * Fetch vertex attributes for 'count' vertices.
673  */
generic_run_elts(struct translate * translate,const unsigned * elts,unsigned count,unsigned instance_id,void * output_buffer)674 static void PIPE_CDECL generic_run_elts( struct translate *translate,
675                                          const unsigned *elts,
676                                          unsigned count,
677                                          unsigned instance_id,
678                                          void *output_buffer )
679 {
680    struct translate_generic *tg = translate_generic(translate);
681    char *vert = output_buffer;
682    unsigned i;
683 
684    for (i = 0; i < count; i++) {
685       generic_run_one(tg, *elts++, instance_id, vert);
686       vert += tg->translate.key.output_stride;
687    }
688 }
689 
generic_run_elts16(struct translate * translate,const uint16_t * elts,unsigned count,unsigned instance_id,void * output_buffer)690 static void PIPE_CDECL generic_run_elts16( struct translate *translate,
691                                          const uint16_t *elts,
692                                          unsigned count,
693                                          unsigned instance_id,
694                                          void *output_buffer )
695 {
696    struct translate_generic *tg = translate_generic(translate);
697    char *vert = output_buffer;
698    unsigned i;
699 
700    for (i = 0; i < count; i++) {
701       generic_run_one(tg, *elts++, instance_id, vert);
702       vert += tg->translate.key.output_stride;
703    }
704 }
705 
generic_run_elts8(struct translate * translate,const uint8_t * elts,unsigned count,unsigned instance_id,void * output_buffer)706 static void PIPE_CDECL generic_run_elts8( struct translate *translate,
707                                          const uint8_t *elts,
708                                          unsigned count,
709                                          unsigned instance_id,
710                                          void *output_buffer )
711 {
712    struct translate_generic *tg = translate_generic(translate);
713    char *vert = output_buffer;
714    unsigned i;
715 
716    for (i = 0; i < count; i++) {
717       generic_run_one(tg, *elts++, instance_id, vert);
718       vert += tg->translate.key.output_stride;
719    }
720 }
721 
generic_run(struct translate * translate,unsigned start,unsigned count,unsigned instance_id,void * output_buffer)722 static void PIPE_CDECL generic_run( struct translate *translate,
723                                     unsigned start,
724                                     unsigned count,
725                                     unsigned instance_id,
726                                     void *output_buffer )
727 {
728    struct translate_generic *tg = translate_generic(translate);
729    char *vert = output_buffer;
730    unsigned i;
731 
732    for (i = 0; i < count; i++) {
733       generic_run_one(tg, start + i, instance_id, vert);
734       vert += tg->translate.key.output_stride;
735    }
736 }
737 
738 
739 
generic_set_buffer(struct translate * translate,unsigned buf,const void * ptr,unsigned stride,unsigned max_index)740 static void generic_set_buffer( struct translate *translate,
741 				unsigned buf,
742 				const void *ptr,
743 				unsigned stride,
744 				unsigned max_index )
745 {
746    struct translate_generic *tg = translate_generic(translate);
747    unsigned i;
748 
749    for (i = 0; i < tg->nr_attrib; i++) {
750       if (tg->attrib[i].buffer == buf) {
751 	 tg->attrib[i].input_ptr = ((const uint8_t *)ptr +
752 				    tg->attrib[i].input_offset);
753 	 tg->attrib[i].input_stride = stride;
754          tg->attrib[i].max_index = max_index;
755       }
756    }
757 }
758 
759 
generic_release(struct translate * translate)760 static void generic_release( struct translate *translate )
761 {
762    /* Refcount?
763     */
764    FREE(translate);
765 }
766 
767 static boolean
is_legal_int_format_combo(const struct util_format_description * src,const struct util_format_description * dst)768 is_legal_int_format_combo( const struct util_format_description *src,
769                            const struct util_format_description *dst )
770 {
771    unsigned i;
772    unsigned nr = MIN2(src->nr_channels, dst->nr_channels);
773 
774    for (i = 0; i < nr; i++) {
775       /* The signs must match. */
776       if (src->channel[i].type != dst->channel[i].type) {
777          return FALSE;
778       }
779 
780       /* Integers must not lose precision at any point in the pipeline. */
781       if (src->channel[i].size > dst->channel[i].size) {
782          return FALSE;
783       }
784    }
785    return TRUE;
786 }
787 
translate_generic_create(const struct translate_key * key)788 struct translate *translate_generic_create( const struct translate_key *key )
789 {
790    struct translate_generic *tg = CALLOC_STRUCT(translate_generic);
791    unsigned i;
792 
793    if (tg == NULL)
794       return NULL;
795 
796    tg->translate.key = *key;
797    tg->translate.release = generic_release;
798    tg->translate.set_buffer = generic_set_buffer;
799    tg->translate.run_elts = generic_run_elts;
800    tg->translate.run_elts16 = generic_run_elts16;
801    tg->translate.run_elts8 = generic_run_elts8;
802    tg->translate.run = generic_run;
803 
804    for (i = 0; i < key->nr_elements; i++) {
805       const struct util_format_description *format_desc =
806             util_format_description(key->element[i].input_format);
807 
808       assert(format_desc);
809       assert(format_desc->fetch_rgba_float);
810 
811       tg->attrib[i].type = key->element[i].type;
812 
813       if (format_desc->channel[0].pure_integer) {
814          const struct util_format_description *out_format_desc =
815                util_format_description(key->element[i].output_format);
816 
817          if (!is_legal_int_format_combo(format_desc, out_format_desc)) {
818             FREE(tg);
819             return NULL;
820          }
821 
822          if (format_desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
823             tg->attrib[i].fetch = (fetch_func)format_desc->fetch_rgba_sint;
824          } else {
825             tg->attrib[i].fetch = (fetch_func)format_desc->fetch_rgba_uint;
826          }
827       } else {
828          tg->attrib[i].fetch = (fetch_func)format_desc->fetch_rgba_float;
829       }
830 
831       tg->attrib[i].buffer = key->element[i].input_buffer;
832       tg->attrib[i].input_offset = key->element[i].input_offset;
833       tg->attrib[i].instance_divisor = key->element[i].instance_divisor;
834 
835       tg->attrib[i].output_offset = key->element[i].output_offset;
836 
837       tg->attrib[i].copy_size = -1;
838       if (tg->attrib[i].type == TRANSLATE_ELEMENT_INSTANCE_ID)
839       {
840             if(key->element[i].output_format == PIPE_FORMAT_R32_USCALED
841                   || key->element[i].output_format == PIPE_FORMAT_R32_SSCALED)
842                tg->attrib[i].copy_size = 4;
843       }
844       else
845       {
846          if(key->element[i].input_format == key->element[i].output_format
847                && format_desc->block.width == 1
848                && format_desc->block.height == 1
849                && !(format_desc->block.bits & 7))
850             tg->attrib[i].copy_size = format_desc->block.bits >> 3;
851       }
852 
853       if(tg->attrib[i].copy_size < 0)
854 	      tg->attrib[i].emit = get_emit_func(key->element[i].output_format);
855       else
856 	      tg->attrib[i].emit  = NULL;
857    }
858 
859    tg->nr_attrib = key->nr_elements;
860 
861 
862    return &tg->translate;
863 }
864 
translate_generic_is_output_format_supported(enum pipe_format format)865 boolean translate_generic_is_output_format_supported(enum pipe_format format)
866 {
867    switch(format)
868    {
869    case PIPE_FORMAT_R64G64B64A64_FLOAT: return TRUE;
870    case PIPE_FORMAT_R64G64B64_FLOAT: return TRUE;
871    case PIPE_FORMAT_R64G64_FLOAT: return TRUE;
872    case PIPE_FORMAT_R64_FLOAT: return TRUE;
873 
874    case PIPE_FORMAT_R32G32B32A32_FLOAT: return TRUE;
875    case PIPE_FORMAT_R32G32B32_FLOAT: return TRUE;
876    case PIPE_FORMAT_R32G32_FLOAT: return TRUE;
877    case PIPE_FORMAT_R32_FLOAT: return TRUE;
878 
879    case PIPE_FORMAT_R16G16B16A16_FLOAT: return TRUE;
880    case PIPE_FORMAT_R16G16B16_FLOAT: return TRUE;
881    case PIPE_FORMAT_R16G16_FLOAT: return TRUE;
882    case PIPE_FORMAT_R16_FLOAT: return TRUE;
883 
884    case PIPE_FORMAT_R32G32B32A32_USCALED: return TRUE;
885    case PIPE_FORMAT_R32G32B32_USCALED: return TRUE;
886    case PIPE_FORMAT_R32G32_USCALED: return TRUE;
887    case PIPE_FORMAT_R32_USCALED: return TRUE;
888 
889    case PIPE_FORMAT_R32G32B32A32_SSCALED: return TRUE;
890    case PIPE_FORMAT_R32G32B32_SSCALED: return TRUE;
891    case PIPE_FORMAT_R32G32_SSCALED: return TRUE;
892    case PIPE_FORMAT_R32_SSCALED: return TRUE;
893 
894    case PIPE_FORMAT_R32G32B32A32_UNORM: return TRUE;
895    case PIPE_FORMAT_R32G32B32_UNORM: return TRUE;
896    case PIPE_FORMAT_R32G32_UNORM: return TRUE;
897    case PIPE_FORMAT_R32_UNORM: return TRUE;
898 
899    case PIPE_FORMAT_R32G32B32A32_SNORM: return TRUE;
900    case PIPE_FORMAT_R32G32B32_SNORM: return TRUE;
901    case PIPE_FORMAT_R32G32_SNORM: return TRUE;
902    case PIPE_FORMAT_R32_SNORM: return TRUE;
903 
904    case PIPE_FORMAT_R16G16B16A16_USCALED: return TRUE;
905    case PIPE_FORMAT_R16G16B16_USCALED: return TRUE;
906    case PIPE_FORMAT_R16G16_USCALED: return TRUE;
907    case PIPE_FORMAT_R16_USCALED: return TRUE;
908 
909    case PIPE_FORMAT_R16G16B16A16_SSCALED: return TRUE;
910    case PIPE_FORMAT_R16G16B16_SSCALED: return TRUE;
911    case PIPE_FORMAT_R16G16_SSCALED: return TRUE;
912    case PIPE_FORMAT_R16_SSCALED: return TRUE;
913 
914    case PIPE_FORMAT_R16G16B16A16_UNORM: return TRUE;
915    case PIPE_FORMAT_R16G16B16_UNORM: return TRUE;
916    case PIPE_FORMAT_R16G16_UNORM: return TRUE;
917    case PIPE_FORMAT_R16_UNORM: return TRUE;
918 
919    case PIPE_FORMAT_R16G16B16A16_SNORM: return TRUE;
920    case PIPE_FORMAT_R16G16B16_SNORM: return TRUE;
921    case PIPE_FORMAT_R16G16_SNORM: return TRUE;
922    case PIPE_FORMAT_R16_SNORM: return TRUE;
923 
924    case PIPE_FORMAT_R8G8B8A8_USCALED: return TRUE;
925    case PIPE_FORMAT_R8G8B8_USCALED: return TRUE;
926    case PIPE_FORMAT_R8G8_USCALED: return TRUE;
927    case PIPE_FORMAT_R8_USCALED: return TRUE;
928 
929    case PIPE_FORMAT_R8G8B8A8_SSCALED: return TRUE;
930    case PIPE_FORMAT_R8G8B8_SSCALED: return TRUE;
931    case PIPE_FORMAT_R8G8_SSCALED: return TRUE;
932    case PIPE_FORMAT_R8_SSCALED: return TRUE;
933 
934    case PIPE_FORMAT_R8G8B8A8_UNORM: return TRUE;
935    case PIPE_FORMAT_R8G8B8_UNORM: return TRUE;
936    case PIPE_FORMAT_R8G8_UNORM: return TRUE;
937    case PIPE_FORMAT_R8_UNORM: return TRUE;
938 
939    case PIPE_FORMAT_R8G8B8A8_SNORM: return TRUE;
940    case PIPE_FORMAT_R8G8B8_SNORM: return TRUE;
941    case PIPE_FORMAT_R8G8_SNORM: return TRUE;
942    case PIPE_FORMAT_R8_SNORM: return TRUE;
943 
944    case PIPE_FORMAT_A8R8G8B8_UNORM: return TRUE;
945    case PIPE_FORMAT_B8G8R8A8_UNORM: return TRUE;
946 
947    case PIPE_FORMAT_R32G32B32A32_UINT: return TRUE;
948    case PIPE_FORMAT_R32G32B32_UINT: return TRUE;
949    case PIPE_FORMAT_R32G32_UINT: return TRUE;
950    case PIPE_FORMAT_R32_UINT: return TRUE;
951 
952    case PIPE_FORMAT_R16G16B16A16_UINT: return TRUE;
953    case PIPE_FORMAT_R16G16B16_UINT: return TRUE;
954    case PIPE_FORMAT_R16G16_UINT: return TRUE;
955    case PIPE_FORMAT_R16_UINT: return TRUE;
956 
957    case PIPE_FORMAT_R8G8B8A8_UINT: return TRUE;
958    case PIPE_FORMAT_R8G8B8_UINT: return TRUE;
959    case PIPE_FORMAT_R8G8_UINT: return TRUE;
960    case PIPE_FORMAT_R8_UINT: return TRUE;
961 
962    case PIPE_FORMAT_R32G32B32A32_SINT: return TRUE;
963    case PIPE_FORMAT_R32G32B32_SINT: return TRUE;
964    case PIPE_FORMAT_R32G32_SINT: return TRUE;
965    case PIPE_FORMAT_R32_SINT: return TRUE;
966 
967    case PIPE_FORMAT_R16G16B16A16_SINT: return TRUE;
968    case PIPE_FORMAT_R16G16B16_SINT: return TRUE;
969    case PIPE_FORMAT_R16G16_SINT: return TRUE;
970    case PIPE_FORMAT_R16_SINT: return TRUE;
971 
972    case PIPE_FORMAT_R8G8B8A8_SINT: return TRUE;
973    case PIPE_FORMAT_R8G8B8_SINT: return TRUE;
974    case PIPE_FORMAT_R8G8_SINT: return TRUE;
975    case PIPE_FORMAT_R8_SINT: return TRUE;
976 
977    case PIPE_FORMAT_B10G10R10A2_UNORM: return TRUE;
978    case PIPE_FORMAT_B10G10R10A2_USCALED: return TRUE;
979    case PIPE_FORMAT_B10G10R10A2_SNORM: return TRUE;
980    case PIPE_FORMAT_B10G10R10A2_SSCALED: return TRUE;
981 
982    case PIPE_FORMAT_R10G10B10A2_UNORM: return TRUE;
983    case PIPE_FORMAT_R10G10B10A2_USCALED: return TRUE;
984    case PIPE_FORMAT_R10G10B10A2_SNORM: return TRUE;
985    case PIPE_FORMAT_R10G10B10A2_SSCALED: return TRUE;
986 
987    default: return FALSE;
988    }
989 }
990