api_images.c revision 544dd4b11f7be76bb00fe29a60eaf2772dcc69ca
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/openvg.h" 30 31#include "vg_context.h" 32#include "vg_translate.h" 33#include "api_consts.h" 34#include "image.h" 35 36#include "pipe/p_context.h" 37#include "pipe/p_screen.h" 38#include "pipe/p_inlines.h" 39#include "util/u_blit.h" 40#include "util/u_tile.h" 41#include "util/u_memory.h" 42 43static INLINE VGboolean supported_image_format(VGImageFormat format) 44{ 45 switch(format) { 46 case VG_sRGBX_8888: 47 case VG_sRGBA_8888: 48 case VG_sRGBA_8888_PRE: 49 case VG_sRGB_565: 50 case VG_sRGBA_5551: 51 case VG_sRGBA_4444: 52 case VG_sL_8: 53 case VG_lRGBX_8888: 54 case VG_lRGBA_8888: 55 case VG_lRGBA_8888_PRE: 56 case VG_lL_8: 57 case VG_A_8: 58 case VG_BW_1: 59#ifdef OPENVG_VERSION_1_1 60 case VG_A_1: 61 case VG_A_4: 62#endif 63 case VG_sXRGB_8888: 64 case VG_sARGB_8888: 65 case VG_sARGB_8888_PRE: 66 case VG_sARGB_1555: 67 case VG_sARGB_4444: 68 case VG_lXRGB_8888: 69 case VG_lARGB_8888: 70 case VG_lARGB_8888_PRE: 71 case VG_sBGRX_8888: 72 case VG_sBGRA_8888: 73 case VG_sBGRA_8888_PRE: 74 case VG_sBGR_565: 75 case VG_sBGRA_5551: 76 case VG_sBGRA_4444: 77 case VG_lBGRX_8888: 78 case VG_lBGRA_8888: 79 case VG_lBGRA_8888_PRE: 80 case VG_sXBGR_8888: 81 case VG_sABGR_8888: 82 case VG_sABGR_8888_PRE: 83 case VG_sABGR_1555: 84 case VG_sABGR_4444: 85 case VG_lXBGR_8888: 86 case VG_lABGR_8888: 87 case VG_lABGR_8888_PRE: 88 return VG_TRUE; 89 default: 90 return VG_FALSE; 91 } 92 return VG_FALSE; 93} 94 95VGImage vgCreateImage(VGImageFormat format, 96 VGint width, VGint height, 97 VGbitfield allowedQuality) 98{ 99 struct vg_context *ctx = vg_current_context(); 100 101 if (!supported_image_format(format)) { 102 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 103 return VG_INVALID_HANDLE; 104 } 105 if (width <= 0 || height <= 0) { 106 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 107 return VG_INVALID_HANDLE; 108 } 109 if (width > vgGeti(VG_MAX_IMAGE_WIDTH) || 110 height > vgGeti(VG_MAX_IMAGE_HEIGHT)) { 111 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 112 return VG_INVALID_HANDLE; 113 } 114 if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) { 115 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 116 return VG_INVALID_HANDLE; 117 } 118 119 if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED | 120 VG_IMAGE_QUALITY_FASTER | 121 VG_IMAGE_QUALITY_BETTER)))) { 122 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 123 return VG_INVALID_HANDLE; 124 } 125 126 return (VGImage)image_create(format, width, height); 127} 128 129void vgDestroyImage(VGImage image) 130{ 131 struct vg_context *ctx = vg_current_context(); 132 struct vg_image *img = (struct vg_image *)image; 133 134 if (image == VG_INVALID_HANDLE) { 135 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 136 return; 137 } 138 if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) { 139 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 140 return; 141 } 142 image_destroy(img); 143} 144 145void vgClearImage(VGImage image, 146 VGint x, VGint y, 147 VGint width, VGint height) 148{ 149 struct vg_context *ctx = vg_current_context(); 150 struct vg_image *img; 151 152 if (image == VG_INVALID_HANDLE) { 153 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 154 return; 155 } 156 if (width <= 0 || height <= 0) { 157 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 158 return; 159 } 160 161 img = (struct vg_image*)image; 162 163 if (x + width < 0 || y + height < 0) 164 return; 165 166 image_clear(img, x, y, width, height); 167 168} 169 170void vgImageSubData(VGImage image, 171 const void * data, 172 VGint dataStride, 173 VGImageFormat dataFormat, 174 VGint x, VGint y, 175 VGint width, VGint height) 176{ 177 struct vg_context *ctx = vg_current_context(); 178 struct vg_image *img; 179 180 if (image == VG_INVALID_HANDLE) { 181 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 182 return; 183 } 184 if (!supported_image_format(dataFormat)) { 185 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 186 return; 187 } 188 if (width <= 0 || height <= 0 || !data || !is_aligned(data)) { 189 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 190 return; 191 } 192 193 img = (struct vg_image*)(image); 194 image_sub_data(img, data, dataStride, dataFormat, 195 x, y, width, height); 196} 197 198void vgGetImageSubData(VGImage image, 199 void * data, 200 VGint dataStride, 201 VGImageFormat dataFormat, 202 VGint x, VGint y, 203 VGint width, VGint height) 204{ 205 struct vg_context *ctx = vg_current_context(); 206 struct vg_image *img; 207 208 if (image == VG_INVALID_HANDLE) { 209 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 210 return; 211 } 212 if (!supported_image_format(dataFormat)) { 213 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 214 return; 215 } 216 if (width <= 0 || height <= 0 || !data || !is_aligned(data)) { 217 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 218 return; 219 } 220 img = (struct vg_image*)image; 221 image_get_sub_data(img, data, dataStride, dataFormat, 222 x, y, width, height); 223} 224 225VGImage vgChildImage(VGImage parent, 226 VGint x, VGint y, 227 VGint width, VGint height) 228{ 229 struct vg_context *ctx = vg_current_context(); 230 struct vg_image *p; 231 232 if (parent == VG_INVALID_HANDLE || 233 !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) || 234 !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) { 235 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 236 return VG_INVALID_HANDLE; 237 } 238 if (width <= 0 || height <= 0 || x < 0 || y < 0) { 239 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 240 return VG_INVALID_HANDLE; 241 } 242 p = (struct vg_image *)parent; 243 if (x > p->width || y > p->height) { 244 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 245 return VG_INVALID_HANDLE; 246 } 247 if (x + width > p->width || y + height > p->height) { 248 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 249 return VG_INVALID_HANDLE; 250 } 251 252 return (VGImage)image_child_image(p, x, y, width, height); 253} 254 255VGImage vgGetParent(VGImage image) 256{ 257 struct vg_context *ctx = vg_current_context(); 258 struct vg_image *img; 259 260 if (image == VG_INVALID_HANDLE) { 261 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 262 return VG_INVALID_HANDLE; 263 } 264 265 img = (struct vg_image*)image; 266 if (img->parent) 267 return (VGImage)img->parent; 268 else 269 return image; 270} 271 272void vgCopyImage(VGImage dst, VGint dx, VGint dy, 273 VGImage src, VGint sx, VGint sy, 274 VGint width, VGint height, 275 VGboolean dither) 276{ 277 struct vg_context *ctx = vg_current_context(); 278 279 if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) { 280 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 281 return; 282 } 283 284 if (width <= 0 || height <= 0) { 285 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 286 return; 287 } 288 vg_validate_state(ctx); 289 image_copy((struct vg_image*)dst, dx, dy, 290 (struct vg_image*)src, sx, sy, 291 width, height, dither); 292} 293 294void vgDrawImage(VGImage image) 295{ 296 struct vg_context *ctx = vg_current_context(); 297 298 if (!ctx) 299 return; 300 301 if (image == VG_INVALID_HANDLE) { 302 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 303 return; 304 } 305 306 vg_validate_state(ctx); 307 image_draw((struct vg_image*)image); 308} 309 310void vgSetPixels(VGint dx, VGint dy, 311 VGImage src, VGint sx, VGint sy, 312 VGint width, VGint height) 313{ 314 struct vg_context *ctx = vg_current_context(); 315 316 vg_validate_state(ctx); 317 318 if (src == VG_INVALID_HANDLE) { 319 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 320 return; 321 } 322 if (width <= 0 || height <= 0) { 323 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 324 return; 325 } 326 image_set_pixels(dx, dy, (struct vg_image*)src, sx, sy, width, 327 height); 328} 329 330void vgGetPixels(VGImage dst, VGint dx, VGint dy, 331 VGint sx, VGint sy, 332 VGint width, VGint height) 333{ 334 struct vg_context *ctx = vg_current_context(); 335 struct vg_image *img; 336 337 if (dst == VG_INVALID_HANDLE) { 338 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 339 return; 340 } 341 if (width <= 0 || height <= 0) { 342 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 343 return; 344 } 345 346 img = (struct vg_image*)dst; 347 348 image_get_pixels(img, dx, dy, 349 sx, sy, width, height); 350} 351 352void vgWritePixels(const void * data, VGint dataStride, 353 VGImageFormat dataFormat, 354 VGint dx, VGint dy, 355 VGint width, VGint height) 356{ 357 struct vg_context *ctx = vg_current_context(); 358 struct pipe_context *pipe = ctx->pipe; 359 360 if (!supported_image_format(dataFormat)) { 361 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 362 return; 363 } 364 if (!data || !is_aligned(data)) { 365 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 366 return; 367 } 368 if (width <= 0 || height <= 0) { 369 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 370 return; 371 } 372 373 vg_validate_state(ctx); 374 { 375 struct vg_image *img = image_create(dataFormat, width, height); 376 image_sub_data(img, data, dataStride, dataFormat, 0, 0, 377 width, height); 378#if 0 379 struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix; 380 matrix_translate(matrix, dx, dy); 381 image_draw(img); 382 matrix_translate(matrix, -dx, -dy); 383#else 384 /* this looks like a better approach */ 385 image_set_pixels(dx, dy, img, 0, 0, width, height); 386#endif 387 image_destroy(img); 388 } 389 /* make sure rendering has completed */ 390 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 391} 392 393void vgReadPixels(void * data, VGint dataStride, 394 VGImageFormat dataFormat, 395 VGint sx, VGint sy, 396 VGint width, VGint height) 397{ 398 struct vg_context *ctx = vg_current_context(); 399 struct pipe_context *pipe = ctx->pipe; 400 struct pipe_screen *screen = pipe->screen; 401 402 struct st_framebuffer *stfb = ctx->draw_buffer; 403 struct st_renderbuffer *strb = stfb->strb; 404 struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; 405 406 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; 407 VGfloat *df = (VGfloat*)temp; 408 VGint y = (fb->height - sy) - 1, yStep = -1; 409 VGint i; 410 VGubyte *dst = (VGubyte *)data; 411 VGint xoffset = 0, yoffset = 0; 412 413 if (!supported_image_format(dataFormat)) { 414 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 415 return; 416 } 417 if (!data || !is_aligned(data)) { 418 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 419 return; 420 } 421 if (width <= 0 || height <= 0) { 422 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 423 return; 424 } 425 426 /* make sure rendering has completed */ 427 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); 428 if (sx < 0) { 429 xoffset = -sx; 430 xoffset *= _vega_size_for_format(dataFormat); 431 width += sx; 432 sx = 0; 433 } 434 if (sy < 0) { 435 yoffset = -sy; 436 height += sy; 437 sy = 0; 438 y = (fb->height - sy) - 1; 439 yoffset *= dataStride; 440 } 441 442 { 443 struct pipe_transfer *transfer; 444 445 transfer = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0, 446 PIPE_TRANSFER_READ, 447 0, 0, width, height); 448 449 /* Do a row at a time to flip image data vertically */ 450 for (i = 0; i < height; i++) { 451#if 0 452 debug_printf("%d-%d == %d\n", sy, height, y); 453#endif 454 pipe_get_tile_rgba(transfer, sx, y, width, 1, df); 455 y += yStep; 456 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, 457 dst + yoffset + xoffset); 458 dst += dataStride; 459 } 460 461 screen->tex_transfer_destroy(transfer); 462 } 463} 464 465void vgCopyPixels(VGint dx, VGint dy, 466 VGint sx, VGint sy, 467 VGint width, VGint height) 468{ 469 struct vg_context *ctx = vg_current_context(); 470 struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; 471 struct st_renderbuffer *strb = ctx->draw_buffer->strb; 472 473 if (width <= 0 || height <= 0) { 474 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 475 return; 476 } 477 478 /* do nothing if we copy from outside the fb */ 479 if (dx >= (VGint)fb->width || dy >= (VGint)fb->height || 480 sx >= (VGint)fb->width || sy >= (VGint)fb->height) 481 return; 482 483 vg_validate_state(ctx); 484 /* make sure rendering has completed */ 485 vgFinish(); 486 487 vg_copy_surface(ctx, strb->surface, dx, dy, 488 strb->surface, sx, sy, width, height); 489} 490