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