Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / state_trackers / vega / image.c
1 /**************************************************************************
2  *
3  * Copyright 2009 VMware, Inc.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 #include "image.h"
28
29 #include "vg_translate.h"
30 #include "vg_context.h"
31 #include "matrix.h"
32 #include "renderer.h"
33 #include "util_array.h"
34 #include "api_consts.h"
35 #include "shader.h"
36
37 #include "pipe/p_context.h"
38 #include "pipe/p_screen.h"
39 #include "util/u_inlines.h"
40 #include "util/u_format.h"
41 #include "util/u_tile.h"
42 #include "util/u_memory.h"
43 #include "util/u_math.h"
44 #include "util/u_sampler.h"
45 #include "util/u_surface.h"
46
47 static enum pipe_format vg_format_to_pipe(VGImageFormat format)
48 {
49    switch(format) {
50    case VG_sRGB_565:
51       return PIPE_FORMAT_B5G6R5_UNORM;
52    case VG_sRGBA_5551:
53       return PIPE_FORMAT_B5G5R5A1_UNORM;
54    case VG_sRGBA_4444:
55       return PIPE_FORMAT_B4G4R4A4_UNORM;
56    case VG_sL_8:
57    case VG_lL_8:
58       return PIPE_FORMAT_L8_UNORM;
59    case VG_BW_1:
60       return PIPE_FORMAT_B8G8R8A8_UNORM;
61    case VG_A_8:
62       return PIPE_FORMAT_A8_UNORM;
63 #ifdef OPENVG_VERSION_1_1
64    case VG_A_1:
65    case VG_A_4:
66       return PIPE_FORMAT_A8_UNORM;
67 #endif
68    default:
69       return PIPE_FORMAT_B8G8R8A8_UNORM;
70    }
71 }
72
73 static INLINE void vg_sync_size(VGfloat *src_loc, VGfloat *dst_loc)
74 {
75    src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
76    src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
77    dst_loc[2] = src_loc[2];
78    dst_loc[3] = src_loc[3];
79 }
80
81 static void vg_get_copy_coords(VGfloat *src_loc,
82                                VGfloat src_width, VGfloat src_height,
83                                VGfloat *dst_loc,
84                                VGfloat dst_width, VGfloat dst_height)
85 {
86    VGfloat dst_bounds[4], src_bounds[4];
87    VGfloat src_shift[4], dst_shift[4], shift[4];
88
89    dst_bounds[0] = 0.f;
90    dst_bounds[1] = 0.f;
91    dst_bounds[2] = dst_width;
92    dst_bounds[3] = dst_height;
93
94    src_bounds[0] = 0.f;
95    src_bounds[1] = 0.f;
96    src_bounds[2] = src_width;
97    src_bounds[3] = src_height;
98
99    vg_bound_rect(src_loc, src_bounds, src_shift);
100    vg_bound_rect(dst_loc, dst_bounds, dst_shift);
101    shift[0] = src_shift[0] - dst_shift[0];
102    shift[1] = src_shift[1] - dst_shift[1];
103
104    if (shift[0] < 0)
105       vg_shift_rectx(src_loc, src_bounds, -shift[0]);
106    else
107       vg_shift_rectx(dst_loc, dst_bounds, shift[0]);
108
109    if (shift[1] < 0)
110       vg_shift_recty(src_loc, src_bounds, -shift[1]);
111    else
112       vg_shift_recty(dst_loc, dst_bounds, shift[1]);
113
114    vg_sync_size(src_loc, dst_loc);
115 }
116
117 static void vg_copy_texture(struct vg_context *ctx,
118                             struct pipe_resource *dst, VGint dx, VGint dy,
119                             struct pipe_sampler_view *src, VGint sx, VGint sy,
120                             VGint width, VGint height)
121 {
122    VGfloat dst_loc[4], src_loc[4];
123
124    dst_loc[0] = dx;
125    dst_loc[1] = dy;
126    dst_loc[2] = width;
127    dst_loc[3] = height;
128
129    src_loc[0] = sx;
130    src_loc[1] = sy;
131    src_loc[2] = width;
132    src_loc[3] = height;
133
134    vg_get_copy_coords(src_loc, src->texture->width0, src->texture->height0,
135                       dst_loc, dst->width0, dst->height0);
136
137    if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
138        dst_loc[2] >= 0 && dst_loc[3] >= 0) {
139       struct pipe_surface *surf, surf_tmpl;
140
141       /* get the destination surface */
142       u_surface_default_template(&surf_tmpl, dst, PIPE_BIND_RENDER_TARGET);
143       surf = ctx->pipe->create_surface(ctx->pipe, dst, &surf_tmpl);
144       if (surf && renderer_copy_begin(ctx->renderer, surf, VG_TRUE, src)) {
145          renderer_copy(ctx->renderer,
146                dst_loc[0], dst_loc[1], dst_loc[2], dst_loc[3],
147                src_loc[0], src_loc[1], src_loc[2], src_loc[3]);
148          renderer_copy_end(ctx->renderer);
149       }
150
151       pipe_surface_reference(&surf, NULL);
152    }
153 }
154
155 void vg_copy_surface(struct vg_context *ctx,
156                      struct pipe_surface *dst, VGint dx, VGint dy,
157                      struct pipe_surface *src, VGint sx, VGint sy,
158                      VGint width, VGint height)
159 {
160    VGfloat dst_loc[4], src_loc[4];
161
162    dst_loc[0] = dx;
163    dst_loc[1] = dy;
164    dst_loc[2] = width;
165    dst_loc[3] = height;
166
167    src_loc[0] = sx;
168    src_loc[1] = sy;
169    src_loc[2] = width;
170    src_loc[3] = height;
171
172    vg_get_copy_coords(src_loc, src->width, src->height,
173                       dst_loc, dst->width, dst->height);
174
175    if (src_loc[2] > 0 && src_loc[3] > 0 &&
176        dst_loc[2] > 0 && dst_loc[3] > 0) {
177       if (src == dst)
178          renderer_copy_surface(ctx->renderer,
179                                src,
180                                src_loc[0],
181                                src->height - (src_loc[1] + src_loc[3]),
182                                src_loc[0] + src_loc[2],
183                                src->height - src_loc[1],
184                                dst,
185                                dst_loc[0],
186                                dst->height - (dst_loc[1] + dst_loc[3]),
187                                dst_loc[0] + dst_loc[2],
188                                dst->height - dst_loc[1],
189                                0, 0);
190       else
191          renderer_copy_surface(ctx->renderer,
192                                src,
193                                src_loc[0],
194                                src->height - src_loc[1],
195                                src_loc[0] + src_loc[2],
196                                src->height - (src_loc[1] + src_loc[3]),
197                                dst,
198                                dst_loc[0],
199                                dst->height - (dst_loc[1] + dst_loc[3]),
200                                dst_loc[0] + dst_loc[2],
201                                dst->height - dst_loc[1],
202                                0, 0);
203    }
204
205 }
206
207 static struct pipe_resource *image_texture(struct vg_image *img)
208 {
209    struct pipe_resource *tex = img->sampler_view->texture;
210    return tex;
211 }
212
213
214 static void image_cleari(struct vg_image *img, VGint clear_colori,
215                          VGint x, VGint y, VGint width, VGint height)
216 {
217    VGint *clearbuf;
218    VGint i;
219    VGfloat dwidth, dheight;
220
221    clearbuf = malloc(sizeof(VGint)*width*height);
222    for (i = 0; i < width*height; ++i)
223       clearbuf[i] = clear_colori;
224
225    dwidth = MIN2(width, img->width);
226    dheight = MIN2(height, img->height);
227
228    image_sub_data(img, clearbuf, width * sizeof(VGint),
229                   VG_sRGBA_8888,
230                   x, y, dwidth, dheight);
231    free(clearbuf);
232 }
233
234 struct vg_image * image_create(VGImageFormat format,
235                                VGint width, VGint height)
236 {
237    struct vg_context *ctx = vg_current_context();
238    struct pipe_context *pipe = ctx->pipe;
239    struct vg_image *image = CALLOC_STRUCT(vg_image);
240    enum pipe_format pformat = vg_format_to_pipe(format);
241    struct pipe_resource pt, *newtex;
242    struct pipe_sampler_view view_templ;
243    struct pipe_sampler_view *view;
244    struct pipe_screen *screen = ctx->pipe->screen;
245
246    vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
247
248    image->format = format;
249    image->width = width;
250    image->height = height;
251
252    image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
253    image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
254    image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
255    image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
256    image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
257    image->sampler.normalized_coords = 1;
258
259    assert(screen->is_format_supported(screen, pformat, PIPE_TEXTURE_2D,
260                                       0, PIPE_BIND_SAMPLER_VIEW));
261
262    memset(&pt, 0, sizeof(pt));
263    pt.target = PIPE_TEXTURE_2D;
264    pt.format = pformat;
265    pt.last_level = 0;
266    pt.width0 = width;
267    pt.height0 = height;
268    pt.depth0 = 1;
269    pt.array_size = 1;
270    pt.bind = PIPE_BIND_SAMPLER_VIEW;
271
272    newtex = screen->resource_create(screen, &pt);
273
274    debug_assert(newtex);
275
276    u_sampler_view_default_template(&view_templ, newtex, newtex->format);
277    /* R, G, and B are treated as 1.0 for alpha-only formats in OpenVG */
278    if (newtex->format == PIPE_FORMAT_A8_UNORM) {
279       view_templ.swizzle_r = PIPE_SWIZZLE_ONE;
280       view_templ.swizzle_g = PIPE_SWIZZLE_ONE;
281       view_templ.swizzle_b = PIPE_SWIZZLE_ONE;
282    }
283
284    view = pipe->create_sampler_view(pipe, newtex, &view_templ);
285    /* want the texture to go away if the view is freed */
286    pipe_resource_reference(&newtex, NULL);
287
288    image->sampler_view = view;
289
290    vg_context_add_object(ctx, VG_OBJECT_IMAGE, image);
291
292    image_cleari(image, 0, 0, 0, image->width, image->height);
293    return image;
294 }
295
296 void image_destroy(struct vg_image *img)
297 {
298    struct vg_context *ctx = vg_current_context();
299    vg_context_remove_object(ctx, VG_OBJECT_IMAGE, img);
300
301
302    if (img->parent) {
303       /* remove img from the parent child array */
304       int idx;
305       struct vg_image **array =
306          (struct vg_image **)img->parent->children_array->data;
307
308       for (idx = 0; idx < img->parent->children_array->num_elements; ++idx) {
309          struct vg_image *child = array[idx];
310          if (child == img) {
311             break;
312          }
313       }
314       debug_assert(idx < img->parent->children_array->num_elements);
315       array_remove_element(img->parent->children_array, idx);
316    }
317
318    if (img->children_array && img->children_array->num_elements) {
319       /* reparent the children */
320       VGint i;
321       struct vg_image *parent = img->parent;
322       struct vg_image **children =
323          (struct vg_image **)img->children_array->data;
324       if (!parent) {
325          VGint min_x = children[0]->x;
326          parent = children[0];
327
328          for (i = 1; i < img->children_array->num_elements; ++i) {
329             struct vg_image *child = children[i];
330             if (child->x < min_x) {
331                parent = child;
332             }
333          }
334       }
335
336       for (i = 0; i < img->children_array->num_elements; ++i) {
337          struct vg_image *child = children[i];
338          if (child != parent) {
339             child->parent = parent;
340             if (!parent->children_array) {
341                parent->children_array = array_create(
342                   sizeof(struct vg_image*));
343             }
344             array_append_data(parent->children_array,
345                               &child, 1);
346          } else
347             child->parent = NULL;
348       }
349       array_destroy(img->children_array);
350    }
351
352    vg_free_object(&img->base);
353
354    pipe_sampler_view_reference(&img->sampler_view, NULL);
355    FREE(img);
356 }
357
358 void image_clear(struct vg_image *img,
359                  VGint x, VGint y, VGint width, VGint height)
360 {
361    struct vg_context *ctx = vg_current_context();
362    VGfloat *clear_colorf = ctx->state.vg.clear_color;
363    VGubyte r, g, b ,a;
364    VGint clear_colori;
365    /* FIXME: this is very nasty */
366    r = float_to_ubyte(clear_colorf[0]);
367    g = float_to_ubyte(clear_colorf[1]);
368    b = float_to_ubyte(clear_colorf[2]);
369    a = float_to_ubyte(clear_colorf[3]);
370    clear_colori = r << 24 | g << 16 | b << 8 | a;
371    image_cleari(img, clear_colori, x, y, width, height);
372 }
373
374 void image_sub_data(struct vg_image *image,
375                     const void * data,
376                     VGint dataStride,
377                     VGImageFormat dataFormat,
378                     VGint x, VGint y,
379                     VGint width, VGint height)
380 {
381    const VGint yStep = 1;
382    VGubyte *src = (VGubyte *)data;
383    VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
384    VGfloat *df = (VGfloat*)temp;
385    VGint i;
386    struct vg_context *ctx = vg_current_context();
387    struct pipe_context *pipe = ctx->pipe;
388    struct pipe_resource *texture = image_texture(image);
389    VGint xoffset = 0, yoffset = 0;
390
391    if (x < 0) {
392       xoffset -= x;
393       width += x;
394       x = 0;
395    }
396    if (y < 0) {
397       yoffset -= y;
398       height += y;
399       y = 0;
400    }
401
402    if (width <= 0 || height <= 0) {
403       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
404       return;
405    }
406
407    if (x > image->width || y > image->width) {
408       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
409       return;
410    }
411
412    if (x + width > image->width) {
413       width = image->width - x;
414    }
415
416    if (y + height > image->height) {
417       height = image->height - y;
418    }
419
420    { /* upload color_data */
421       struct pipe_transfer *transfer = pipe_get_transfer(
422          pipe, texture, 0, 0,
423          PIPE_TRANSFER_WRITE, 0, 0, texture->width0, texture->height0);
424       src += (dataStride * yoffset);
425       for (i = 0; i < height; i++) {
426          _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp);
427          pipe_put_tile_rgba(pipe, transfer, x+image->x, y+image->y, width, 1, df);
428          y += yStep;
429          src += dataStride;
430       }
431       pipe->transfer_destroy(pipe, transfer);
432    }
433 }
434
435 void image_get_sub_data(struct vg_image * image,
436                         void * data,
437                         VGint dataStride,
438                         VGImageFormat dataFormat,
439                         VGint sx, VGint sy,
440                         VGint width, VGint height)
441 {
442    struct vg_context *ctx = vg_current_context();
443    struct pipe_context *pipe = ctx->pipe;
444    VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
445    VGfloat *df = (VGfloat*)temp;
446    VGint y = 0, yStep = 1;
447    VGint i;
448    VGubyte *dst = (VGubyte *)data;
449
450    {
451       struct pipe_transfer *transfer =
452          pipe_get_transfer(pipe,
453                            image->sampler_view->texture,  0, 0,
454                            PIPE_TRANSFER_READ,
455                            0, 0,
456                            image->x + image->width,
457                            image->y + image->height);
458       /* Do a row at a time to flip image data vertically */
459       for (i = 0; i < height; i++) {
460 #if 0
461          debug_printf("%d-%d  == %d\n", sy, height, y);
462 #endif
463          pipe_get_tile_rgba(pipe, transfer, sx+image->x, y, width, 1, df);
464          y += yStep;
465          _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst);
466          dst += dataStride;
467       }
468
469       pipe->transfer_destroy(pipe, transfer);
470    }
471 }
472
473 struct vg_image * image_child_image(struct vg_image *parent,
474                                     VGint x, VGint y,
475                                     VGint width, VGint height)
476 {
477    struct vg_context *ctx = vg_current_context();
478    struct vg_image *image = CALLOC_STRUCT(vg_image);
479
480    vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
481
482    image->x = parent->x + x;
483    image->y = parent->y + y;
484    image->width = width;
485    image->height = height;
486    image->parent = parent;
487    image->sampler_view = NULL;
488    pipe_sampler_view_reference(&image->sampler_view,
489                                parent->sampler_view);
490
491    image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
492    image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
493    image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
494    image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
495    image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
496    image->sampler.normalized_coords = 1;
497
498    if (!parent->children_array)
499       parent->children_array = array_create(
500          sizeof(struct vg_image*));
501
502    array_append_data(parent->children_array,
503                      &image, 1);
504
505    vg_context_add_object(ctx, VG_OBJECT_IMAGE, image);
506
507    return image;
508 }
509
510 void image_copy(struct vg_image *dst, VGint dx, VGint dy,
511                 struct vg_image *src, VGint sx, VGint sy,
512                 VGint width, VGint height,
513                 VGboolean dither)
514 {
515    struct vg_context *ctx = vg_current_context();
516
517    if (width <= 0 || height <= 0) {
518       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
519       return;
520    }
521    vg_copy_texture(ctx, dst->sampler_view->texture, dst->x + dx, dst->y + dy,
522                    src->sampler_view, src->x + sx, src->y + sy, width, height);
523 }
524
525 void image_draw(struct vg_image *img, struct matrix *matrix)
526 {
527    struct vg_context *ctx = vg_current_context();
528    struct matrix paint_matrix;
529    VGfloat x1, y1;
530    VGfloat x2, y2;
531    VGfloat x3, y3;
532    VGfloat x4, y4;
533
534    if (!vg_get_paint_matrix(ctx,
535                             &ctx->state.vg.fill_paint_to_user_matrix,
536                             matrix,
537                             &paint_matrix))
538       return;
539
540    x1 = 0;
541    y1 = 0;
542    x2 = img->width;
543    y2 = 0;
544    x3 = img->width;
545    y3 = img->height;
546    x4 = 0;
547    y4 = img->height;
548
549    shader_set_surface_matrix(ctx->shader, matrix);
550    shader_set_drawing_image(ctx->shader, VG_TRUE);
551    shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
552    shader_set_paint_matrix(ctx->shader, &paint_matrix);
553    shader_set_image(ctx->shader, img);
554    shader_bind(ctx->shader);
555
556    renderer_texture_quad(ctx->renderer, image_texture(img),
557                          img->x, img->y, img->x + img->width, img->y + img->height,
558                          x1, y1, x2, y2, x3, y3, x4, y4);
559 }
560
561 void image_set_pixels(VGint dx, VGint dy,
562                       struct vg_image *src, VGint sx, VGint sy,
563                       VGint width, VGint height)
564 {
565    struct vg_context *ctx = vg_current_context();
566    struct pipe_context *pipe = ctx->pipe;
567    struct pipe_surface *surf, surf_tmpl;
568    struct st_renderbuffer *strb = ctx->draw_buffer->strb;
569
570    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
571    u_surface_default_template(&surf_tmpl, image_texture(src),
572                               0 /* no bind flag - not a surface*/);
573    surf = pipe->create_surface(pipe, image_texture(src), &surf_tmpl);
574
575    vg_copy_surface(ctx, strb->surface, dx, dy,
576                    surf, sx+src->x, sy+src->y, width, height);
577
578    pipe->surface_destroy(pipe, surf);
579 }
580
581 void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy,
582                       VGint sx, VGint sy,
583                       VGint width, VGint height)
584 {
585    struct vg_context *ctx = vg_current_context();
586    struct pipe_context *pipe = ctx->pipe;
587    struct pipe_surface *surf, surf_tmpl;
588    struct st_renderbuffer *strb = ctx->draw_buffer->strb;
589
590    /* flip the y coordinates */
591    /*dy = dst->height - dy - height;*/
592
593    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
594    u_surface_default_template(&surf_tmpl, image_texture(dst),
595                               PIPE_BIND_RENDER_TARGET);
596    surf = pipe->create_surface(pipe, image_texture(dst), &surf_tmpl);
597
598    vg_copy_surface(ctx, surf, dst->x + dx, dst->y + dy,
599                    strb->surface, sx, sy, width, height);
600
601    pipe_surface_reference(&surf, NULL);
602 }
603
604
605 VGboolean vg_image_overlaps(struct vg_image *dst,
606                             struct vg_image *src)
607 {
608    if (dst == src || dst->parent == src ||
609        dst == src->parent)
610       return VG_TRUE;
611    if (dst->parent && dst->parent == src->parent) {
612       VGfloat left1 = dst->x;
613       VGfloat left2 = src->x;
614       VGfloat right1 = dst->x + dst->width;
615       VGfloat right2 = src->x + src->width;
616       VGfloat bottom1 = dst->y;
617       VGfloat bottom2 = src->y;
618       VGfloat top1 = dst->y + dst->height;
619       VGfloat top2 = src->y + src->height;
620
621       return !(left2 > right1 || right2 < left1 ||
622                top2 > bottom1 || bottom2 < top1);
623    }
624    return VG_FALSE;
625 }
626
627 VGint image_bind_samplers(struct vg_image *img, struct pipe_sampler_state **samplers,
628                           struct pipe_sampler_view **sampler_views)
629 {
630    img->sampler.min_img_filter = image_sampler_filter(img->base.ctx);
631    img->sampler.mag_img_filter = image_sampler_filter(img->base.ctx);
632    samplers[3] = &img->sampler;
633    sampler_views[3] = img->sampler_view;
634    return 1;
635 }
636
637 VGint image_sampler_filter(struct vg_context *ctx)
638 {
639     switch(ctx->state.vg.image_quality) {
640     case VG_IMAGE_QUALITY_NONANTIALIASED:
641        return PIPE_TEX_FILTER_NEAREST;
642        break;
643     case VG_IMAGE_QUALITY_FASTER:
644        return PIPE_TEX_FILTER_NEAREST;
645        break;
646     case VG_IMAGE_QUALITY_BETTER:
647        /* possibly use anisotropic filtering */
648        return PIPE_TEX_FILTER_LINEAR;
649        break;
650     default:
651        debug_printf("Unknown image quality");
652     }
653     return PIPE_TEX_FILTER_NEAREST;
654 }