Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / state_trackers / vega / api_images.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/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 }