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