st/egl: Remove.
[mesa.git] / src / gallium / state_trackers / vega / image.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_translate.h"
30 #include "vg_context.h"
31 #include "matrix.h"
32 #include "renderer.h"
33 #include "util_array.h"
34 #include "api_consts.h"
35 #include "shader.h"
36
37 #include "pipe/p_context.h"
38 #include "pipe/p_screen.h"
39 #include "util/u_inlines.h"
40 #include "util/u_format.h"
41 #include "util/u_tile.h"
42 #include "util/u_memory.h"
43 #include "util/u_math.h"
44 #include "util/u_sampler.h"
45 #include "util/u_surface.h"
46
47 static enum pipe_format vg_format_to_pipe(VGImageFormat format)
48 {
49 switch(format) {
50 case VG_sRGB_565:
51 return PIPE_FORMAT_B5G6R5_UNORM;
52 case VG_sRGBA_5551:
53 return PIPE_FORMAT_B5G5R5A1_UNORM;
54 case VG_sRGBA_4444:
55 return PIPE_FORMAT_B4G4R4A4_UNORM;
56 case VG_sL_8:
57 case VG_lL_8:
58 return PIPE_FORMAT_L8_UNORM;
59 case VG_BW_1:
60 return PIPE_FORMAT_B8G8R8A8_UNORM;
61 case VG_A_8:
62 return PIPE_FORMAT_A8_UNORM;
63 #ifdef OPENVG_VERSION_1_1
64 case VG_A_1:
65 case VG_A_4:
66 return PIPE_FORMAT_A8_UNORM;
67 #endif
68 default:
69 return PIPE_FORMAT_B8G8R8A8_UNORM;
70 }
71 }
72
73 static INLINE void vg_sync_size(VGfloat *src_loc, VGfloat *dst_loc)
74 {
75 src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
76 src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
77 dst_loc[2] = src_loc[2];
78 dst_loc[3] = src_loc[3];
79 }
80
81 static void vg_get_copy_coords(VGfloat *src_loc,
82 VGfloat src_width, VGfloat src_height,
83 VGfloat *dst_loc,
84 VGfloat dst_width, VGfloat dst_height)
85 {
86 VGfloat dst_bounds[4], src_bounds[4];
87 VGfloat src_shift[4], dst_shift[4], shift[4];
88
89 dst_bounds[0] = 0.f;
90 dst_bounds[1] = 0.f;
91 dst_bounds[2] = dst_width;
92 dst_bounds[3] = dst_height;
93
94 src_bounds[0] = 0.f;
95 src_bounds[1] = 0.f;
96 src_bounds[2] = src_width;
97 src_bounds[3] = src_height;
98
99 vg_bound_rect(src_loc, src_bounds, src_shift);
100 vg_bound_rect(dst_loc, dst_bounds, dst_shift);
101 shift[0] = src_shift[0] - dst_shift[0];
102 shift[1] = src_shift[1] - dst_shift[1];
103
104 if (shift[0] < 0)
105 vg_shift_rectx(src_loc, src_bounds, -shift[0]);
106 else
107 vg_shift_rectx(dst_loc, dst_bounds, shift[0]);
108
109 if (shift[1] < 0)
110 vg_shift_recty(src_loc, src_bounds, -shift[1]);
111 else
112 vg_shift_recty(dst_loc, dst_bounds, shift[1]);
113
114 vg_sync_size(src_loc, dst_loc);
115 }
116
117 static void vg_copy_texture(struct vg_context *ctx,
118 struct pipe_resource *dst, VGint dx, VGint dy,
119 struct pipe_sampler_view *src, VGint sx, VGint sy,
120 VGint width, VGint height)
121 {
122 VGfloat dst_loc[4], src_loc[4];
123
124 dst_loc[0] = dx;
125 dst_loc[1] = dy;
126 dst_loc[2] = width;
127 dst_loc[3] = height;
128
129 src_loc[0] = sx;
130 src_loc[1] = sy;
131 src_loc[2] = width;
132 src_loc[3] = height;
133
134 vg_get_copy_coords(src_loc, src->texture->width0, src->texture->height0,
135 dst_loc, dst->width0, dst->height0);
136
137 if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
138 dst_loc[2] >= 0 && dst_loc[3] >= 0) {
139 struct pipe_surface *surf, surf_tmpl;
140
141 /* get the destination surface */
142 u_surface_default_template(&surf_tmpl, dst);
143 surf = ctx->pipe->create_surface(ctx->pipe, dst, &surf_tmpl);
144 if (surf && renderer_copy_begin(ctx->renderer, surf, VG_TRUE, src)) {
145 renderer_copy(ctx->renderer,
146 dst_loc[0], dst_loc[1], dst_loc[2], dst_loc[3],
147 src_loc[0], src_loc[1], src_loc[2], src_loc[3]);
148 renderer_copy_end(ctx->renderer);
149 }
150
151 pipe_surface_reference(&surf, NULL);
152 }
153 }
154
155 void vg_copy_surface(struct vg_context *ctx,
156 struct pipe_surface *dst, VGint dx, VGint dy,
157 struct pipe_surface *src, VGint sx, VGint sy,
158 VGint width, VGint height)
159 {
160 VGfloat dst_loc[4], src_loc[4];
161
162 dst_loc[0] = dx;
163 dst_loc[1] = dy;
164 dst_loc[2] = width;
165 dst_loc[3] = height;
166
167 src_loc[0] = sx;
168 src_loc[1] = sy;
169 src_loc[2] = width;
170 src_loc[3] = height;
171
172 vg_get_copy_coords(src_loc, src->width, src->height,
173 dst_loc, dst->width, dst->height);
174
175 if (src_loc[2] > 0 && src_loc[3] > 0 &&
176 dst_loc[2] > 0 && dst_loc[3] > 0) {
177 if (src == dst)
178 renderer_copy_surface(ctx->renderer,
179 src,
180 src_loc[0],
181 src->height - (src_loc[1] + src_loc[3]),
182 src_loc[0] + src_loc[2],
183 src->height - src_loc[1],
184 dst,
185 dst_loc[0],
186 dst->height - (dst_loc[1] + dst_loc[3]),
187 dst_loc[0] + dst_loc[2],
188 dst->height - dst_loc[1],
189 0, 0);
190 else
191 renderer_copy_surface(ctx->renderer,
192 src,
193 src_loc[0],
194 src->height - src_loc[1],
195 src_loc[0] + src_loc[2],
196 src->height - (src_loc[1] + src_loc[3]),
197 dst,
198 dst_loc[0],
199 dst->height - (dst_loc[1] + dst_loc[3]),
200 dst_loc[0] + dst_loc[2],
201 dst->height - dst_loc[1],
202 0, 0);
203 }
204
205 }
206
207 static struct pipe_resource *image_texture(struct vg_image *img)
208 {
209 struct pipe_resource *tex = img->sampler_view->texture;
210 return tex;
211 }
212
213
214 static void image_cleari(struct vg_image *img, VGint clear_colori,
215 VGint x, VGint y, VGint width, VGint height)
216 {
217 VGint *clearbuf;
218 VGint i;
219 VGfloat dwidth, dheight;
220
221 clearbuf = malloc(sizeof(VGint)*width*height);
222 for (i = 0; i < width*height; ++i)
223 clearbuf[i] = clear_colori;
224
225 dwidth = MIN2(width, img->width);
226 dheight = MIN2(height, img->height);
227
228 image_sub_data(img, clearbuf, width * sizeof(VGint),
229 VG_sRGBA_8888,
230 x, y, dwidth, dheight);
231 free(clearbuf);
232 }
233
234 struct vg_image * image_create(VGImageFormat format,
235 VGint width, VGint height)
236 {
237 struct vg_context *ctx = vg_current_context();
238 struct pipe_context *pipe = ctx->pipe;
239 struct vg_image *image = CALLOC_STRUCT(vg_image);
240 enum pipe_format pformat = vg_format_to_pipe(format);
241 struct pipe_resource pt, *newtex;
242 struct pipe_sampler_view view_templ;
243 struct pipe_sampler_view *view;
244 struct pipe_screen *screen = ctx->pipe->screen;
245
246 vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
247
248 image->format = format;
249 image->width = width;
250 image->height = height;
251
252 image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
253 image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
254 image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
255 image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
256 image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
257 image->sampler.normalized_coords = 1;
258
259 assert(screen->is_format_supported(screen, pformat, PIPE_TEXTURE_2D,
260 0, PIPE_BIND_SAMPLER_VIEW));
261
262 memset(&pt, 0, sizeof(pt));
263 pt.target = PIPE_TEXTURE_2D;
264 pt.format = pformat;
265 pt.last_level = 0;
266 pt.width0 = width;
267 pt.height0 = height;
268 pt.depth0 = 1;
269 pt.array_size = 1;
270 pt.bind = PIPE_BIND_SAMPLER_VIEW;
271
272 newtex = screen->resource_create(screen, &pt);
273
274 debug_assert(newtex);
275
276 u_sampler_view_default_template(&view_templ, newtex, newtex->format);
277 /* R, G, and B are treated as 1.0 for alpha-only formats in OpenVG */
278 if (newtex->format == PIPE_FORMAT_A8_UNORM) {
279 view_templ.swizzle_r = PIPE_SWIZZLE_ONE;
280 view_templ.swizzle_g = PIPE_SWIZZLE_ONE;
281 view_templ.swizzle_b = PIPE_SWIZZLE_ONE;
282 }
283
284 view = pipe->create_sampler_view(pipe, newtex, &view_templ);
285 /* want the texture to go away if the view is freed */
286 pipe_resource_reference(&newtex, NULL);
287
288 image->sampler_view = view;
289
290 vg_context_add_object(ctx, &image->base);
291
292 image_cleari(image, 0, 0, 0, image->width, image->height);
293 return image;
294 }
295
296 void image_destroy(struct vg_image *img)
297 {
298 struct vg_context *ctx = vg_current_context();
299 vg_context_remove_object(ctx, &img->base);
300
301
302 if (img->parent) {
303 /* remove img from the parent child array */
304 int idx;
305 struct vg_image **array =
306 (struct vg_image **)img->parent->children_array->data;
307
308 for (idx = 0; idx < img->parent->children_array->num_elements; ++idx) {
309 struct vg_image *child = array[idx];
310 if (child == img) {
311 break;
312 }
313 }
314 debug_assert(idx < img->parent->children_array->num_elements);
315 array_remove_element(img->parent->children_array, idx);
316 }
317
318 if (img->children_array && img->children_array->num_elements) {
319 /* reparent the children */
320 VGint i;
321 struct vg_image *parent = img->parent;
322 struct vg_image **children =
323 (struct vg_image **)img->children_array->data;
324 if (!parent) {
325 VGint min_x = children[0]->x;
326 parent = children[0];
327
328 for (i = 1; i < img->children_array->num_elements; ++i) {
329 struct vg_image *child = children[i];
330 if (child->x < min_x) {
331 parent = child;
332 }
333 }
334 }
335
336 for (i = 0; i < img->children_array->num_elements; ++i) {
337 struct vg_image *child = children[i];
338 if (child != parent) {
339 child->parent = parent;
340 if (!parent->children_array) {
341 parent->children_array = array_create(
342 sizeof(struct vg_image*));
343 }
344 array_append_data(parent->children_array,
345 &child, 1);
346 } else
347 child->parent = NULL;
348 }
349 array_destroy(img->children_array);
350 }
351
352 vg_free_object(&img->base);
353
354 pipe_sampler_view_reference(&img->sampler_view, NULL);
355 FREE(img);
356 }
357
358 void image_clear(struct vg_image *img,
359 VGint x, VGint y, VGint width, VGint height)
360 {
361 struct vg_context *ctx = vg_current_context();
362 VGfloat *clear_colorf = ctx->state.vg.clear_color;
363 VGubyte r, g, b ,a;
364 VGint clear_colori;
365 /* FIXME: this is very nasty */
366 r = float_to_ubyte(clear_colorf[0]);
367 g = float_to_ubyte(clear_colorf[1]);
368 b = float_to_ubyte(clear_colorf[2]);
369 a = float_to_ubyte(clear_colorf[3]);
370 clear_colori = r << 24 | g << 16 | b << 8 | a;
371 image_cleari(img, clear_colori, x, y, width, height);
372 }
373
374 void image_sub_data(struct vg_image *image,
375 const void * data,
376 VGint dataStride,
377 VGImageFormat dataFormat,
378 VGint x, VGint y,
379 VGint width, VGint height)
380 {
381 const VGint yStep = 1;
382 VGubyte *src = (VGubyte *)data;
383 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
384 VGfloat *df = (VGfloat*)temp;
385 VGint i;
386 struct vg_context *ctx = vg_current_context();
387 struct pipe_context *pipe = ctx->pipe;
388 struct pipe_resource *texture = image_texture(image);
389 VGint xoffset = 0, yoffset = 0;
390
391 if (x < 0) {
392 xoffset -= x;
393 width += x;
394 x = 0;
395 }
396 if (y < 0) {
397 yoffset -= y;
398 height += y;
399 y = 0;
400 }
401
402 if (width <= 0 || height <= 0) {
403 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
404 return;
405 }
406
407 if (x > image->width || y > image->width) {
408 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
409 return;
410 }
411
412 if (x + width > image->width) {
413 width = image->width - x;
414 }
415
416 if (y + height > image->height) {
417 height = image->height - y;
418 }
419
420 { /* upload color_data */
421 struct pipe_transfer *transfer;
422 void *map = pipe_transfer_map(pipe, texture, 0, 0,
423 PIPE_TRANSFER_WRITE, 0, 0,
424 texture->width0, texture->height0,
425 &transfer);
426 src += (dataStride * yoffset);
427 for (i = 0; i < height; i++) {
428 _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp);
429 pipe_put_tile_rgba(transfer, map, x+image->x, y+image->y, width, 1, df);
430 y += yStep;
431 src += dataStride;
432 }
433 pipe->transfer_unmap(pipe, transfer);
434 }
435 }
436
437 void image_get_sub_data(struct vg_image * image,
438 void * data,
439 VGint dataStride,
440 VGImageFormat dataFormat,
441 VGint sx, VGint sy,
442 VGint width, VGint height)
443 {
444 struct vg_context *ctx = vg_current_context();
445 struct pipe_context *pipe = ctx->pipe;
446 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
447 VGfloat *df = (VGfloat*)temp;
448 VGint y = 0, yStep = 1;
449 VGint i;
450 VGubyte *dst = (VGubyte *)data;
451
452 {
453 struct pipe_transfer *transfer;
454 void *map =
455 pipe_transfer_map(pipe,
456 image->sampler_view->texture, 0, 0,
457 PIPE_TRANSFER_READ,
458 0, 0,
459 image->x + image->width,
460 image->y + image->height, &transfer);
461 /* Do a row at a time to flip image data vertically */
462 for (i = 0; i < height; i++) {
463 #if 0
464 debug_printf("%d-%d == %d\n", sy, height, y);
465 #endif
466 pipe_get_tile_rgba(transfer, map, sx+image->x, y, width, 1, df);
467 y += yStep;
468 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst);
469 dst += dataStride;
470 }
471
472 pipe->transfer_unmap(pipe, transfer);
473 }
474 }
475
476 struct vg_image * image_child_image(struct vg_image *parent,
477 VGint x, VGint y,
478 VGint width, VGint height)
479 {
480 struct vg_context *ctx = vg_current_context();
481 struct vg_image *image = CALLOC_STRUCT(vg_image);
482
483 vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
484
485 image->x = parent->x + x;
486 image->y = parent->y + y;
487 image->width = width;
488 image->height = height;
489 image->parent = parent;
490 image->sampler_view = NULL;
491 pipe_sampler_view_reference(&image->sampler_view,
492 parent->sampler_view);
493
494 image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
495 image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
496 image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
497 image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
498 image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
499 image->sampler.normalized_coords = 1;
500
501 if (!parent->children_array)
502 parent->children_array = array_create(
503 sizeof(struct vg_image*));
504
505 array_append_data(parent->children_array,
506 &image, 1);
507
508 vg_context_add_object(ctx, &image->base);
509
510 return image;
511 }
512
513 void image_copy(struct vg_image *dst, VGint dx, VGint dy,
514 struct vg_image *src, VGint sx, VGint sy,
515 VGint width, VGint height,
516 VGboolean dither)
517 {
518 struct vg_context *ctx = vg_current_context();
519
520 if (width <= 0 || height <= 0) {
521 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
522 return;
523 }
524 vg_copy_texture(ctx, dst->sampler_view->texture, dst->x + dx, dst->y + dy,
525 src->sampler_view, src->x + sx, src->y + sy, width, height);
526 }
527
528 void image_draw(struct vg_image *img, struct matrix *matrix)
529 {
530 struct vg_context *ctx = vg_current_context();
531 struct matrix paint_matrix;
532 VGfloat x1, y1;
533 VGfloat x2, y2;
534 VGfloat x3, y3;
535 VGfloat x4, y4;
536
537 if (!vg_get_paint_matrix(ctx,
538 &ctx->state.vg.fill_paint_to_user_matrix,
539 matrix,
540 &paint_matrix))
541 return;
542
543 x1 = 0;
544 y1 = 0;
545 x2 = img->width;
546 y2 = 0;
547 x3 = img->width;
548 y3 = img->height;
549 x4 = 0;
550 y4 = img->height;
551
552 shader_set_surface_matrix(ctx->shader, matrix);
553 shader_set_drawing_image(ctx->shader, VG_TRUE);
554 shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
555 shader_set_paint_matrix(ctx->shader, &paint_matrix);
556 shader_set_image(ctx->shader, img);
557 shader_bind(ctx->shader);
558
559 renderer_texture_quad(ctx->renderer, image_texture(img),
560 img->x, img->y, img->x + img->width, img->y + img->height,
561 x1, y1, x2, y2, x3, y3, x4, y4);
562 }
563
564 void image_set_pixels(VGint dx, VGint dy,
565 struct vg_image *src, VGint sx, VGint sy,
566 VGint width, VGint height)
567 {
568 struct vg_context *ctx = vg_current_context();
569 struct pipe_context *pipe = ctx->pipe;
570 struct pipe_surface *surf, surf_tmpl;
571 struct st_renderbuffer *strb = ctx->draw_buffer->strb;
572
573 u_surface_default_template(&surf_tmpl, image_texture(src));
574 surf = pipe->create_surface(pipe, image_texture(src), &surf_tmpl);
575
576 vg_copy_surface(ctx, strb->surface, dx, dy,
577 surf, sx+src->x, sy+src->y, width, height);
578
579 pipe->surface_destroy(pipe, surf);
580 }
581
582 void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy,
583 VGint sx, VGint sy,
584 VGint width, VGint height)
585 {
586 struct vg_context *ctx = vg_current_context();
587 struct pipe_context *pipe = ctx->pipe;
588 struct pipe_surface *surf, surf_tmpl;
589 struct st_renderbuffer *strb = ctx->draw_buffer->strb;
590
591 /* flip the y coordinates */
592 /*dy = dst->height - dy - height;*/
593
594 u_surface_default_template(&surf_tmpl, image_texture(dst));
595 surf = pipe->create_surface(pipe, image_texture(dst), &surf_tmpl);
596
597 vg_copy_surface(ctx, surf, dst->x + dx, dst->y + dy,
598 strb->surface, sx, sy, width, height);
599
600 pipe_surface_reference(&surf, NULL);
601 }
602
603
604 VGboolean vg_image_overlaps(struct vg_image *dst,
605 struct vg_image *src)
606 {
607 if (dst == src || dst->parent == src ||
608 dst == src->parent)
609 return VG_TRUE;
610 if (dst->parent && dst->parent == src->parent) {
611 VGfloat left1 = dst->x;
612 VGfloat left2 = src->x;
613 VGfloat right1 = dst->x + dst->width;
614 VGfloat right2 = src->x + src->width;
615 VGfloat bottom1 = dst->y;
616 VGfloat bottom2 = src->y;
617 VGfloat top1 = dst->y + dst->height;
618 VGfloat top2 = src->y + src->height;
619
620 return !(left2 > right1 || right2 < left1 ||
621 top2 > bottom1 || bottom2 < top1);
622 }
623 return VG_FALSE;
624 }
625
626 VGint image_bind_samplers(struct vg_image *img, struct pipe_sampler_state **samplers,
627 struct pipe_sampler_view **sampler_views)
628 {
629 img->sampler.min_img_filter = image_sampler_filter(img->base.ctx);
630 img->sampler.mag_img_filter = image_sampler_filter(img->base.ctx);
631 samplers[3] = &img->sampler;
632 sampler_views[3] = img->sampler_view;
633 return 1;
634 }
635
636 VGint image_sampler_filter(struct vg_context *ctx)
637 {
638 switch(ctx->state.vg.image_quality) {
639 case VG_IMAGE_QUALITY_NONANTIALIASED:
640 return PIPE_TEX_FILTER_NEAREST;
641 break;
642 case VG_IMAGE_QUALITY_FASTER:
643 return PIPE_TEX_FILTER_NEAREST;
644 break;
645 case VG_IMAGE_QUALITY_BETTER:
646 /* possibly use anisotropic filtering */
647 return PIPE_TEX_FILTER_LINEAR;
648 break;
649 default:
650 debug_printf("Unknown image quality");
651 }
652 return PIPE_TEX_FILTER_NEAREST;
653 }