api_images.c revision 75143ef05576ee9f25ee176bc28c3c4d03705bf5
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#include "api.h"
36
37#include "pipe/p_context.h"
38#include "pipe/p_screen.h"
39#include "util/u_inlines.h"
40#include "util/u_blit.h"
41#include "util/u_tile.h"
42#include "util/u_memory.h"
43
44static INLINE VGboolean supported_image_format(VGImageFormat format)
45{
46   switch(format) {
47   case VG_sRGBX_8888:
48   case VG_sRGBA_8888:
49   case VG_sRGBA_8888_PRE:
50   case VG_sRGB_565:
51   case VG_sRGBA_5551:
52   case VG_sRGBA_4444:
53   case VG_sL_8:
54   case VG_lRGBX_8888:
55   case VG_lRGBA_8888:
56   case VG_lRGBA_8888_PRE:
57   case VG_lL_8:
58   case VG_A_8:
59   case VG_BW_1:
60#ifdef OPENVG_VERSION_1_1
61   case VG_A_1:
62   case VG_A_4:
63#endif
64   case VG_sXRGB_8888:
65   case VG_sARGB_8888:
66   case VG_sARGB_8888_PRE:
67   case VG_sARGB_1555:
68   case VG_sARGB_4444:
69   case VG_lXRGB_8888:
70   case VG_lARGB_8888:
71   case VG_lARGB_8888_PRE:
72   case VG_sBGRX_8888:
73   case VG_sBGRA_8888:
74   case VG_sBGRA_8888_PRE:
75   case VG_sBGR_565:
76   case VG_sBGRA_5551:
77   case VG_sBGRA_4444:
78   case VG_lBGRX_8888:
79   case VG_lBGRA_8888:
80   case VG_lBGRA_8888_PRE:
81   case VG_sXBGR_8888:
82   case VG_sABGR_8888:
83   case VG_sABGR_8888_PRE:
84   case VG_sABGR_1555:
85   case VG_sABGR_4444:
86   case VG_lXBGR_8888:
87   case VG_lABGR_8888:
88   case VG_lABGR_8888_PRE:
89      return VG_TRUE;
90   default:
91      return VG_FALSE;
92   }
93   return VG_FALSE;
94}
95
96VGImage vegaCreateImage(VGImageFormat format,
97                        VGint width, VGint height,
98                        VGbitfield allowedQuality)
99{
100   struct vg_context *ctx = vg_current_context();
101
102   if (!supported_image_format(format)) {
103      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
104      return VG_INVALID_HANDLE;
105   }
106   if (width <= 0 || height <= 0) {
107      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
108      return VG_INVALID_HANDLE;
109   }
110   if (width > vgGeti(VG_MAX_IMAGE_WIDTH) ||
111       height > vgGeti(VG_MAX_IMAGE_HEIGHT)) {
112      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
113      return VG_INVALID_HANDLE;
114   }
115   if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) {
116      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
117      return VG_INVALID_HANDLE;
118   }
119
120   if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED |
121                           VG_IMAGE_QUALITY_FASTER |
122                           VG_IMAGE_QUALITY_BETTER)))) {
123      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
124      return VG_INVALID_HANDLE;
125   }
126
127   return (VGImage)image_create(format, width, height);
128}
129
130void vegaDestroyImage(VGImage image)
131{
132   struct vg_context *ctx = vg_current_context();
133   struct vg_image *img = (struct vg_image *)image;
134
135   if (image == VG_INVALID_HANDLE) {
136      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
137      return;
138   }
139   if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) {
140      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
141      return;
142   }
143   image_destroy(img);
144}
145
146void vegaClearImage(VGImage image,
147                    VGint x, VGint y,
148                    VGint width, VGint height)
149{
150   struct vg_context *ctx = vg_current_context();
151   struct vg_image *img;
152
153   if (image == VG_INVALID_HANDLE) {
154      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
155      return;
156   }
157   if (width <= 0 || height <= 0) {
158      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
159      return;
160   }
161
162   img = (struct vg_image*)image;
163
164   if (x + width < 0 || y + height < 0)
165      return;
166
167   image_clear(img, x, y, width, height);
168
169}
170
171void vegaImageSubData(VGImage image,
172                      const void * data,
173                      VGint dataStride,
174                      VGImageFormat dataFormat,
175                      VGint x, VGint y,
176                      VGint width, VGint height)
177{
178   struct vg_context *ctx = vg_current_context();
179   struct vg_image *img;
180
181   if (image == VG_INVALID_HANDLE) {
182      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
183      return;
184   }
185   if (!supported_image_format(dataFormat)) {
186      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
187      return;
188   }
189   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
190      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
191      return;
192   }
193
194   img = (struct vg_image*)(image);
195   image_sub_data(img, data, dataStride, dataFormat,
196                  x, y, width, height);
197}
198
199void vegaGetImageSubData(VGImage image,
200                         void * data,
201                         VGint dataStride,
202                         VGImageFormat dataFormat,
203                         VGint x, VGint y,
204                         VGint width, VGint height)
205{
206   struct vg_context *ctx = vg_current_context();
207   struct vg_image *img;
208
209   if (image == VG_INVALID_HANDLE) {
210      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
211      return;
212   }
213   if (!supported_image_format(dataFormat)) {
214      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
215      return;
216   }
217   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
218      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
219      return;
220   }
221   img = (struct vg_image*)image;
222   image_get_sub_data(img, data, dataStride, dataFormat,
223                      x, y, width, height);
224}
225
226VGImage vegaChildImage(VGImage parent,
227                       VGint x, VGint y,
228                       VGint width, VGint height)
229{
230   struct vg_context *ctx = vg_current_context();
231   struct vg_image *p;
232
233   if (parent == VG_INVALID_HANDLE ||
234       !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) ||
235       !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) {
236      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
237      return VG_INVALID_HANDLE;
238   }
239   if (width <= 0 || height <= 0 || x < 0 || y < 0) {
240      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
241      return VG_INVALID_HANDLE;
242   }
243   p = (struct vg_image *)parent;
244   if (x > p->width  || y > p->height) {
245      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
246      return VG_INVALID_HANDLE;
247   }
248   if (x + width > p->width  || y + height > p->height) {
249      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
250      return VG_INVALID_HANDLE;
251   }
252
253   return (VGImage)image_child_image(p, x, y, width, height);
254}
255
256VGImage vegaGetParent(VGImage image)
257{
258   struct vg_context *ctx = vg_current_context();
259   struct vg_image *img;
260
261   if (image == VG_INVALID_HANDLE) {
262      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
263      return VG_INVALID_HANDLE;
264   }
265
266   img = (struct vg_image*)image;
267   if (img->parent)
268      return (VGImage)img->parent;
269   else
270      return image;
271}
272
273void vegaCopyImage(VGImage dst, VGint dx, VGint dy,
274                   VGImage src, VGint sx, VGint sy,
275                   VGint width, VGint height,
276                   VGboolean dither)
277{
278   struct vg_context *ctx = vg_current_context();
279
280   if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) {
281      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
282      return;
283   }
284
285   if (width <= 0 || height <= 0) {
286      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
287      return;
288   }
289   vg_validate_state(ctx);
290   image_copy((struct vg_image*)dst, dx, dy,
291              (struct vg_image*)src, sx, sy,
292              width, height, dither);
293}
294
295void vegaDrawImage(VGImage image)
296{
297   struct vg_context *ctx = vg_current_context();
298
299   if (!ctx)
300      return;
301
302   if (image == VG_INVALID_HANDLE) {
303      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
304      return;
305   }
306
307   vg_validate_state(ctx);
308   image_draw((struct vg_image*)image);
309}
310
311void 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, (struct vg_image*)src, sx, sy, width,
328                    height);
329}
330
331void 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 = (struct vg_image*)dst;
348
349   image_get_pixels(img, dx, dy,
350                    sx, sy, width, height);
351}
352
353void 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   struct pipe_context *pipe = ctx->pipe;
360
361   if (!supported_image_format(dataFormat)) {
362      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
363      return;
364   }
365   if (!data || !is_aligned(data)) {
366      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
367      return;
368   }
369   if (width <= 0 || height <= 0) {
370      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
371      return;
372   }
373
374   vg_validate_state(ctx);
375   {
376      struct vg_image *img = image_create(dataFormat, width, height);
377      image_sub_data(img, data, dataStride, dataFormat, 0, 0,
378                     width, height);
379#if 0
380      struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix;
381      matrix_translate(matrix, dx, dy);
382      image_draw(img);
383      matrix_translate(matrix, -dx, -dy);
384#else
385      /* this looks like a better approach */
386      image_set_pixels(dx, dy, img, 0, 0, width, height);
387#endif
388      image_destroy(img);
389   }
390   /* make sure rendering has completed */
391   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
392}
393
394void vegaReadPixels(void * data, VGint dataStride,
395                    VGImageFormat dataFormat,
396                    VGint sx, VGint sy,
397                    VGint width, VGint height)
398{
399   struct vg_context *ctx = vg_current_context();
400   struct pipe_context *pipe = ctx->pipe;
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 = pipe_get_transfer(pipe, 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(pipe, 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      pipe->transfer_destroy(pipe, transfer);
462   }
463}
464
465void vegaCopyPixels(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