Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
[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 "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
43 static 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
95 VGImage 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
129 void 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
145 void 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
170 void 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
198 void 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
225 VGImage 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
255 VGImage 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
272 void 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
294 void 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
310 void 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
330 void 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
352 void 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
393 void 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
465 void 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 }