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