1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
29 #include "vg_translate.h"
30 #include "vg_context.h"
33 #include "util_array.h"
34 #include "api_consts.h"
35 #include "shaders_cache.h"
38 #include "pipe/p_context.h"
39 #include "pipe/p_screen.h"
40 #include "pipe/p_inlines.h"
41 #include "util/u_blit.h"
42 #include "util/u_tile.h"
43 #include "util/u_memory.h"
44 #include "util/u_math.h"
46 static enum pipe_format
vg_format_to_pipe(VGImageFormat format
)
50 return PIPE_FORMAT_R5G6B5_UNORM
;
52 return PIPE_FORMAT_A1R5G5B5_UNORM
;
54 return PIPE_FORMAT_A4R4G4B4_UNORM
;
57 return PIPE_FORMAT_L8_UNORM
;
59 return PIPE_FORMAT_A8R8G8B8_UNORM
;
61 return PIPE_FORMAT_A8_UNORM
;
62 #ifdef OPENVG_VERSION_1_1
65 return PIPE_FORMAT_A8_UNORM
;
68 return PIPE_FORMAT_A8R8G8B8_UNORM
;
72 static INLINE
void vg_sync_size(VGfloat
*src_loc
, VGfloat
*dst_loc
)
74 src_loc
[2] = MIN2(src_loc
[2], dst_loc
[2]);
75 src_loc
[3] = MIN2(src_loc
[3], dst_loc
[3]);
76 dst_loc
[2] = src_loc
[2];
77 dst_loc
[3] = src_loc
[3];
81 static void vg_copy_texture(struct vg_context
*ctx
,
82 struct pipe_texture
*dst
, VGint dx
, VGint dy
,
83 struct pipe_texture
*src
, VGint sx
, VGint sy
,
84 VGint width
, VGint height
)
86 VGfloat dst_loc
[4], src_loc
[4];
87 VGfloat dst_bounds
[4], src_bounds
[4];
88 VGfloat src_shift
[4], dst_shift
[4], shift
[4];
96 dst_bounds
[2] = dst
->width0
;
97 dst_bounds
[3] = dst
->height0
;
105 src_bounds
[2] = src
->width0
;
106 src_bounds
[3] = src
->height0
;
108 vg_bound_rect(src_loc
, src_bounds
, src_shift
);
109 vg_bound_rect(dst_loc
, dst_bounds
, dst_shift
);
110 shift
[0] = src_shift
[0] - dst_shift
[0];
111 shift
[1] = src_shift
[1] - dst_shift
[1];
114 vg_shift_rectx(src_loc
, src_bounds
, -shift
[0]);
116 vg_shift_rectx(dst_loc
, dst_bounds
, shift
[0]);
119 vg_shift_recty(src_loc
, src_bounds
, -shift
[1]);
121 vg_shift_recty(dst_loc
, dst_bounds
, shift
[1]);
123 vg_sync_size(src_loc
, dst_loc
);
125 if (src_loc
[2] >= 0 && src_loc
[3] >= 0 &&
126 dst_loc
[2] >= 0 && dst_loc
[3] >= 0) {
127 renderer_copy_texture(ctx
->renderer
,
130 src_loc
[1] + src_loc
[3],
131 src_loc
[0] + src_loc
[2],
135 dst_loc
[1] + dst_loc
[3],
136 dst_loc
[0] + dst_loc
[2],
142 void vg_copy_surface(struct vg_context
*ctx
,
143 struct pipe_surface
*dst
, VGint dx
, VGint dy
,
144 struct pipe_surface
*src
, VGint sx
, VGint sy
,
145 VGint width
, VGint height
)
147 VGfloat dst_loc
[4], src_loc
[4];
148 VGfloat dst_bounds
[4], src_bounds
[4];
149 VGfloat src_shift
[4], dst_shift
[4], shift
[4];
157 dst_bounds
[2] = dst
->width
;
158 dst_bounds
[3] = dst
->height
;
166 src_bounds
[2] = src
->width
;
167 src_bounds
[3] = src
->height
;
169 vg_bound_rect(src_loc
, src_bounds
, src_shift
);
170 vg_bound_rect(dst_loc
, dst_bounds
, dst_shift
);
171 shift
[0] = src_shift
[0] - dst_shift
[0];
172 shift
[1] = src_shift
[1] - dst_shift
[1];
175 vg_shift_rectx(src_loc
, src_bounds
, -shift
[0]);
177 vg_shift_rectx(dst_loc
, dst_bounds
, shift
[0]);
180 vg_shift_recty(src_loc
, src_bounds
, -shift
[1]);
182 vg_shift_recty(dst_loc
, dst_bounds
, shift
[1]);
184 vg_sync_size(src_loc
, dst_loc
);
186 if (src_loc
[2] > 0 && src_loc
[3] > 0 &&
187 dst_loc
[2] > 0 && dst_loc
[3] > 0) {
189 renderer_copy_surface(ctx
->renderer
,
192 src
->height
- (src_loc
[1] + src_loc
[3]),
193 src_loc
[0] + src_loc
[2],
194 src
->height
- src_loc
[1],
197 dst
->height
- (dst_loc
[1] + dst_loc
[3]),
198 dst_loc
[0] + dst_loc
[2],
199 dst
->height
- dst_loc
[1],
202 renderer_copy_surface(ctx
->renderer
,
205 src
->height
- src_loc
[1],
206 src_loc
[0] + src_loc
[2],
207 src
->height
- (src_loc
[1] + src_loc
[3]),
210 dst
->height
- (dst_loc
[1] + dst_loc
[3]),
211 dst_loc
[0] + dst_loc
[2],
212 dst
->height
- dst_loc
[1],
218 static struct pipe_texture
*image_texture(struct vg_image
*img
)
220 struct pipe_texture
*tex
= img
->texture
;
225 static void image_cleari(struct vg_image
*img
, VGint clear_colori
,
226 VGint x
, VGint y
, VGint width
, VGint height
)
230 VGfloat dwidth
, dheight
;
232 clearbuf
= malloc(sizeof(VGint
)*width
*height
);
233 for (i
= 0; i
< width
*height
; ++i
)
234 clearbuf
[i
] = clear_colori
;
236 dwidth
= MIN2(width
, img
->width
);
237 dheight
= MIN2(height
, img
->height
);
239 image_sub_data(img
, clearbuf
, width
* sizeof(VGint
),
241 x
, y
, dwidth
, dheight
);
245 struct vg_image
* image_create(VGImageFormat format
,
246 VGint width
, VGint height
)
248 struct vg_context
*ctx
= vg_current_context();
249 struct vg_image
*image
= CALLOC_STRUCT(vg_image
);
250 enum pipe_format pformat
= vg_format_to_pipe(format
);
251 struct pipe_texture pt
, *newtex
;
252 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
254 vg_init_object(&image
->base
, ctx
, VG_OBJECT_IMAGE
);
256 image
->format
= format
;
257 image
->width
= width
;
258 image
->height
= height
;
260 image
->sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
261 image
->sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
262 image
->sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
263 image
->sampler
.min_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
264 image
->sampler
.mag_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
265 image
->sampler
.normalized_coords
= 1;
267 assert(screen
->is_format_supported(screen
, pformat
, PIPE_TEXTURE_2D
,
268 PIPE_TEXTURE_USAGE_SAMPLER
, 0));
270 memset(&pt
, 0, sizeof(pt
));
271 pt
.target
= PIPE_TEXTURE_2D
;
277 pt
.tex_usage
= PIPE_TEXTURE_USAGE_SAMPLER
;
279 newtex
= screen
->texture_create(screen
, &pt
);
281 debug_assert(newtex
);
283 image
->texture
= newtex
;
285 vg_context_add_object(ctx
, VG_OBJECT_IMAGE
, image
);
287 image_cleari(image
, 0, 0, 0, image
->width
, image
->height
);
291 void image_destroy(struct vg_image
*img
)
293 struct vg_context
*ctx
= vg_current_context();
294 vg_context_remove_object(ctx
, VG_OBJECT_IMAGE
, img
);
298 /* remove img from the parent child array */
300 struct vg_image
**array
=
301 (struct vg_image
**)img
->parent
->children_array
->data
;
303 for (idx
= 0; idx
< img
->parent
->children_array
->num_elements
; ++idx
) {
304 struct vg_image
*child
= array
[idx
];
309 debug_assert(idx
< img
->parent
->children_array
->num_elements
);
310 array_remove_element(img
->parent
->children_array
, idx
);
313 if (img
->children_array
&& img
->children_array
->num_elements
) {
314 /* reparent the children */
316 struct vg_image
*parent
= img
->parent
;
317 struct vg_image
**children
=
318 (struct vg_image
**)img
->children_array
->data
;
320 VGint min_x
= children
[0]->x
;
321 parent
= children
[0];
323 for (i
= 1; i
< img
->children_array
->num_elements
; ++i
) {
324 struct vg_image
*child
= children
[i
];
325 if (child
->x
< min_x
) {
331 for (i
= 0; i
< img
->children_array
->num_elements
; ++i
) {
332 struct vg_image
*child
= children
[i
];
333 if (child
!= parent
) {
334 child
->parent
= parent
;
335 if (!parent
->children_array
) {
336 parent
->children_array
= array_create(
337 sizeof(struct vg_image
*));
339 array_append_data(parent
->children_array
,
342 child
->parent
= NULL
;
344 array_destroy(img
->children_array
);
347 pipe_texture_reference(&img
->texture
, NULL
);
351 void image_clear(struct vg_image
*img
,
352 VGint x
, VGint y
, VGint width
, VGint height
)
354 struct vg_context
*ctx
= vg_current_context();
355 VGfloat
*clear_colorf
= ctx
->state
.vg
.clear_color
;
358 /* FIXME: this is very nasty */
359 r
= float_to_ubyte(clear_colorf
[0]);
360 g
= float_to_ubyte(clear_colorf
[1]);
361 b
= float_to_ubyte(clear_colorf
[2]);
362 a
= float_to_ubyte(clear_colorf
[3]);
363 clear_colori
= r
<< 24 | g
<< 16 | b
<< 8 | a
;
364 image_cleari(img
, clear_colori
, x
, y
, width
, height
);
367 void image_sub_data(struct vg_image
*image
,
370 VGImageFormat dataFormat
,
372 VGint width
, VGint height
)
374 const VGint yStep
= 1;
375 VGubyte
*src
= (VGubyte
*)data
;
376 VGfloat temp
[VEGA_MAX_IMAGE_WIDTH
][4];
377 VGfloat
*df
= (VGfloat
*)temp
;
379 struct vg_context
*ctx
= vg_current_context();
380 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
381 struct pipe_texture
*texture
= image_texture(image
);
382 VGint xoffset
= 0, yoffset
= 0;
395 if (width
<= 0 || height
<= 0) {
396 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
400 if (x
> image
->width
|| y
> image
->width
) {
401 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
405 if (x
+ width
> image
->width
) {
406 width
= image
->width
- x
;
409 if (y
+ height
> image
->height
) {
410 height
= image
->height
- y
;
413 { /* upload color_data */
414 struct pipe_transfer
*transfer
= screen
->get_tex_transfer(
415 screen
, texture
, 0, 0, 0,
416 PIPE_TRANSFER_WRITE
, 0, 0, texture
->width0
, texture
->height0
);
417 src
+= (dataStride
* yoffset
);
418 for (i
= 0; i
< height
; i
++) {
419 _vega_unpack_float_span_rgba(ctx
, width
, xoffset
, src
, dataFormat
, temp
);
420 pipe_put_tile_rgba(transfer
, x
+image
->x
, y
+image
->y
, width
, 1, df
);
424 screen
->tex_transfer_destroy(transfer
);
428 void image_get_sub_data(struct vg_image
* image
,
431 VGImageFormat dataFormat
,
433 VGint width
, VGint height
)
435 struct vg_context
*ctx
= vg_current_context();
436 struct pipe_context
*pipe
= ctx
->pipe
;
437 struct pipe_screen
*screen
= pipe
->screen
;
438 VGfloat temp
[VEGA_MAX_IMAGE_WIDTH
][4];
439 VGfloat
*df
= (VGfloat
*)temp
;
440 VGint y
= 0, yStep
= 1;
442 VGubyte
*dst
= (VGubyte
*)data
;
445 struct pipe_transfer
*transfer
=
446 screen
->get_tex_transfer(screen
,
447 image
->texture
, 0, 0, 0,
450 image
->x
+ image
->width
,
451 image
->y
+ image
->height
);
452 /* Do a row at a time to flip image data vertically */
453 for (i
= 0; i
< height
; i
++) {
455 debug_printf("%d-%d == %d\n", sy
, height
, y
);
457 pipe_get_tile_rgba(transfer
, sx
+image
->x
, y
, width
, 1, df
);
459 _vega_pack_rgba_span_float(ctx
, width
, temp
, dataFormat
, dst
);
463 screen
->tex_transfer_destroy(transfer
);
467 struct vg_image
* image_child_image(struct vg_image
*parent
,
469 VGint width
, VGint height
)
471 struct vg_context
*ctx
= vg_current_context();
472 struct vg_image
*image
= CALLOC_STRUCT(vg_image
);
474 vg_init_object(&image
->base
, ctx
, VG_OBJECT_IMAGE
);
476 image
->x
= parent
->x
+ x
;
477 image
->y
= parent
->y
+ y
;
478 image
->width
= width
;
479 image
->height
= height
;
480 image
->parent
= parent
;
482 pipe_texture_reference(&image
->texture
,
485 image
->sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
486 image
->sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
487 image
->sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
488 image
->sampler
.min_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
489 image
->sampler
.mag_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
490 image
->sampler
.normalized_coords
= 1;
492 if (!parent
->children_array
)
493 parent
->children_array
= array_create(
494 sizeof(struct vg_image
*));
496 array_append_data(parent
->children_array
,
499 vg_context_add_object(ctx
, VG_OBJECT_IMAGE
, image
);
504 void image_copy(struct vg_image
*dst
, VGint dx
, VGint dy
,
505 struct vg_image
*src
, VGint sx
, VGint sy
,
506 VGint width
, VGint height
,
509 struct vg_context
*ctx
= vg_current_context();
511 if (width
<= 0 || height
<= 0) {
512 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
515 /* make sure rendering has completed */
516 ctx
->pipe
->flush(ctx
->pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
517 vg_copy_texture(ctx
, dst
->texture
, dst
->x
+ dx
, dst
->y
+ dy
,
518 src
->texture
, src
->x
+ sx
, src
->y
+ sy
, width
, height
);
521 void image_draw(struct vg_image
*img
)
523 struct vg_context
*ctx
= vg_current_context();
528 struct matrix
*matrix
;
539 matrix
= &ctx
->state
.vg
.image_user_to_surface_matrix
;
541 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
542 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
543 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
544 matrix_map_point(matrix
, x4
, y4
, &x4
, &y4
);
546 shader_set_drawing_image(ctx
->shader
, VG_TRUE
);
547 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
548 shader_set_image(ctx
->shader
, img
);
549 shader_bind(ctx
->shader
);
551 renderer_texture_quad(ctx
->renderer
, image_texture(img
),
552 img
->x
, img
->y
, img
->x
+ img
->width
, img
->y
+ img
->height
,
553 x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
);
556 void image_set_pixels(VGint dx
, VGint dy
,
557 struct vg_image
*src
, VGint sx
, VGint sy
,
558 VGint width
, VGint height
)
560 struct vg_context
*ctx
= vg_current_context();
561 struct pipe_context
*pipe
= ctx
->pipe
;
562 struct pipe_screen
*screen
= pipe
->screen
;
563 struct pipe_surface
*surf
;
564 struct st_renderbuffer
*strb
= ctx
->draw_buffer
->strb
;
566 /* make sure rendering has completed */
567 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
569 surf
= screen
->get_tex_surface(screen
, image_texture(src
), 0, 0, 0,
570 PIPE_BUFFER_USAGE_GPU_READ
);
572 vg_copy_surface(ctx
, strb
->surface
, dx
, dy
,
573 surf
, sx
+src
->x
, sy
+src
->y
, width
, height
);
575 screen
->tex_surface_destroy(surf
);
578 void image_get_pixels(struct vg_image
*dst
, VGint dx
, VGint dy
,
580 VGint width
, VGint height
)
582 struct vg_context
*ctx
= vg_current_context();
583 struct pipe_context
*pipe
= ctx
->pipe
;
584 struct pipe_screen
*screen
= pipe
->screen
;
585 struct pipe_surface
*surf
;
586 struct st_renderbuffer
*strb
= ctx
->draw_buffer
->strb
;
588 /* flip the y coordinates */
589 /*dy = dst->height - dy - height;*/
591 /* make sure rendering has completed */
592 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
594 surf
= screen
->get_tex_surface(screen
, image_texture(dst
), 0, 0, 0,
595 PIPE_BUFFER_USAGE_GPU_WRITE
|
596 PIPE_BUFFER_USAGE_GPU_READ
);
597 vg_copy_surface(ctx
, surf
, dst
->x
+ dx
, dst
->y
+ dy
,
598 strb
->surface
, sx
, sy
, width
, height
);
600 pipe_surface_reference(&surf
, NULL
);
604 VGboolean
vg_image_overlaps(struct vg_image
*dst
,
605 struct vg_image
*src
)
607 if (dst
== src
|| dst
->parent
== src
||
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
;
620 return !(left2
> right1
|| right2
< left1
||
621 top2
> bottom1
|| bottom2
< top1
);
626 VGint
image_bind_samplers(struct vg_image
*img
, struct pipe_sampler_state
**samplers
,
627 struct pipe_texture
**textures
)
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 textures
[3] = img
->texture
;
636 VGint
image_sampler_filter(struct vg_context
*ctx
)
638 switch(ctx
->state
.vg
.image_quality
) {
639 case VG_IMAGE_QUALITY_NONANTIALIASED
:
640 return PIPE_TEX_FILTER_NEAREST
;
642 case VG_IMAGE_QUALITY_FASTER
:
643 return PIPE_TEX_FILTER_NEAREST
;
645 case VG_IMAGE_QUALITY_BETTER
:
646 /*return PIPE_TEX_FILTER_ANISO;*/
647 return PIPE_TEX_FILTER_LINEAR
;
650 debug_printf("Unknown image quality");
652 return PIPE_TEX_FILTER_NEAREST
;