api_images.c revision 4c7001462607e6e99e474d6271dd481d3f8f201c
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
36#include "pipe/p_context.h"
37#include "pipe/p_screen.h"
38#include "util/u_inlines.h"
39#include "util/u_tile.h"
40#include "util/u_math.h"
41
42static INLINE VGboolean supported_image_format(VGImageFormat format)
43{
44   switch(format) {
45   case VG_sRGBX_8888:
46   case VG_sRGBA_8888:
47   case VG_sRGBA_8888_PRE:
48   case VG_sRGB_565:
49   case VG_sRGBA_5551:
50   case VG_sRGBA_4444:
51   case VG_sL_8:
52   case VG_lRGBX_8888:
53   case VG_lRGBA_8888:
54   case VG_lRGBA_8888_PRE:
55   case VG_lL_8:
56   case VG_A_8:
57   case VG_BW_1:
58#ifdef OPENVG_VERSION_1_1
59   case VG_A_1:
60   case VG_A_4:
61#endif
62   case VG_sXRGB_8888:
63   case VG_sARGB_8888:
64   case VG_sARGB_8888_PRE:
65   case VG_sARGB_1555:
66   case VG_sARGB_4444:
67   case VG_lXRGB_8888:
68   case VG_lARGB_8888:
69   case VG_lARGB_8888_PRE:
70   case VG_sBGRX_8888:
71   case VG_sBGRA_8888:
72   case VG_sBGRA_8888_PRE:
73   case VG_sBGR_565:
74   case VG_sBGRA_5551:
75   case VG_sBGRA_4444:
76   case VG_lBGRX_8888:
77   case VG_lBGRA_8888:
78   case VG_lBGRA_8888_PRE:
79   case VG_sXBGR_8888:
80   case VG_sABGR_8888:
81   case VG_sABGR_8888_PRE:
82   case VG_sABGR_1555:
83   case VG_sABGR_4444:
84   case VG_lXBGR_8888:
85   case VG_lABGR_8888:
86   case VG_lABGR_8888_PRE:
87      return VG_TRUE;
88   default:
89      return VG_FALSE;
90   }
91   return VG_FALSE;
92}
93
94VGImage vegaCreateImage(VGImageFormat format,
95                        VGint width, VGint height,
96                        VGbitfield allowedQuality)
97{
98   struct vg_context *ctx = vg_current_context();
99
100   if (!supported_image_format(format)) {
101      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
102      return VG_INVALID_HANDLE;
103   }
104   if (width <= 0 || height <= 0) {
105      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
106      return VG_INVALID_HANDLE;
107   }
108   if (width > vgGeti(VG_MAX_IMAGE_WIDTH) ||
109       height > vgGeti(VG_MAX_IMAGE_HEIGHT)) {
110      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
111      return VG_INVALID_HANDLE;
112   }
113   if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) {
114      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
115      return VG_INVALID_HANDLE;
116   }
117
118   if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED |
119                           VG_IMAGE_QUALITY_FASTER |
120                           VG_IMAGE_QUALITY_BETTER)))) {
121      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
122      return VG_INVALID_HANDLE;
123   }
124
125   return (VGImage)image_create(format, width, height);
126}
127
128void vegaDestroyImage(VGImage image)
129{
130   struct vg_context *ctx = vg_current_context();
131   struct vg_image *img = (struct vg_image *)image;
132
133   if (image == VG_INVALID_HANDLE) {
134      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
135      return;
136   }
137   if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) {
138      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
139      return;
140   }
141   image_destroy(img);
142}
143
144void vegaClearImage(VGImage image,
145                    VGint x, VGint y,
146                    VGint width, VGint height)
147{
148   struct vg_context *ctx = vg_current_context();
149   struct vg_image *img;
150
151   if (image == VG_INVALID_HANDLE) {
152      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
153      return;
154   }
155   if (width <= 0 || height <= 0) {
156      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
157      return;
158   }
159
160   img = (struct vg_image*)image;
161
162   if (x + width < 0 || y + height < 0)
163      return;
164
165   image_clear(img, x, y, width, height);
166
167}
168
169void vegaImageSubData(VGImage image,
170                      const void * data,
171                      VGint dataStride,
172                      VGImageFormat dataFormat,
173                      VGint x, VGint y,
174                      VGint width, VGint height)
175{
176   struct vg_context *ctx = vg_current_context();
177   struct vg_image *img;
178
179   if (image == VG_INVALID_HANDLE) {
180      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
181      return;
182   }
183   if (!supported_image_format(dataFormat)) {
184      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
185      return;
186   }
187   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
188      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
189      return;
190   }
191
192   img = (struct vg_image*)(image);
193   image_sub_data(img, data, dataStride, dataFormat,
194                  x, y, width, height);
195}
196
197void vegaGetImageSubData(VGImage image,
198                         void * data,
199                         VGint dataStride,
200                         VGImageFormat dataFormat,
201                         VGint x, VGint y,
202                         VGint width, VGint height)
203{
204   struct vg_context *ctx = vg_current_context();
205   struct vg_image *img;
206
207   if (image == VG_INVALID_HANDLE) {
208      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
209      return;
210   }
211   if (!supported_image_format(dataFormat)) {
212      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
213      return;
214   }
215   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
216      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
217      return;
218   }
219   img = (struct vg_image*)image;
220   image_get_sub_data(img, data, dataStride, dataFormat,
221                      x, y, width, height);
222}
223
224VGImage vegaChildImage(VGImage parent,
225                       VGint x, VGint y,
226                       VGint width, VGint height)
227{
228   struct vg_context *ctx = vg_current_context();
229   struct vg_image *p;
230
231   if (parent == VG_INVALID_HANDLE ||
232       !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) ||
233       !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) {
234      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
235      return VG_INVALID_HANDLE;
236   }
237   if (width <= 0 || height <= 0 || x < 0 || y < 0) {
238      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
239      return VG_INVALID_HANDLE;
240   }
241   p = (struct vg_image *)parent;
242   if (x > p->width  || y > p->height) {
243      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
244      return VG_INVALID_HANDLE;
245   }
246   if (x + width > p->width  || y + height > p->height) {
247      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
248      return VG_INVALID_HANDLE;
249   }
250
251   return (VGImage)image_child_image(p, x, y, width, height);
252}
253
254VGImage vegaGetParent(VGImage image)
255{
256   struct vg_context *ctx = vg_current_context();
257   struct vg_image *img;
258
259   if (image == VG_INVALID_HANDLE) {
260      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
261      return VG_INVALID_HANDLE;
262   }
263
264   img = (struct vg_image*)image;
265   if (img->parent)
266      return (VGImage)img->parent;
267   else
268      return image;
269}
270
271void vegaCopyImage(VGImage dst, VGint dx, VGint dy,
272                   VGImage src, VGint sx, VGint sy,
273                   VGint width, VGint height,
274                   VGboolean dither)
275{
276   struct vg_context *ctx = vg_current_context();
277
278   if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) {
279      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
280      return;
281   }
282
283   if (width <= 0 || height <= 0) {
284      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
285      return;
286   }
287   vg_validate_state(ctx);
288   image_copy((struct vg_image*)dst, dx, dy,
289              (struct vg_image*)src, sx, sy,
290              width, height, dither);
291}
292
293void vegaDrawImage(VGImage image)
294{
295   struct vg_context *ctx = vg_current_context();
296
297   if (!ctx)
298      return;
299
300   if (image == VG_INVALID_HANDLE) {
301      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
302      return;
303   }
304
305   vg_validate_state(ctx);
306   image_draw((struct vg_image*)image,
307         &ctx->state.vg.image_user_to_surface_matrix);
308}
309
310void vegaSetPixels(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 vegaGetPixels(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 vegaWritePixels(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 vegaReadPixels(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
404   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
405   VGfloat *df = (VGfloat*)temp;
406   VGint i;
407   VGubyte *dst = (VGubyte *)data;
408   VGint xoffset = 0, yoffset = 0;
409
410   if (!supported_image_format(dataFormat)) {
411      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
412      return;
413   }
414   if (!data || !is_aligned(data)) {
415      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
416      return;
417   }
418   if (width <= 0 || height <= 0) {
419      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
420      return;
421   }
422
423   /* make sure rendering has completed */
424   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
425   if (sx < 0) {
426      xoffset = -sx;
427      xoffset *= _vega_size_for_format(dataFormat);
428      width += sx;
429      sx = 0;
430   }
431   if (sy < 0) {
432      yoffset = -sy;
433      yoffset *= dataStride;
434      height += sy;
435      sy = 0;
436   }
437
438   if (sx + width > stfb->width || sy + height > stfb->height) {
439      width = stfb->width - sx;
440      height = stfb->height - sy;
441      /* nothing to read */
442      if (width <= 0 || height <= 0)
443         return;
444   }
445
446   {
447      VGint y = (stfb->height - sy) - 1, yStep = -1;
448      struct pipe_transfer *transfer;
449
450      transfer = pipe_get_transfer(pipe, strb->texture,  0, 0,
451                                   PIPE_TRANSFER_READ,
452                                   0, 0, sx + width, stfb->height - sy);
453
454      /* Do a row at a time to flip image data vertically */
455      for (i = 0; i < height; i++) {
456#if 0
457         debug_printf("%d-%d  == %d\n", sy, height, y);
458#endif
459         pipe_get_tile_rgba(pipe, transfer, sx, y, width, 1, df);
460         y += yStep;
461         _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
462                                    dst + yoffset + xoffset);
463         dst += dataStride;
464      }
465
466      pipe->transfer_destroy(pipe, transfer);
467   }
468}
469
470void vegaCopyPixels(VGint dx, VGint dy,
471                    VGint sx, VGint sy,
472                    VGint width, VGint height)
473{
474   struct vg_context *ctx = vg_current_context();
475   struct st_framebuffer *stfb = ctx->draw_buffer;
476   struct st_renderbuffer *strb = stfb->strb;
477
478   if (width <= 0 || height <= 0) {
479      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
480      return;
481   }
482
483   /* do nothing if we copy from outside the fb */
484   if (dx >= (VGint)stfb->width || dy >= (VGint)stfb->height ||
485       sx >= (VGint)stfb->width || sy >= (VGint)stfb->height)
486      return;
487
488   vg_validate_state(ctx);
489   /* make sure rendering has completed */
490   vgFinish();
491
492   vg_copy_surface(ctx, strb->surface, dx, dy,
493                   strb->surface, sx, sy, width, height);
494}
495