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
supported_image_format(VGImageFormat format)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
vegaCreateImage(VGImageFormat format,VGint width,VGint height,VGbitfield allowedQuality)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
vegaDestroyImage(VGImage image)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
vegaClearImage(VGImage image,VGint x,VGint y,VGint width,VGint height)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
vegaImageSubData(VGImage image,const void * data,VGint dataStride,VGImageFormat dataFormat,VGint x,VGint y,VGint width,VGint height)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
vegaGetImageSubData(VGImage image,void * data,VGint dataStride,VGImageFormat dataFormat,VGint x,VGint y,VGint width,VGint height)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
vegaChildImage(VGImage parent,VGint x,VGint y,VGint width,VGint height)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
vegaGetParent(VGImage image)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
vegaCopyImage(VGImage dst,VGint dx,VGint dy,VGImage src,VGint sx,VGint sy,VGint width,VGint height,VGboolean dither)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
vegaDrawImage(VGImage image)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
vegaSetPixels(VGint dx,VGint dy,VGImage src,VGint sx,VGint sy,VGint width,VGint height)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
vegaGetPixels(VGImage dst,VGint dx,VGint dy,VGint sx,VGint sy,VGint width,VGint height)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
vegaWritePixels(const void * data,VGint dataStride,VGImageFormat dataFormat,VGint dx,VGint dy,VGint width,VGint height)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
vegaReadPixels(void * data,VGint dataStride,VGImageFormat dataFormat,VGint sx,VGint sy,VGint width,VGint height)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
vegaCopyPixels(VGint dx,VGint dy,VGint sx,VGint sy,VGint width,VGint height)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