image.c revision a84a1e344f544ec4da61809d4f09853a94d93e07
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 47static 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 73static 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 81static 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 117static 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 155void 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 207static 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 214static 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 234struct 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, 0)); 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 296void 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 pipe_sampler_view_reference(&img->sampler_view, NULL); 353 FREE(img); 354} 355 356void image_clear(struct vg_image *img, 357 VGint x, VGint y, VGint width, VGint height) 358{ 359 struct vg_context *ctx = vg_current_context(); 360 VGfloat *clear_colorf = ctx->state.vg.clear_color; 361 VGubyte r, g, b ,a; 362 VGint clear_colori; 363 /* FIXME: this is very nasty */ 364 r = float_to_ubyte(clear_colorf[0]); 365 g = float_to_ubyte(clear_colorf[1]); 366 b = float_to_ubyte(clear_colorf[2]); 367 a = float_to_ubyte(clear_colorf[3]); 368 clear_colori = r << 24 | g << 16 | b << 8 | a; 369 image_cleari(img, clear_colori, x, y, width, height); 370} 371 372void image_sub_data(struct vg_image *image, 373 const void * data, 374 VGint dataStride, 375 VGImageFormat dataFormat, 376 VGint x, VGint y, 377 VGint width, VGint height) 378{ 379 const VGint yStep = 1; 380 VGubyte *src = (VGubyte *)data; 381 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; 382 VGfloat *df = (VGfloat*)temp; 383 VGint i; 384 struct vg_context *ctx = vg_current_context(); 385 struct pipe_context *pipe = ctx->pipe; 386 struct pipe_resource *texture = image_texture(image); 387 VGint xoffset = 0, yoffset = 0; 388 389 if (x < 0) { 390 xoffset -= x; 391 width += x; 392 x = 0; 393 } 394 if (y < 0) { 395 yoffset -= y; 396 height += y; 397 y = 0; 398 } 399 400 if (width <= 0 || height <= 0) { 401 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 402 return; 403 } 404 405 if (x > image->width || y > image->width) { 406 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 407 return; 408 } 409 410 if (x + width > image->width) { 411 width = image->width - x; 412 } 413 414 if (y + height > image->height) { 415 height = image->height - y; 416 } 417 418 { /* upload color_data */ 419 struct pipe_transfer *transfer = pipe_get_transfer( 420 pipe, texture, 0, 0, 421 PIPE_TRANSFER_WRITE, 0, 0, texture->width0, texture->height0); 422 src += (dataStride * yoffset); 423 for (i = 0; i < height; i++) { 424 _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp); 425 pipe_put_tile_rgba(pipe, transfer, x+image->x, y+image->y, width, 1, df); 426 y += yStep; 427 src += dataStride; 428 } 429 pipe->transfer_destroy(pipe, transfer); 430 } 431} 432 433void image_get_sub_data(struct vg_image * image, 434 void * data, 435 VGint dataStride, 436 VGImageFormat dataFormat, 437 VGint sx, VGint sy, 438 VGint width, VGint height) 439{ 440 struct vg_context *ctx = vg_current_context(); 441 struct pipe_context *pipe = ctx->pipe; 442 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; 443 VGfloat *df = (VGfloat*)temp; 444 VGint y = 0, yStep = 1; 445 VGint i; 446 VGubyte *dst = (VGubyte *)data; 447 448 { 449 struct pipe_transfer *transfer = 450 pipe_get_transfer(pipe, 451 image->sampler_view->texture, 0, 0, 452 PIPE_TRANSFER_READ, 453 0, 0, 454 image->x + image->width, 455 image->y + image->height); 456 /* Do a row at a time to flip image data vertically */ 457 for (i = 0; i < height; i++) { 458#if 0 459 debug_printf("%d-%d == %d\n", sy, height, y); 460#endif 461 pipe_get_tile_rgba(pipe, transfer, sx+image->x, y, width, 1, df); 462 y += yStep; 463 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst); 464 dst += dataStride; 465 } 466 467 pipe->transfer_destroy(pipe, transfer); 468 } 469} 470 471struct vg_image * image_child_image(struct vg_image *parent, 472 VGint x, VGint y, 473 VGint width, VGint height) 474{ 475 struct vg_context *ctx = vg_current_context(); 476 struct vg_image *image = CALLOC_STRUCT(vg_image); 477 478 vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE); 479 480 image->x = parent->x + x; 481 image->y = parent->y + y; 482 image->width = width; 483 image->height = height; 484 image->parent = parent; 485 image->sampler_view = NULL; 486 pipe_sampler_view_reference(&image->sampler_view, 487 parent->sampler_view); 488 489 image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 490 image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 491 image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 492 image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 493 image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; 494 image->sampler.normalized_coords = 1; 495 496 if (!parent->children_array) 497 parent->children_array = array_create( 498 sizeof(struct vg_image*)); 499 500 array_append_data(parent->children_array, 501 &image, 1); 502 503 vg_context_add_object(ctx, VG_OBJECT_IMAGE, image); 504 505 return image; 506} 507 508void image_copy(struct vg_image *dst, VGint dx, VGint dy, 509 struct vg_image *src, VGint sx, VGint sy, 510 VGint width, VGint height, 511 VGboolean dither) 512{ 513 struct vg_context *ctx = vg_current_context(); 514 515 if (width <= 0 || height <= 0) { 516 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 517 return; 518 } 519 /* make sure rendering has completed */ 520 ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 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 525void 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 561void 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 /* make sure rendering has completed */ 571 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 572 573 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 574 u_surface_default_template(&surf_tmpl, image_texture(src), 575 0 /* no bind flag - not a surface*/); 576 surf = pipe->create_surface(pipe, image_texture(src), &surf_tmpl); 577 578 vg_copy_surface(ctx, strb->surface, dx, dy, 579 surf, sx+src->x, sy+src->y, width, height); 580 581 pipe->surface_destroy(pipe, surf); 582} 583 584void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, 585 VGint sx, VGint sy, 586 VGint width, VGint height) 587{ 588 struct vg_context *ctx = vg_current_context(); 589 struct pipe_context *pipe = ctx->pipe; 590 struct pipe_surface *surf, surf_tmpl; 591 struct st_renderbuffer *strb = ctx->draw_buffer->strb; 592 593 /* flip the y coordinates */ 594 /*dy = dst->height - dy - height;*/ 595 596 /* make sure rendering has completed */ 597 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 598 599 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 600 u_surface_default_template(&surf_tmpl, image_texture(dst), 601 PIPE_BIND_RENDER_TARGET); 602 surf = pipe->create_surface(pipe, image_texture(dst), &surf_tmpl); 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 611VGboolean 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 633VGint 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 643VGint 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} 661