Merge remote branch 'origin/master' into pipe-video
[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 "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
41 static 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
93 VGImage 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
127 void 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
143 void 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
168 void 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
196 void 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
223 VGImage 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
253 VGImage 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
270 void 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
292 void 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
308 void 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
328 void 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
350 void 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
391 void 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
462 void 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 }