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 **************************************************************************/
31 #include "shaders_cache.h"
34 #include "st_inlines.h"
36 #include "pipe/p_context.h"
37 #include "pipe/p_screen.h"
38 #include "pipe/p_inlines.h"
39 #include "util/u_memory.h"
41 struct vg_mask_layer
{
42 struct vg_object base
;
47 struct pipe_texture
*texture
;
50 static INLINE
struct pipe_surface
*
51 alpha_mask_surface(struct vg_context
*ctx
, int usage
)
53 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
54 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
55 return screen
->get_tex_surface(screen
,
61 static INLINE VGboolean
62 intersect_rectangles(VGint dwidth
, VGint dheight
,
63 VGint swidth
, VGint sheight
,
65 VGint twidth
, VGint theight
,
69 if (tx
+ twidth
<= 0 || tx
>= dwidth
)
71 if (ty
+ theight
<= 0 || ty
>= dheight
)
83 location
[2] = MIN2(tx
+ swidth
, MIN2(dwidth
, tx
+ twidth
));
84 offsets
[2] = location
[2];
86 offsets
[2] = MIN2(twidth
, MIN2(dwidth
- tx
, swidth
));
87 location
[2] = offsets
[2];
94 location
[3] = MIN2(ty
+ sheight
, MIN2(dheight
, ty
+ theight
));
95 offsets
[3] = location
[3];
97 offsets
[3] = MIN2(theight
, MIN2(dheight
- ty
, sheight
));
98 location
[3] = offsets
[3];
105 static void read_alpha_mask(void * data
, VGint dataStride
,
106 VGImageFormat dataFormat
,
108 VGint width
, VGint height
)
110 struct vg_context
*ctx
= vg_current_context();
111 struct pipe_context
*pipe
= ctx
->pipe
;
112 struct pipe_screen
*screen
= pipe
->screen
;
114 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
115 struct st_renderbuffer
*strb
= stfb
->alpha_mask
;
116 struct pipe_framebuffer_state
*fb
= &ctx
->state
.g3d
.fb
;
118 VGfloat temp
[VEGA_MAX_IMAGE_WIDTH
][4];
119 VGfloat
*df
= (VGfloat
*)temp
;
120 VGint y
= (fb
->height
- sy
) - 1, yStep
= -1;
122 VGubyte
*dst
= (VGubyte
*)data
;
123 VGint xoffset
= 0, yoffset
= 0;
125 /* make sure rendering has completed */
126 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
129 xoffset
*= _vega_size_for_format(dataFormat
);
137 y
= (fb
->height
- sy
) - 1;
138 yoffset
*= dataStride
;
142 struct pipe_surface
*surf
;
144 surf
= screen
->get_tex_surface(screen
, strb
->texture
, 0, 0, 0,
145 PIPE_BUFFER_USAGE_CPU_READ
);
147 /* Do a row at a time to flip image data vertically */
148 for (i
= 0; i
< height
; i
++) {
150 debug_printf("%d-%d == %d\n", sy
, height
, y
);
152 pipe_get_tile_rgba(surf
, sx
, y
, width
, 1, df
);
154 _vega_pack_rgba_span_float(ctx
, width
, temp
, dataFormat
,
155 dst
+ yoffset
+ xoffset
);
159 pipe_surface_reference(&surf
, NULL
);
163 void save_alpha_to_file(const char *filename
)
165 struct vg_context
*ctx
= vg_current_context();
166 struct pipe_framebuffer_state
*fb
= &ctx
->state
.g3d
.fb
;
170 data
= malloc(sizeof(int) * fb
->width
* fb
->height
);
171 read_alpha_mask(data
, fb
->width
* sizeof(int),
173 0, 0, fb
->width
, fb
->height
);
174 fprintf(stderr
, "/*---------- start */\n");
175 fprintf(stderr
, "const int image_width = %d;\n",
177 fprintf(stderr
, "const int image_height = %d;\n",
179 fprintf(stderr
, "const int image_data = {\n");
180 for (i
= 0; i
< fb
->height
; ++i
) {
181 for (j
= 0; j
< fb
->width
; ++j
) {
182 int rgba
= data
[i
* fb
->height
+ j
];
185 argb
|= ((rgba
& 0xff) << 24);
186 fprintf(stderr
, "0x%x, ", argb
);
188 fprintf(stderr
, "\n");
190 fprintf(stderr
, "};\n");
191 fprintf(stderr
, "/*---------- end */\n");
195 static void setup_mask_framebuffer(struct pipe_surface
*surf
,
196 VGint surf_width
, VGint surf_height
)
198 struct vg_context
*ctx
= vg_current_context();
199 struct pipe_framebuffer_state fb
;
201 memset(&fb
, 0, sizeof(fb
));
202 fb
.width
= surf_width
;
203 fb
.height
= surf_height
;
208 for (i
= 1; i
< PIPE_MAX_COLOR_BUFS
; ++i
)
211 cso_set_framebuffer(ctx
->cso_context
, &fb
);
215 /* setup shader constants */
216 static void setup_mask_operation(VGMaskOperation operation
)
218 struct vg_context
*ctx
= vg_current_context();
219 struct pipe_constant_buffer
*cbuf
= &ctx
->mask
.cbuf
;
220 const VGint param_bytes
= 4 * sizeof(VGfloat
);
221 const VGfloat ones
[4] = {1.f
, 1.f
, 1.f
, 1.f
};
224 /* We always need to get a new buffer, to keep the drivers simple and
225 * avoid gratuitous rendering synchronization.
227 pipe_buffer_reference(&cbuf
->buffer
, NULL
);
229 cbuf
->buffer
= pipe_buffer_create(ctx
->pipe
->screen
, 1,
230 PIPE_BUFFER_USAGE_CONSTANT
,
233 st_no_flush_pipe_buffer_write(ctx
, cbuf
->buffer
,
234 0, param_bytes
, ones
);
237 ctx
->pipe
->set_constant_buffer(ctx
->pipe
, PIPE_SHADER_FRAGMENT
, 0, cbuf
);
239 case VG_UNION_MASK
: {
240 if (!ctx
->mask
.union_fs
) {
241 ctx
->mask
.union_fs
= shader_create_from_text(ctx
->pipe
,
244 PIPE_SHADER_FRAGMENT
);
246 shader
= ctx
->mask
.union_fs
->driver
;
249 case VG_INTERSECT_MASK
: {
250 if (!ctx
->mask
.intersect_fs
) {
251 ctx
->mask
.intersect_fs
= shader_create_from_text(ctx
->pipe
,
254 PIPE_SHADER_FRAGMENT
);
256 shader
= ctx
->mask
.intersect_fs
->driver
;
259 case VG_SUBTRACT_MASK
: {
260 if (!ctx
->mask
.subtract_fs
) {
261 ctx
->mask
.subtract_fs
= shader_create_from_text(ctx
->pipe
,
264 PIPE_SHADER_FRAGMENT
);
266 shader
= ctx
->mask
.subtract_fs
->driver
;
270 if (!ctx
->mask
.set_fs
) {
271 ctx
->mask
.set_fs
= shader_create_from_text(ctx
->pipe
,
274 PIPE_SHADER_FRAGMENT
);
276 shader
= ctx
->mask
.set_fs
->driver
;
283 cso_set_fragment_shader_handle(ctx
->cso_context
, shader
);
286 static void setup_mask_samplers(struct pipe_texture
*umask
)
288 struct vg_context
*ctx
= vg_current_context();
289 struct pipe_sampler_state
*samplers
[PIPE_MAX_SAMPLERS
];
290 struct pipe_texture
*textures
[PIPE_MAX_SAMPLERS
];
291 struct st_framebuffer
*fb_buffers
= ctx
->draw_buffer
;
292 struct pipe_texture
*uprev
= NULL
;
293 struct pipe_sampler_state sampler
;
295 uprev
= fb_buffers
->blend_texture
;
296 sampler
= ctx
->mask
.sampler
;
297 sampler
.normalized_coords
= 1;
306 samplers
[0] = &sampler
;
307 samplers
[1] = &ctx
->mask
.sampler
;
312 cso_set_samplers(ctx
->cso_context
, 2,
313 (const struct pipe_sampler_state
**)samplers
);
314 cso_set_sampler_textures(ctx
->cso_context
, 2, textures
);
318 /* setup shader constants */
319 static void setup_mask_fill(const VGfloat color
[4])
321 struct vg_context
*ctx
= vg_current_context();
322 struct pipe_constant_buffer
*cbuf
= &ctx
->mask
.cbuf
;
323 const VGint param_bytes
= 4 * sizeof(VGfloat
);
325 /* We always need to get a new buffer, to keep the drivers simple and
326 * avoid gratuitous rendering synchronization.
328 pipe_buffer_reference(&cbuf
->buffer
, NULL
);
330 cbuf
->buffer
= pipe_buffer_create(ctx
->pipe
->screen
, 1,
331 PIPE_BUFFER_USAGE_CONSTANT
,
334 st_no_flush_pipe_buffer_write(ctx
, cbuf
->buffer
, 0, param_bytes
, color
);
337 ctx
->pipe
->set_constant_buffer(ctx
->pipe
, PIPE_SHADER_FRAGMENT
, 0, cbuf
);
338 cso_set_fragment_shader_handle(ctx
->cso_context
,
339 shaders_cache_fill(ctx
->sc
,
340 VEGA_SOLID_FILL_SHADER
));
343 static void setup_mask_viewport()
345 struct vg_context
*ctx
= vg_current_context();
346 vg_set_viewport(ctx
, VEGA_Y0_TOP
);
349 static void setup_mask_blend()
351 struct vg_context
*ctx
= vg_current_context();
353 struct pipe_blend_state blend
;
355 memset(&blend
, 0, sizeof(struct pipe_blend_state
));
356 blend
.blend_enable
= 1;
357 blend
.colormask
|= PIPE_MASK_R
;
358 blend
.colormask
|= PIPE_MASK_G
;
359 blend
.colormask
|= PIPE_MASK_B
;
360 blend
.colormask
|= PIPE_MASK_A
;
361 blend
.rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
362 blend
.alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
363 blend
.rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
364 blend
.alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
366 cso_set_blend(ctx
->cso_context
, &blend
);
370 static void surface_fill(struct pipe_surface
*surf
,
371 int surf_width
, int surf_height
,
372 int x
, int y
, int width
, int height
,
373 const VGfloat color
[4])
375 struct vg_context
*ctx
= vg_current_context();
386 cso_save_framebuffer(ctx
->cso_context
);
387 cso_save_blend(ctx
->cso_context
);
388 cso_save_fragment_shader(ctx
->cso_context
);
389 cso_save_viewport(ctx
->cso_context
);
392 setup_mask_fill(color
);
393 setup_mask_framebuffer(surf
, surf_width
, surf_height
);
394 setup_mask_viewport();
396 renderer_draw_quad(ctx
->renderer
, x
, y
,
397 x
+ width
, y
+ height
, 0.0f
/*depth should be disabled*/);
400 /* make sure rendering has completed */
401 ctx
->pipe
->flush(ctx
->pipe
,
402 PIPE_FLUSH_RENDER_CACHE
| PIPE_FLUSH_FRAME
,
406 save_alpha_to_file(0);
409 cso_restore_blend(ctx
->cso_context
);
410 cso_restore_framebuffer(ctx
->cso_context
);
411 cso_restore_fragment_shader(ctx
->cso_context
);
412 cso_restore_viewport(ctx
->cso_context
);
416 static void mask_using_texture(struct pipe_texture
*texture
,
417 VGMaskOperation operation
,
419 VGint width
, VGint height
)
421 struct vg_context
*ctx
= vg_current_context();
422 struct pipe_surface
*surface
=
423 alpha_mask_surface(ctx
, PIPE_BUFFER_USAGE_GPU_WRITE
);
424 VGint offsets
[4], loc
[4];
428 if (!intersect_rectangles(surface
->width
, surface
->height
,
429 texture
->width
[0], texture
->height
[0],
434 debug_printf("Offset = [%d, %d, %d, %d]\n", offsets
[0],
435 offsets
[1], offsets
[2], offsets
[3]);
436 debug_printf("Locati = [%d, %d, %d, %d]\n", loc
[0],
437 loc
[1], loc
[2], loc
[3]);
440 /* prepare our blend surface */
441 vg_prepare_blend_surface_from_mask(ctx
);
443 cso_save_samplers(ctx
->cso_context
);
444 cso_save_sampler_textures(ctx
->cso_context
);
445 cso_save_framebuffer(ctx
->cso_context
);
446 cso_save_blend(ctx
->cso_context
);
447 cso_save_fragment_shader(ctx
->cso_context
);
448 cso_save_viewport(ctx
->cso_context
);
450 setup_mask_samplers(texture
);
452 setup_mask_operation(operation
);
453 setup_mask_framebuffer(surface
, surface
->width
, surface
->height
);
454 setup_mask_viewport();
456 /* render the quad to propagate the rendering from stencil */
457 renderer_draw_texture(ctx
->renderer
, texture
,
458 offsets
[0], offsets
[1],
459 offsets
[0] + offsets
[2], offsets
[1] + offsets
[3],
460 loc
[0], loc
[1], loc
[0] + loc
[2], loc
[1] + loc
[3]);
462 /* make sure rendering has completed */
463 ctx
->pipe
->flush(ctx
->pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
464 cso_restore_blend(ctx
->cso_context
);
465 cso_restore_framebuffer(ctx
->cso_context
);
466 cso_restore_fragment_shader(ctx
->cso_context
);
467 cso_restore_samplers(ctx
->cso_context
);
468 cso_restore_sampler_textures(ctx
->cso_context
);
469 cso_restore_viewport(ctx
->cso_context
);
471 pipe_surface_reference(&surface
, NULL
);
475 #ifdef OPENVG_VERSION_1_1
477 struct vg_mask_layer
* mask_layer_create(VGint width
, VGint height
)
479 struct vg_context
*ctx
= vg_current_context();
480 struct vg_mask_layer
*mask
= 0;
482 mask
= CALLOC_STRUCT(vg_mask_layer
);
483 vg_init_object(&mask
->base
, ctx
, VG_OBJECT_MASK
);
485 mask
->height
= height
;
488 struct pipe_texture pt
;
489 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
491 memset(&pt
, 0, sizeof(pt
));
492 pt
.target
= PIPE_TEXTURE_2D
;
493 pt
.format
= PIPE_FORMAT_A8R8G8B8_UNORM
;
494 pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM
, &pt
.block
);
497 pt
.height
[0] = height
;
499 pt
.tex_usage
= PIPE_TEXTURE_USAGE_SAMPLER
;
502 mask
->texture
= screen
->texture_create(screen
, &pt
);
505 vg_context_add_object(ctx
, VG_OBJECT_MASK
, mask
);
510 void mask_layer_destroy(struct vg_mask_layer
*layer
)
512 struct vg_context
*ctx
= vg_current_context();
514 vg_context_remove_object(ctx
, VG_OBJECT_MASK
, layer
);
515 pipe_texture_release(&layer
->texture
);
519 void mask_layer_fill(struct vg_mask_layer
*layer
,
521 VGint width
, VGint height
,
524 struct vg_context
*ctx
= vg_current_context();
525 VGfloat alpha_color
[4] = {0, 0, 0, 0};
526 struct pipe_surface
*surface
;
528 alpha_color
[3] = value
;
530 surface
= ctx
->pipe
->screen
->get_tex_surface(
531 ctx
->pipe
->screen
, layer
->texture
,
533 PIPE_BUFFER_USAGE_GPU_WRITE
);
535 surface_fill(surface
,
536 layer
->width
, layer
->height
,
537 x
, y
, width
, height
, alpha_color
);
539 ctx
->pipe
->screen
->tex_surface_release(ctx
->pipe
->screen
, &surface
);
542 void mask_copy(struct vg_mask_layer
*layer
,
545 VGint width
, VGint height
)
547 struct vg_context
*ctx
= vg_current_context();
548 struct st_framebuffer
*fb_buffers
= ctx
->draw_buffer
;
550 renderer_copy_texture(ctx
->renderer
,
553 sx
+ width
, sy
+ height
,
554 fb_buffers
->alpha_mask
,
556 dx
+ width
, dy
+ height
);
559 static void mask_layer_render_to(struct vg_mask_layer
*layer
,
561 VGbitfield paint_modes
)
563 struct vg_context
*ctx
= vg_current_context();
564 const VGfloat fill_color
[4] = {1.f
, 1.f
, 1.f
, 1.f
};
565 struct pipe_screen
*screen
= ctx
->pipe
->screen
;
566 struct pipe_surface
*surface
;
568 surface
= screen
->get_tex_surface(screen
, layer
->texture
, 0, 0, 0,
569 PIPE_BUFFER_USAGE_GPU_WRITE
);
571 cso_save_framebuffer(ctx
->cso_context
);
572 cso_save_fragment_shader(ctx
->cso_context
);
573 cso_save_viewport(ctx
->cso_context
);
576 setup_mask_fill(fill_color
);
577 setup_mask_framebuffer(surface
, layer
->width
, layer
->height
);
578 setup_mask_viewport();
580 if (paint_modes
& VG_FILL_PATH
) {
581 struct matrix
*mat
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
582 path_fill(path
, mat
);
585 if (paint_modes
& VG_STROKE_PATH
){
590 /* make sure rendering has completed */
591 ctx
->pipe
->flush(ctx
->pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
593 cso_restore_framebuffer(ctx
->cso_context
);
594 cso_restore_fragment_shader(ctx
->cso_context
);
595 cso_restore_viewport(ctx
->cso_context
);
596 ctx
->state
.dirty
|= BLEND_DIRTY
;
598 screen
->tex_surface_release(ctx
->pipe
->screen
, &surface
);
601 void mask_render_to(struct path
*path
,
602 VGbitfield paint_modes
,
603 VGMaskOperation operation
)
605 struct vg_context
*ctx
= vg_current_context();
606 struct st_framebuffer
*fb_buffers
= ctx
->draw_buffer
;
607 struct vg_mask_layer
*temp_layer
;
610 width
= fb_buffers
->alpha_mask
->width
[0];
611 height
= fb_buffers
->alpha_mask
->width
[0];
613 temp_layer
= mask_layer_create(width
, height
);
615 mask_layer_render_to(temp_layer
, path
, paint_modes
);
617 mask_using_layer(temp_layer
, 0, 0, width
, height
,
620 mask_layer_destroy(temp_layer
);
623 void mask_using_layer(struct vg_mask_layer
*layer
,
624 VGMaskOperation operation
,
626 VGint width
, VGint height
)
628 mask_using_texture(layer
->texture
, operation
,
629 x
, y
, width
, height
);
632 VGint
mask_layer_width(struct vg_mask_layer
*layer
)
637 VGint
mask_layer_height(struct vg_mask_layer
*layer
)
639 return layer
->height
;
645 void mask_using_image(struct vg_image
*image
,
646 VGMaskOperation operation
,
648 VGint width
, VGint height
)
650 mask_using_texture(image
->texture
, operation
,
651 x
, y
, width
, height
);
654 void mask_fill(VGint x
, VGint y
, VGint width
, VGint height
,
657 struct vg_context
*ctx
= vg_current_context();
658 VGfloat alpha_color
[4] = {.0f
, .0f
, .0f
, value
};
659 struct pipe_surface
*surf
= alpha_mask_surface(
660 ctx
, PIPE_BUFFER_USAGE_GPU_WRITE
);
663 debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n",
665 alpha_color
[0], alpha_color
[1],
666 alpha_color
[2], alpha_color
[3]);
667 debug_printf("XXX %f === %f \n",
668 alpha_color
[3], value
);
671 surface_fill(surf
, surf
->width
, surf
->height
,
672 x
, y
, width
, height
, alpha_color
);
674 pipe_surface_reference(&surf
, NULL
);
677 VGint
mask_bind_samplers(struct pipe_sampler_state
**samplers
,
678 struct pipe_texture
**textures
)
680 struct vg_context
*ctx
= vg_current_context();
682 if (ctx
->state
.vg
.masking
) {
683 struct st_framebuffer
*fb_buffers
= ctx
->draw_buffer
;
685 samplers
[1] = &ctx
->mask
.sampler
;
686 textures
[1] = fb_buffers
->alpha_mask
;