fec473d9d23c3e9ce844eb846a2ef6d5b7bb4969
[profile/ivi/mesa.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 "image.h"
35
36 #include "pipe/p_context.h"
37 #include "pipe/p_screen.h"
38 #include "util/u_inlines.h"
39 #include "util/u_blit.h"
40 #include "util/u_tile.h"
41 #include "util/u_memory.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 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
129 void 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
145 void 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
170 void 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
198 void 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
225 VGImage 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
255 VGImage 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
272 void 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
294 void 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
310 void 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
330 void 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
352 void 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
393 void 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
401    struct st_framebuffer *stfb = ctx->draw_buffer;
402    struct st_renderbuffer *strb = stfb->strb;
403    struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
404
405    VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
406    VGfloat *df = (VGfloat*)temp;
407    VGint y = (fb->height - sy) - 1, yStep = -1;
408    VGint i;
409    VGubyte *dst = (VGubyte *)data;
410    VGint xoffset = 0, yoffset = 0;
411
412    if (!supported_image_format(dataFormat)) {
413       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
414       return;
415    }
416    if (!data || !is_aligned(data)) {
417       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
418       return;
419    }
420    if (width <= 0 || height <= 0) {
421       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
422       return;
423    }
424
425    /* make sure rendering has completed */
426    pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
427    if (sx < 0) {
428       xoffset = -sx;
429       xoffset *= _vega_size_for_format(dataFormat);
430       width += sx;
431       sx = 0;
432    }
433    if (sy < 0) {
434       yoffset = -sy;
435       height += sy;
436       sy = 0;
437       y = (fb->height - sy) - 1;
438       yoffset *= dataStride;
439    }
440
441    {
442       struct pipe_transfer *transfer;
443
444       transfer = pipe->get_tex_transfer(pipe, strb->texture,  0, 0, 0,
445                                           PIPE_TRANSFER_READ,
446                                           0, 0, width, height);
447
448       /* Do a row at a time to flip image data vertically */
449       for (i = 0; i < height; i++) {
450 #if 0
451          debug_printf("%d-%d  == %d\n", sy, height, y);
452 #endif
453          pipe_get_tile_rgba(pipe, transfer, sx, y, width, 1, df);
454          y += yStep;
455          _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
456                                     dst + yoffset + xoffset);
457          dst += dataStride;
458       }
459
460       pipe->tex_transfer_destroy(pipe, transfer);
461    }
462 }
463
464 void vgCopyPixels(VGint dx, VGint dy,
465                   VGint sx, VGint sy,
466                   VGint width, VGint height)
467 {
468    struct vg_context *ctx = vg_current_context();
469    struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
470    struct st_renderbuffer *strb = ctx->draw_buffer->strb;
471
472    if (width <= 0 || height <= 0) {
473       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
474       return;
475    }
476
477    /* do nothing if we copy from outside the fb */
478    if (dx >= (VGint)fb->width || dy >= (VGint)fb->height ||
479        sx >= (VGint)fb->width || sy >= (VGint)fb->height)
480       return;
481
482    vg_validate_state(ctx);
483    /* make sure rendering has completed */
484    vgFinish();
485
486    vg_copy_surface(ctx, strb->surface, dx, dy,
487                    strb->surface, sx, sy, width, height);
488 }