api_images.c revision 93a7e6d94e09a25bdbe31eedb0759e390ccb6a86
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
41static INLINE VGboolean supported_image_format(VGImageFormat format)
42{
43   switch(format) {
44   case VG_sRGBX_8888:
45   case VG_sRGBA_8888:
46   case VG_sRGBA_8888_PRE:
47   case VG_sRGB_565:
48   case VG_sRGBA_5551:
49   case VG_sRGBA_4444:
50   case VG_sL_8:
51   case VG_lRGBX_8888:
52   case VG_lRGBA_8888:
53   case VG_lRGBA_8888_PRE:
54   case VG_lL_8:
55   case VG_A_8:
56   case VG_BW_1:
57#ifdef OPENVG_VERSION_1_1
58   case VG_A_1:
59   case VG_A_4:
60#endif
61   case VG_sXRGB_8888:
62   case VG_sARGB_8888:
63   case VG_sARGB_8888_PRE:
64   case VG_sARGB_1555:
65   case VG_sARGB_4444:
66   case VG_lXRGB_8888:
67   case VG_lARGB_8888:
68   case VG_lARGB_8888_PRE:
69   case VG_sBGRX_8888:
70   case VG_sBGRA_8888:
71   case VG_sBGRA_8888_PRE:
72   case VG_sBGR_565:
73   case VG_sBGRA_5551:
74   case VG_sBGRA_4444:
75   case VG_lBGRX_8888:
76   case VG_lBGRA_8888:
77   case VG_lBGRA_8888_PRE:
78   case VG_sXBGR_8888:
79   case VG_sABGR_8888:
80   case VG_sABGR_8888_PRE:
81   case VG_sABGR_1555:
82   case VG_sABGR_4444:
83   case VG_lXBGR_8888:
84   case VG_lABGR_8888:
85   case VG_lABGR_8888_PRE:
86      return VG_TRUE;
87   default:
88      return VG_FALSE;
89   }
90   return VG_FALSE;
91}
92
93VGImage vegaCreateImage(VGImageFormat format,
94                        VGint width, VGint height,
95                        VGbitfield allowedQuality)
96{
97   struct vg_context *ctx = vg_current_context();
98
99   if (!supported_image_format(format)) {
100      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
101      return VG_INVALID_HANDLE;
102   }
103   if (width <= 0 || height <= 0) {
104      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
105      return VG_INVALID_HANDLE;
106   }
107   if (width > vgGeti(VG_MAX_IMAGE_WIDTH) ||
108       height > vgGeti(VG_MAX_IMAGE_HEIGHT)) {
109      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
110      return VG_INVALID_HANDLE;
111   }
112   if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) {
113      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
114      return VG_INVALID_HANDLE;
115   }
116
117   if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED |
118                           VG_IMAGE_QUALITY_FASTER |
119                           VG_IMAGE_QUALITY_BETTER)))) {
120      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
121      return VG_INVALID_HANDLE;
122   }
123
124   return (VGImage)image_create(format, width, height);
125}
126
127void vegaDestroyImage(VGImage image)
128{
129   struct vg_context *ctx = vg_current_context();
130   struct vg_image *img = (struct vg_image *)image;
131
132   if (image == VG_INVALID_HANDLE) {
133      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
134      return;
135   }
136   if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) {
137      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
138      return;
139   }
140   image_destroy(img);
141}
142
143void vegaClearImage(VGImage image,
144                    VGint x, VGint y,
145                    VGint width, VGint height)
146{
147   struct vg_context *ctx = vg_current_context();
148   struct vg_image *img;
149
150   if (image == VG_INVALID_HANDLE) {
151      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
152      return;
153   }
154   if (width <= 0 || height <= 0) {
155      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
156      return;
157   }
158
159   img = (struct vg_image*)image;
160
161   if (x + width < 0 || y + height < 0)
162      return;
163
164   image_clear(img, x, y, width, height);
165
166}
167
168void vegaImageSubData(VGImage image,
169                      const void * data,
170                      VGint dataStride,
171                      VGImageFormat dataFormat,
172                      VGint x, VGint y,
173                      VGint width, VGint height)
174{
175   struct vg_context *ctx = vg_current_context();
176   struct vg_image *img;
177
178   if (image == VG_INVALID_HANDLE) {
179      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
180      return;
181   }
182   if (!supported_image_format(dataFormat)) {
183      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
184      return;
185   }
186   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
187      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
188      return;
189   }
190
191   img = (struct vg_image*)(image);
192   image_sub_data(img, data, dataStride, dataFormat,
193                  x, y, width, height);
194}
195
196void vegaGetImageSubData(VGImage image,
197                         void * data,
198                         VGint dataStride,
199                         VGImageFormat dataFormat,
200                         VGint x, VGint y,
201                         VGint width, VGint height)
202{
203   struct vg_context *ctx = vg_current_context();
204   struct vg_image *img;
205
206   if (image == VG_INVALID_HANDLE) {
207      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
208      return;
209   }
210   if (!supported_image_format(dataFormat)) {
211      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
212      return;
213   }
214   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
215      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
216      return;
217   }
218   img = (struct vg_image*)image;
219   image_get_sub_data(img, data, dataStride, dataFormat,
220                      x, y, width, height);
221}
222
223VGImage vegaChildImage(VGImage parent,
224                       VGint x, VGint y,
225                       VGint width, VGint height)
226{
227   struct vg_context *ctx = vg_current_context();
228   struct vg_image *p;
229
230   if (parent == VG_INVALID_HANDLE ||
231       !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) ||
232       !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) {
233      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
234      return VG_INVALID_HANDLE;
235   }
236   if (width <= 0 || height <= 0 || x < 0 || y < 0) {
237      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
238      return VG_INVALID_HANDLE;
239   }
240   p = (struct vg_image *)parent;
241   if (x > p->width  || y > p->height) {
242      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
243      return VG_INVALID_HANDLE;
244   }
245   if (x + width > p->width  || y + height > p->height) {
246      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
247      return VG_INVALID_HANDLE;
248   }
249
250   return (VGImage)image_child_image(p, x, y, width, height);
251}
252
253VGImage vegaGetParent(VGImage image)
254{
255   struct vg_context *ctx = vg_current_context();
256   struct vg_image *img;
257
258   if (image == VG_INVALID_HANDLE) {
259      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
260      return VG_INVALID_HANDLE;
261   }
262
263   img = (struct vg_image*)image;
264   if (img->parent)
265      return (VGImage)img->parent;
266   else
267      return image;
268}
269
270void vegaCopyImage(VGImage dst, VGint dx, VGint dy,
271                   VGImage src, VGint sx, VGint sy,
272                   VGint width, VGint height,
273                   VGboolean dither)
274{
275   struct vg_context *ctx = vg_current_context();
276
277   if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) {
278      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
279      return;
280   }
281
282   if (width <= 0 || height <= 0) {
283      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
284      return;
285   }
286   vg_validate_state(ctx);
287   image_copy((struct vg_image*)dst, dx, dy,
288              (struct vg_image*)src, sx, sy,
289              width, height, dither);
290}
291
292void vegaDrawImage(VGImage image)
293{
294   struct vg_context *ctx = vg_current_context();
295
296   if (!ctx)
297      return;
298
299   if (image == VG_INVALID_HANDLE) {
300      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
301      return;
302   }
303
304   vg_validate_state(ctx);
305   image_draw((struct vg_image*)image);
306}
307
308void vegaSetPixels(VGint dx, VGint dy,
309                   VGImage src, VGint sx, VGint sy,
310                   VGint width, VGint height)
311{
312   struct vg_context *ctx = vg_current_context();
313
314   vg_validate_state(ctx);
315
316   if (src == VG_INVALID_HANDLE) {
317      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
318      return;
319   }
320   if (width <= 0 || height <= 0) {
321      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
322      return;
323   }
324   image_set_pixels(dx, dy, (struct vg_image*)src, sx, sy, width,
325                    height);
326}
327
328void vegaGetPixels(VGImage dst, VGint dx, VGint dy,
329                   VGint sx, VGint sy,
330                   VGint width, VGint height)
331{
332   struct vg_context *ctx = vg_current_context();
333   struct vg_image *img;
334
335   if (dst == VG_INVALID_HANDLE) {
336      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
337      return;
338   }
339   if (width <= 0 || height <= 0) {
340      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
341      return;
342   }
343
344   img = (struct vg_image*)dst;
345
346   image_get_pixels(img, dx, dy,
347                    sx, sy, width, height);
348}
349
350void vegaWritePixels(const void * data, VGint dataStride,
351                     VGImageFormat dataFormat,
352                     VGint dx, VGint dy,
353                     VGint width, VGint height)
354{
355   struct vg_context *ctx = vg_current_context();
356   struct pipe_context *pipe = ctx->pipe;
357
358   if (!supported_image_format(dataFormat)) {
359      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
360      return;
361   }
362   if (!data || !is_aligned(data)) {
363      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
364      return;
365   }
366   if (width <= 0 || height <= 0) {
367      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
368      return;
369   }
370
371   vg_validate_state(ctx);
372   {
373      struct vg_image *img = image_create(dataFormat, width, height);
374      image_sub_data(img, data, dataStride, dataFormat, 0, 0,
375                     width, height);
376#if 0
377      struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix;
378      matrix_translate(matrix, dx, dy);
379      image_draw(img);
380      matrix_translate(matrix, -dx, -dy);
381#else
382      /* this looks like a better approach */
383      image_set_pixels(dx, dy, img, 0, 0, width, height);
384#endif
385      image_destroy(img);
386   }
387   /* make sure rendering has completed */
388   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
389}
390
391void 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   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
402
403   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
404   VGfloat *df = (VGfloat*)temp;
405   VGint y = (fb->height - sy) - 1, yStep = -1;
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      height += sy;
434      sy = 0;
435      y = (fb->height - sy) - 1;
436      yoffset *= dataStride;
437   }
438
439   {
440      struct pipe_transfer *transfer;
441
442      transfer = pipe_get_transfer(pipe, strb->texture,  0, 0, 0,
443				   PIPE_TRANSFER_READ,
444				   0, 0, width, height);
445
446      /* Do a row at a time to flip image data vertically */
447      for (i = 0; i < height; i++) {
448#if 0
449         debug_printf("%d-%d  == %d\n", sy, height, y);
450#endif
451         pipe_get_tile_rgba(pipe, transfer, sx, y, width, 1, df);
452         y += yStep;
453         _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
454                                    dst + yoffset + xoffset);
455         dst += dataStride;
456      }
457
458      pipe->transfer_destroy(pipe, transfer);
459   }
460}
461
462void vegaCopyPixels(VGint dx, VGint dy,
463                    VGint sx, VGint sy,
464                    VGint width, VGint height)
465{
466   struct vg_context *ctx = vg_current_context();
467   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
468   struct st_renderbuffer *strb = ctx->draw_buffer->strb;
469
470   if (width <= 0 || height <= 0) {
471      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
472      return;
473   }
474
475   /* do nothing if we copy from outside the fb */
476   if (dx >= (VGint)fb->width || dy >= (VGint)fb->height ||
477       sx >= (VGint)fb->width || sy >= (VGint)fb->height)
478      return;
479
480   vg_validate_state(ctx);
481   /* make sure rendering has completed */
482   vgFinish();
483
484   vg_copy_surface(ctx, strb->surface, dx, dy,
485                   strb->surface, sx, sy, width, height);
486}
487