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 "api.h" 35 #include "handle.h" 36 37 #include "pipe/p_context.h" 38 #include "pipe/p_screen.h" 39 #include "util/u_inlines.h" 40 #include "util/u_tile.h" 41 #include "util/u_math.h" 42 43 static 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 95 VGImage vegaCreateImage(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 > vegaGeti(VG_MAX_IMAGE_WIDTH) || 110 height > vegaGeti(VG_MAX_IMAGE_HEIGHT)) { 111 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 112 return VG_INVALID_HANDLE; 113 } 114 if (width * height > vegaGeti(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 image_to_handle(image_create(format, width, height)); 127 } 128 129 void vegaDestroyImage(VGImage image) 130 { 131 struct vg_context *ctx = vg_current_context(); 132 struct vg_image *img = handle_to_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(image, VG_OBJECT_IMAGE)) { 139 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 140 return; 141 } 142 image_destroy(img); 143 } 144 145 void vegaClearImage(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 = handle_to_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 170 void vegaImageSubData(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 = handle_to_image(image); 194 image_sub_data(img, data, dataStride, dataFormat, 195 x, y, width, height); 196 } 197 198 void vegaGetImageSubData(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 = handle_to_image(image); 221 image_get_sub_data(img, data, dataStride, dataFormat, 222 x, y, width, height); 223 } 224 225 VGImage vegaChildImage(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, parent) || 234 !vg_object_is_valid(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 = handle_to_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 image_to_handle(image_child_image(p, x, y, width, height)); 253 } 254 255 VGImage vegaGetParent(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 = handle_to_image(image); 266 if (img->parent) 267 return image_to_handle(img->parent); 268 else 269 return image; 270 } 271 272 void vegaCopyImage(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(handle_to_image(dst), dx, dy, 290 handle_to_image(src), sx, sy, 291 width, height, dither); 292 } 293 294 void vegaDrawImage(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(handle_to_image(image), 308 &ctx->state.vg.image_user_to_surface_matrix); 309 } 310 311 void vegaSetPixels(VGint dx, VGint dy, 312 VGImage src, VGint sx, VGint sy, 313 VGint width, VGint height) 314 { 315 struct vg_context *ctx = vg_current_context(); 316 317 vg_validate_state(ctx); 318 319 if (src == VG_INVALID_HANDLE) { 320 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 321 return; 322 } 323 if (width <= 0 || height <= 0) { 324 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 325 return; 326 } 327 image_set_pixels(dx, dy, handle_to_image(src), sx, sy, width, 328 height); 329 } 330 331 void vegaGetPixels(VGImage dst, VGint dx, VGint dy, 332 VGint sx, VGint sy, 333 VGint width, VGint height) 334 { 335 struct vg_context *ctx = vg_current_context(); 336 struct vg_image *img; 337 338 if (dst == VG_INVALID_HANDLE) { 339 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 340 return; 341 } 342 if (width <= 0 || height <= 0) { 343 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 344 return; 345 } 346 347 img = handle_to_image(dst); 348 349 image_get_pixels(img, dx, dy, 350 sx, sy, width, height); 351 } 352 353 void vegaWritePixels(const void * data, VGint dataStride, 354 VGImageFormat dataFormat, 355 VGint dx, VGint dy, 356 VGint width, VGint height) 357 { 358 struct vg_context *ctx = vg_current_context(); 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 } 390 391 void vegaReadPixels(void * data, VGint dataStride, 392 VGImageFormat dataFormat, 393 VGint sx, VGint sy, 394 VGint width, VGint height) 395 { 396 struct vg_context *ctx = vg_current_context(); 397 struct pipe_context *pipe = ctx->pipe; 398 399 struct st_framebuffer *stfb = ctx->draw_buffer; 400 struct st_renderbuffer *strb = stfb->strb; 401 402 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; 403 VGfloat *df = (VGfloat*)temp; 404 VGint i; 405 VGubyte *dst = (VGubyte *)data; 406 VGint xoffset = 0, yoffset = 0; 407 408 if (!supported_image_format(dataFormat)) { 409 vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); 410 return; 411 } 412 if (!data || !is_aligned(data)) { 413 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 414 return; 415 } 416 if (width <= 0 || height <= 0) { 417 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 418 return; 419 } 420 421 if (sx < 0) { 422 xoffset = -sx; 423 xoffset *= _vega_size_for_format(dataFormat); 424 width += sx; 425 sx = 0; 426 } 427 if (sy < 0) { 428 yoffset = -sy; 429 yoffset *= dataStride; 430 height += sy; 431 sy = 0; 432 } 433 434 if (sx + width > stfb->width || sy + height > stfb->height) { 435 width = stfb->width - sx; 436 height = stfb->height - sy; 437 /* nothing to read */ 438 if (width <= 0 || height <= 0) 439 return; 440 } 441 442 { 443 VGint y = (stfb->height - sy) - 1, yStep = -1; 444 struct pipe_transfer *transfer; 445 446 transfer = pipe_get_transfer(pipe, strb->texture, 0, 0, 447 PIPE_TRANSFER_READ, 448 0, 0, sx + width, stfb->height - sy); 449 450 /* Do a row at a time to flip image data vertically */ 451 for (i = 0; i < height; i++) { 452 #if 0 453 debug_printf("%d-%d == %d\n", sy, height, y); 454 #endif 455 pipe_get_tile_rgba(pipe, transfer, sx, y, width, 1, df); 456 y += yStep; 457 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, 458 dst + yoffset + xoffset); 459 dst += dataStride; 460 } 461 462 pipe->transfer_destroy(pipe, transfer); 463 } 464 } 465 466 void vegaCopyPixels(VGint dx, VGint dy, 467 VGint sx, VGint sy, 468 VGint width, VGint height) 469 { 470 struct vg_context *ctx = vg_current_context(); 471 struct st_framebuffer *stfb = ctx->draw_buffer; 472 struct st_renderbuffer *strb = stfb->strb; 473 474 if (width <= 0 || height <= 0) { 475 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 476 return; 477 } 478 479 /* do nothing if we copy from outside the fb */ 480 if (dx >= (VGint)stfb->width || dy >= (VGint)stfb->height || 481 sx >= (VGint)stfb->width || sy >= (VGint)stfb->height) 482 return; 483 484 vg_validate_state(ctx); 485 /* make sure rendering has completed */ 486 vegaFinish(); 487 488 vg_copy_surface(ctx, strb->surface, dx, dy, 489 strb->surface, sx, sy, width, height); 490 } 491