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"
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"
47 static enum pipe_format
vg_format_to_pipe(VGImageFormat format
)
51 return PIPE_FORMAT_B5G6R5_UNORM
;
53 return PIPE_FORMAT_B5G5R5A1_UNORM
;
55 return PIPE_FORMAT_B4G4R4A4_UNORM
;
58 return PIPE_FORMAT_L8_UNORM
;
60 return PIPE_FORMAT_B8G8R8A8_UNORM
;
62 return PIPE_FORMAT_A8_UNORM
;
63 #ifdef OPENVG_VERSION_1_1
66 return PIPE_FORMAT_A8_UNORM
;
69 return PIPE_FORMAT_B8G8R8A8_UNORM
;
73 static INLINE
void vg_sync_size(VGfloat
*src_loc
, VGfloat
*dst_loc
)
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];
81 static void vg_get_copy_coords(VGfloat
*src_loc
,
82 VGfloat src_width
, VGfloat src_height
,
84 VGfloat dst_width
, VGfloat dst_height
)
86 VGfloat dst_bounds
[4], src_bounds
[4];
87 VGfloat src_shift
[4], dst_shift
[4], shift
[4];
91 dst_bounds
[2] = dst_width
;
92 dst_bounds
[3] = dst_height
;
96 src_bounds
[2] = src_width
;
97 src_bounds
[3] = src_height
;
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];
105 vg_shift_rectx(src_loc
, src_bounds
, -shift
[0]);
107 vg_shift_rectx(dst_loc
, dst_bounds
, shift
[0]);
110 vg_shift_recty(src_loc
, src_bounds
, -shift
[1]);
112 vg_shift_recty(dst_loc
, dst_bounds
, shift
[1]);
114 vg_sync_size(src_loc
, dst_loc
);
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
)
122 VGfloat dst_loc
[4], src_loc
[4];
134 vg_get_copy_coords(src_loc
, src
->texture
->width0
, src
->texture
->height0
,
135 dst_loc
, dst
->width0
, dst
->height0
);
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
;
141 /* get the destination surface */
142 u_surface_default_template(&surf_tmpl
, dst
, PIPE_BIND_RENDER_TARGET
);
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
);
151 pipe_surface_reference(&surf
, NULL
);
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
)
160 VGfloat dst_loc
[4], src_loc
[4];
172 vg_get_copy_coords(src_loc
, src
->width
, src
->height
,
173 dst_loc
, dst
->width
, dst
->height
);
175 if (src_loc
[2] > 0 && src_loc
[3] > 0 &&
176 dst_loc
[2] > 0 && dst_loc
[3] > 0) {
178 renderer_copy_surface(ctx
->renderer
,
181 src
->height
- (src_loc
[1] + src_loc
[3]),
182 src_loc
[0] + src_loc
[2],
183 src
->height
- src_loc
[1],
186 dst
->height
- (dst_loc
[1] + dst_loc
[3]),
187 dst_loc
[0] + dst_loc
[2],
188 dst
->height
- dst_loc
[1],
191 renderer_copy_surface(ctx
->renderer
,
194 src
->height
- src_loc
[1],
195 src_loc
[0] + src_loc
[2],
196 src
->height
- (src_loc
[1] + src_loc
[3]),
199 dst
->height
- (dst_loc
[1] + dst_loc
[3]),
200 dst_loc
[0] + dst_loc
[2],
201 dst
->height
- dst_loc
[1],
207 static struct pipe_resource
*image_texture(struct vg_image
*img
)
209 struct pipe_resource
*tex
= img
->sampler_view
->texture
;
214 static void image_cleari(struct vg_image
*img
, VGint clear_colori
,
215 VGint x
, VGint y
, VGint width
, VGint height
)
219 VGfloat dwidth
, dheight
;
221 clearbuf
= malloc(sizeof(VGint
)*width
*height
);
222 for (i
= 0; i
< width
*height
; ++i
)
223 clearbuf
[i
] = clear_colori
;
225 dwidth
= MIN2(width
, img
->width
);
226 dheight
= MIN2(height
, img
->height
);
228 image_sub_data(img
, clearbuf
, width
* sizeof(VGint
),
230 x
, y
, dwidth
, dheight
);
234 struct vg_image
* image_create(VGImageFormat format
,
235 VGint width
, VGint height
)
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
;
246 vg_init_object(&image
->base
, ctx
, VG_OBJECT_IMAGE
);
248 image
->format
= format
;
249 image
->width
= width
;
250 image
->height
= height
;
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;
259 assert(screen
->is_format_supported(screen
, pformat
, PIPE_TEXTURE_2D
,
260 0, PIPE_BIND_SAMPLER_VIEW
));
262 memset(&pt
, 0, sizeof(pt
));
263 pt
.target
= PIPE_TEXTURE_2D
;
270 pt
.bind
= PIPE_BIND_SAMPLER_VIEW
;
272 newtex
= screen
->resource_create(screen
, &pt
);
274 debug_assert(newtex
);
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
;
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
);
288 image
->sampler_view
= view
;
290 vg_context_add_object(ctx
, VG_OBJECT_IMAGE
, image
);
292 image_cleari(image
, 0, 0, 0, image
->width
, image
->height
);
296 void image_destroy(struct vg_image
*img
)
298 struct vg_context
*ctx
= vg_current_context();
299 vg_context_remove_object(ctx
, VG_OBJECT_IMAGE
, img
);
303 /* remove img from the parent child array */
305 struct vg_image
**array
=
306 (struct vg_image
**)img
->parent
->children_array
->data
;
308 for (idx
= 0; idx
< img
->parent
->children_array
->num_elements
; ++idx
) {
309 struct vg_image
*child
= array
[idx
];
314 debug_assert(idx
< img
->parent
->children_array
->num_elements
);
315 array_remove_element(img
->parent
->children_array
, idx
);
318 if (img
->children_array
&& img
->children_array
->num_elements
) {
319 /* reparent the children */
321 struct vg_image
*parent
= img
->parent
;
322 struct vg_image
**children
=
323 (struct vg_image
**)img
->children_array
->data
;
325 VGint min_x
= children
[0]->x
;
326 parent
= children
[0];
328 for (i
= 1; i
< img
->children_array
->num_elements
; ++i
) {
329 struct vg_image
*child
= children
[i
];
330 if (child
->x
< min_x
) {
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
*));
344 array_append_data(parent
->children_array
,
347 child
->parent
= NULL
;
349 array_destroy(img
->children_array
);
352 vg_free_object(&img
->base
);
354 pipe_sampler_view_reference(&img
->sampler_view
, NULL
);
358 void image_clear(struct vg_image
*img
,
359 VGint x
, VGint y
, VGint width
, VGint height
)
361 struct vg_context
*ctx
= vg_current_context();
362 VGfloat
*clear_colorf
= ctx
->state
.vg
.clear_color
;
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
);
374 void image_sub_data(struct vg_image
*image
,
377 VGImageFormat dataFormat
,
379 VGint width
, VGint height
)
381 const VGint yStep
= 1;
382 VGubyte
*src
= (VGubyte
*)data
;
383 VGfloat temp
[VEGA_MAX_IMAGE_WIDTH
][4];
384 VGfloat
*df
= (VGfloat
*)temp
;
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;
402 if (width
<= 0 || height
<= 0) {
403 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
407 if (x
> image
->width
|| y
> image
->width
) {
408 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
412 if (x
+ width
> image
->width
) {
413 width
= image
->width
- x
;
416 if (y
+ height
> image
->height
) {
417 height
= image
->height
- y
;
420 { /* upload color_data */
421 struct pipe_transfer
*transfer
= pipe_get_transfer(
423 PIPE_TRANSFER_WRITE
, 0, 0, texture
->width0
, texture
->height0
);
424 src
+= (dataStride
* yoffset
);
425 for (i
= 0; i
< height
; i
++) {
426 _vega_unpack_float_span_rgba(ctx
, width
, xoffset
, src
, dataFormat
, temp
);
427 pipe_put_tile_rgba(pipe
, transfer
, x
+image
->x
, y
+image
->y
, width
, 1, df
);
431 pipe
->transfer_destroy(pipe
, transfer
);
435 void image_get_sub_data(struct vg_image
* image
,
438 VGImageFormat dataFormat
,
440 VGint width
, VGint height
)
442 struct vg_context
*ctx
= vg_current_context();
443 struct pipe_context
*pipe
= ctx
->pipe
;
444 VGfloat temp
[VEGA_MAX_IMAGE_WIDTH
][4];
445 VGfloat
*df
= (VGfloat
*)temp
;
446 VGint y
= 0, yStep
= 1;
448 VGubyte
*dst
= (VGubyte
*)data
;
451 struct pipe_transfer
*transfer
=
452 pipe_get_transfer(pipe
,
453 image
->sampler_view
->texture
, 0, 0,
456 image
->x
+ image
->width
,
457 image
->y
+ image
->height
);
458 /* Do a row at a time to flip image data vertically */
459 for (i
= 0; i
< height
; i
++) {
461 debug_printf("%d-%d == %d\n", sy
, height
, y
);
463 pipe_get_tile_rgba(pipe
, transfer
, sx
+image
->x
, y
, width
, 1, df
);
465 _vega_pack_rgba_span_float(ctx
, width
, temp
, dataFormat
, dst
);
469 pipe
->transfer_destroy(pipe
, transfer
);
473 struct vg_image
* image_child_image(struct vg_image
*parent
,
475 VGint width
, VGint height
)
477 struct vg_context
*ctx
= vg_current_context();
478 struct vg_image
*image
= CALLOC_STRUCT(vg_image
);
480 vg_init_object(&image
->base
, ctx
, VG_OBJECT_IMAGE
);
482 image
->x
= parent
->x
+ x
;
483 image
->y
= parent
->y
+ y
;
484 image
->width
= width
;
485 image
->height
= height
;
486 image
->parent
= parent
;
487 image
->sampler_view
= NULL
;
488 pipe_sampler_view_reference(&image
->sampler_view
,
489 parent
->sampler_view
);
491 image
->sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
492 image
->sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
493 image
->sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
494 image
->sampler
.min_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
495 image
->sampler
.mag_img_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
496 image
->sampler
.normalized_coords
= 1;
498 if (!parent
->children_array
)
499 parent
->children_array
= array_create(
500 sizeof(struct vg_image
*));
502 array_append_data(parent
->children_array
,
505 vg_context_add_object(ctx
, VG_OBJECT_IMAGE
, image
);
510 void image_copy(struct vg_image
*dst
, VGint dx
, VGint dy
,
511 struct vg_image
*src
, VGint sx
, VGint sy
,
512 VGint width
, VGint height
,
515 struct vg_context
*ctx
= vg_current_context();
517 if (width
<= 0 || height
<= 0) {
518 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
521 vg_copy_texture(ctx
, dst
->sampler_view
->texture
, dst
->x
+ dx
, dst
->y
+ dy
,
522 src
->sampler_view
, src
->x
+ sx
, src
->y
+ sy
, width
, height
);
525 void image_draw(struct vg_image
*img
, struct matrix
*matrix
)
527 struct vg_context
*ctx
= vg_current_context();
528 struct matrix paint_matrix
;
534 if (!vg_get_paint_matrix(ctx
,
535 &ctx
->state
.vg
.fill_paint_to_user_matrix
,
549 shader_set_surface_matrix(ctx
->shader
, matrix
);
550 shader_set_drawing_image(ctx
->shader
, VG_TRUE
);
551 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
552 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
553 shader_set_image(ctx
->shader
, img
);
554 shader_bind(ctx
->shader
);
556 renderer_texture_quad(ctx
->renderer
, image_texture(img
),
557 img
->x
, img
->y
, img
->x
+ img
->width
, img
->y
+ img
->height
,
558 x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
);
561 void image_set_pixels(VGint dx
, VGint dy
,
562 struct vg_image
*src
, VGint sx
, VGint sy
,
563 VGint width
, VGint height
)
565 struct vg_context
*ctx
= vg_current_context();
566 struct pipe_context
*pipe
= ctx
->pipe
;
567 struct pipe_surface
*surf
, surf_tmpl
;
568 struct st_renderbuffer
*strb
= ctx
->draw_buffer
->strb
;
570 memset(&surf_tmpl
, 0, sizeof(surf_tmpl
));
571 u_surface_default_template(&surf_tmpl
, image_texture(src
),
572 0 /* no bind flag - not a surface*/);
573 surf
= pipe
->create_surface(pipe
, image_texture(src
), &surf_tmpl
);
575 vg_copy_surface(ctx
, strb
->surface
, dx
, dy
,
576 surf
, sx
+src
->x
, sy
+src
->y
, width
, height
);
578 pipe
->surface_destroy(pipe
, surf
);
581 void image_get_pixels(struct vg_image
*dst
, VGint dx
, VGint dy
,
583 VGint width
, VGint height
)
585 struct vg_context
*ctx
= vg_current_context();
586 struct pipe_context
*pipe
= ctx
->pipe
;
587 struct pipe_surface
*surf
, surf_tmpl
;
588 struct st_renderbuffer
*strb
= ctx
->draw_buffer
->strb
;
590 /* flip the y coordinates */
591 /*dy = dst->height - dy - height;*/
593 memset(&surf_tmpl
, 0, sizeof(surf_tmpl
));
594 u_surface_default_template(&surf_tmpl
, image_texture(dst
),
595 PIPE_BIND_RENDER_TARGET
);
596 surf
= pipe
->create_surface(pipe
, image_texture(dst
), &surf_tmpl
);
598 vg_copy_surface(ctx
, surf
, dst
->x
+ dx
, dst
->y
+ dy
,
599 strb
->surface
, sx
, sy
, width
, height
);
601 pipe_surface_reference(&surf
, NULL
);
605 VGboolean
vg_image_overlaps(struct vg_image
*dst
,
606 struct vg_image
*src
)
608 if (dst
== src
|| dst
->parent
== src
||
611 if (dst
->parent
&& dst
->parent
== src
->parent
) {
612 VGfloat left1
= dst
->x
;
613 VGfloat left2
= src
->x
;
614 VGfloat right1
= dst
->x
+ dst
->width
;
615 VGfloat right2
= src
->x
+ src
->width
;
616 VGfloat bottom1
= dst
->y
;
617 VGfloat bottom2
= src
->y
;
618 VGfloat top1
= dst
->y
+ dst
->height
;
619 VGfloat top2
= src
->y
+ src
->height
;
621 return !(left2
> right1
|| right2
< left1
||
622 top2
> bottom1
|| bottom2
< top1
);
627 VGint
image_bind_samplers(struct vg_image
*img
, struct pipe_sampler_state
**samplers
,
628 struct pipe_sampler_view
**sampler_views
)
630 img
->sampler
.min_img_filter
= image_sampler_filter(img
->base
.ctx
);
631 img
->sampler
.mag_img_filter
= image_sampler_filter(img
->base
.ctx
);
632 samplers
[3] = &img
->sampler
;
633 sampler_views
[3] = img
->sampler_view
;
637 VGint
image_sampler_filter(struct vg_context
*ctx
)
639 switch(ctx
->state
.vg
.image_quality
) {
640 case VG_IMAGE_QUALITY_NONANTIALIASED
:
641 return PIPE_TEX_FILTER_NEAREST
;
643 case VG_IMAGE_QUALITY_FASTER
:
644 return PIPE_TEX_FILTER_NEAREST
;
646 case VG_IMAGE_QUALITY_BETTER
:
647 /* possibly use anisotropic filtering */
648 return PIPE_TEX_FILTER_LINEAR
;
651 debug_printf("Unknown image quality");
653 return PIPE_TEX_FILTER_NEAREST
;