| /************************************************************************** |
| * |
| * Copyright 2009 VMware, Inc. All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include "mask.h" |
| |
| #include "path.h" |
| #include "image.h" |
| #include "shaders_cache.h" |
| #include "renderer.h" |
| #include "asm_util.h" |
| #include "st_inlines.h" |
| |
| #include "pipe/p_context.h" |
| #include "pipe/p_screen.h" |
| #include "util/u_inlines.h" |
| #include "util/u_format.h" |
| #include "util/u_memory.h" |
| |
| struct vg_mask_layer { |
| struct vg_object base; |
| |
| VGint width; |
| VGint height; |
| |
| struct pipe_sampler_view *sampler_view; |
| }; |
| |
| static INLINE struct pipe_surface * |
| alpha_mask_surface(struct vg_context *ctx, int usage) |
| { |
| struct pipe_screen *screen = ctx->pipe->screen; |
| struct st_framebuffer *stfb = ctx->draw_buffer; |
| return screen->get_tex_surface(screen, |
| stfb->alpha_mask_view->texture, |
| 0, 0, 0, |
| usage); |
| } |
| |
| static INLINE VGboolean |
| intersect_rectangles(VGint dwidth, VGint dheight, |
| VGint swidth, VGint sheight, |
| VGint tx, VGint ty, |
| VGint twidth, VGint theight, |
| VGint *offsets, |
| VGint *location) |
| { |
| if (tx + twidth <= 0 || tx >= dwidth) |
| return VG_FALSE; |
| if (ty + theight <= 0 || ty >= dheight) |
| return VG_FALSE; |
| |
| offsets[0] = 0; |
| offsets[1] = 0; |
| location[0] = tx; |
| location[1] = ty; |
| |
| if (tx < 0) { |
| offsets[0] -= tx; |
| location[0] = 0; |
| |
| location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth)); |
| offsets[2] = location[2]; |
| } else { |
| offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth )); |
| location[2] = offsets[2]; |
| } |
| |
| if (ty < 0) { |
| offsets[1] -= ty; |
| location[1] = 0; |
| |
| location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight)); |
| offsets[3] = location[3]; |
| } else { |
| offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight)); |
| location[3] = offsets[3]; |
| } |
| |
| return VG_TRUE; |
| } |
| |
| #if DEBUG_MASKS |
| static void read_alpha_mask(void * data, VGint dataStride, |
| VGImageFormat dataFormat, |
| VGint sx, VGint sy, |
| VGint width, VGint height) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_context *pipe = ctx->pipe; |
| struct pipe_screen *screen = pipe->screen; |
| |
| struct st_framebuffer *stfb = ctx->draw_buffer; |
| struct st_renderbuffer *strb = stfb->alpha_mask; |
| struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; |
| |
| VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; |
| VGfloat *df = (VGfloat*)temp; |
| VGint y = (fb->height - sy) - 1, yStep = -1; |
| VGint i; |
| VGubyte *dst = (VGubyte *)data; |
| VGint xoffset = 0, yoffset = 0; |
| |
| /* make sure rendering has completed */ |
| pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); |
| if (sx < 0) { |
| xoffset = -sx; |
| xoffset *= _vega_size_for_format(dataFormat); |
| width += sx; |
| sx = 0; |
| } |
| if (sy < 0) { |
| yoffset = -sy; |
| height += sy; |
| sy = 0; |
| y = (fb->height - sy) - 1; |
| yoffset *= dataStride; |
| } |
| |
| { |
| struct pipe_surface *surf; |
| |
| surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, |
| PIPE_BIND_TRANSFER_READ); |
| |
| /* Do a row at a time to flip image data vertically */ |
| for (i = 0; i < height; i++) { |
| #if 0 |
| debug_printf("%d-%d == %d\n", sy, height, y); |
| #endif |
| pipe_get_tile_rgba(surf, sx, y, width, 1, df); |
| y += yStep; |
| _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, |
| dst + yoffset + xoffset); |
| dst += dataStride; |
| } |
| |
| pipe_surface_reference(&surf, NULL); |
| } |
| } |
| |
| void save_alpha_to_file(const char *filename) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; |
| VGint *data; |
| int i, j; |
| |
| data = malloc(sizeof(int) * fb->width * fb->height); |
| read_alpha_mask(data, fb->width * sizeof(int), |
| VG_sRGBA_8888, |
| 0, 0, fb->width, fb->height); |
| fprintf(stderr, "/*---------- start */\n"); |
| fprintf(stderr, "const int image_width = %d;\n", |
| fb->width); |
| fprintf(stderr, "const int image_height = %d;\n", |
| fb->height); |
| fprintf(stderr, "const int image_data = {\n"); |
| for (i = 0; i < fb->height; ++i) { |
| for (j = 0; j < fb->width; ++j) { |
| int rgba = data[i * fb->height + j]; |
| int argb = 0; |
| argb = (rgba >> 8); |
| argb |= ((rgba & 0xff) << 24); |
| fprintf(stderr, "0x%x, ", argb); |
| } |
| fprintf(stderr, "\n"); |
| } |
| fprintf(stderr, "};\n"); |
| fprintf(stderr, "/*---------- end */\n"); |
| } |
| #endif |
| |
| static void setup_mask_framebuffer(struct pipe_surface *surf, |
| VGint surf_width, VGint surf_height) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_framebuffer_state fb; |
| |
| memset(&fb, 0, sizeof(fb)); |
| fb.width = surf_width; |
| fb.height = surf_height; |
| fb.nr_cbufs = 1; |
| fb.cbufs[0] = surf; |
| { |
| VGint i; |
| for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) |
| fb.cbufs[i] = 0; |
| } |
| cso_set_framebuffer(ctx->cso_context, &fb); |
| } |
| |
| |
| /* setup shader constants */ |
| static void setup_mask_operation(VGMaskOperation operation) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_resource **cbuf = &ctx->mask.cbuf; |
| const VGint param_bytes = 4 * sizeof(VGfloat); |
| const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; |
| void *shader = 0; |
| |
| /* We always need to get a new buffer, to keep the drivers simple and |
| * avoid gratuitous rendering synchronization. |
| */ |
| pipe_resource_reference(cbuf, NULL); |
| |
| *cbuf = pipe_buffer_create(ctx->pipe->screen, |
| PIPE_BIND_CONSTANT_BUFFER, |
| param_bytes); |
| if (*cbuf) { |
| st_no_flush_pipe_buffer_write(ctx, *cbuf, |
| 0, param_bytes, ones); |
| } |
| |
| ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); |
| switch (operation) { |
| case VG_UNION_MASK: { |
| if (!ctx->mask.union_fs) { |
| ctx->mask.union_fs = shader_create_from_text(ctx->pipe, |
| union_mask_asm, |
| 200, |
| PIPE_SHADER_FRAGMENT); |
| } |
| shader = ctx->mask.union_fs->driver; |
| } |
| break; |
| case VG_INTERSECT_MASK: { |
| if (!ctx->mask.intersect_fs) { |
| ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe, |
| intersect_mask_asm, |
| 200, |
| PIPE_SHADER_FRAGMENT); |
| } |
| shader = ctx->mask.intersect_fs->driver; |
| } |
| break; |
| case VG_SUBTRACT_MASK: { |
| if (!ctx->mask.subtract_fs) { |
| ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe, |
| subtract_mask_asm, |
| 200, |
| PIPE_SHADER_FRAGMENT); |
| } |
| shader = ctx->mask.subtract_fs->driver; |
| } |
| break; |
| case VG_SET_MASK: { |
| if (!ctx->mask.set_fs) { |
| ctx->mask.set_fs = shader_create_from_text(ctx->pipe, |
| set_mask_asm, |
| 200, |
| PIPE_SHADER_FRAGMENT); |
| } |
| shader = ctx->mask.set_fs->driver; |
| } |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| cso_set_fragment_shader_handle(ctx->cso_context, shader); |
| } |
| |
| static void setup_mask_samplers(struct pipe_sampler_view *umask) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; |
| struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; |
| struct st_framebuffer *fb_buffers = ctx->draw_buffer; |
| struct pipe_sampler_view *uprev = NULL; |
| struct pipe_sampler_state sampler; |
| |
| uprev = fb_buffers->blend_texture_view; |
| sampler = ctx->mask.sampler; |
| sampler.normalized_coords = 1; |
| |
| samplers[0] = NULL; |
| samplers[1] = NULL; |
| sampler_views[0] = NULL; |
| sampler_views[1] = NULL; |
| |
| samplers[0] = &sampler; |
| samplers[1] = &ctx->mask.sampler; |
| |
| sampler_views[0] = umask; |
| sampler_views[1] = uprev; |
| |
| cso_set_samplers(ctx->cso_context, 2, |
| (const struct pipe_sampler_state **)samplers); |
| cso_set_fragment_sampler_views(ctx->cso_context, 2, sampler_views); |
| } |
| |
| |
| /* setup shader constants */ |
| static void setup_mask_fill(const VGfloat color[4]) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_resource **cbuf = &ctx->mask.cbuf; |
| const VGint param_bytes = 4 * sizeof(VGfloat); |
| |
| /* We always need to get a new buffer, to keep the drivers simple and |
| * avoid gratuitous rendering synchronization. |
| */ |
| pipe_resource_reference(cbuf, NULL); |
| |
| *cbuf = pipe_buffer_create(ctx->pipe->screen, |
| PIPE_BIND_CONSTANT_BUFFER, |
| param_bytes); |
| if (*cbuf) { |
| st_no_flush_pipe_buffer_write(ctx, *cbuf, 0, param_bytes, color); |
| } |
| |
| ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf); |
| cso_set_fragment_shader_handle(ctx->cso_context, |
| shaders_cache_fill(ctx->sc, |
| VEGA_SOLID_FILL_SHADER)); |
| } |
| |
| static void setup_mask_viewport() |
| { |
| struct vg_context *ctx = vg_current_context(); |
| vg_set_viewport(ctx, VEGA_Y0_TOP); |
| } |
| |
| static void setup_mask_blend() |
| { |
| struct vg_context *ctx = vg_current_context(); |
| |
| struct pipe_blend_state blend; |
| |
| memset(&blend, 0, sizeof(struct pipe_blend_state)); |
| blend.rt[0].blend_enable = 0; |
| blend.rt[0].colormask = PIPE_MASK_RGBA; |
| blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; |
| blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; |
| blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; |
| blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; |
| |
| cso_set_blend(ctx->cso_context, &blend); |
| } |
| |
| |
| static void surface_fill(struct pipe_surface *surf, |
| int surf_width, int surf_height, |
| int x, int y, int width, int height, |
| const VGfloat color[4]) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| |
| if (x < 0) { |
| width += x; |
| x = 0; |
| } |
| if (y < 0) { |
| height += y; |
| y = 0; |
| } |
| |
| cso_save_framebuffer(ctx->cso_context); |
| cso_save_blend(ctx->cso_context); |
| cso_save_fragment_shader(ctx->cso_context); |
| cso_save_viewport(ctx->cso_context); |
| |
| setup_mask_blend(); |
| setup_mask_fill(color); |
| setup_mask_framebuffer(surf, surf_width, surf_height); |
| setup_mask_viewport(); |
| |
| renderer_draw_quad(ctx->renderer, x, y, |
| x + width, y + height, 0.0f/*depth should be disabled*/); |
| |
| |
| /* make sure rendering has completed */ |
| ctx->pipe->flush(ctx->pipe, |
| PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, |
| NULL); |
| |
| #if DEBUG_MASKS |
| save_alpha_to_file(0); |
| #endif |
| |
| cso_restore_blend(ctx->cso_context); |
| cso_restore_framebuffer(ctx->cso_context); |
| cso_restore_fragment_shader(ctx->cso_context); |
| cso_restore_viewport(ctx->cso_context); |
| } |
| |
| |
| static void mask_using_texture(struct pipe_sampler_view *sampler_view, |
| VGMaskOperation operation, |
| VGint x, VGint y, |
| VGint width, VGint height) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct pipe_resource *texture = sampler_view->texture; |
| struct pipe_surface *surface = |
| alpha_mask_surface(ctx, PIPE_BIND_RENDER_TARGET); |
| VGint offsets[4], loc[4]; |
| |
| if (!surface) |
| return; |
| if (!intersect_rectangles(surface->width, surface->height, |
| texture->width0, texture->height0, |
| x, y, width, height, |
| offsets, loc)) |
| return; |
| #if 0 |
| debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0], |
| offsets[1], offsets[2], offsets[3]); |
| debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0], |
| loc[1], loc[2], loc[3]); |
| #endif |
| |
| /* prepare our blend surface */ |
| vg_prepare_blend_surface_from_mask(ctx); |
| |
| cso_save_samplers(ctx->cso_context); |
| cso_save_fragment_sampler_views(ctx->cso_context); |
| cso_save_framebuffer(ctx->cso_context); |
| cso_save_blend(ctx->cso_context); |
| cso_save_fragment_shader(ctx->cso_context); |
| cso_save_viewport(ctx->cso_context); |
| |
| setup_mask_samplers(sampler_view); |
| setup_mask_blend(); |
| setup_mask_operation(operation); |
| setup_mask_framebuffer(surface, surface->width, surface->height); |
| setup_mask_viewport(); |
| |
| /* render the quad to propagate the rendering from stencil */ |
| renderer_draw_texture(ctx->renderer, texture, |
| offsets[0], offsets[1], |
| offsets[0] + offsets[2], offsets[1] + offsets[3], |
| loc[0], loc[1], loc[0] + loc[2], loc[1] + loc[3]); |
| |
| /* make sure rendering has completed */ |
| ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); |
| cso_restore_blend(ctx->cso_context); |
| cso_restore_framebuffer(ctx->cso_context); |
| cso_restore_fragment_shader(ctx->cso_context); |
| cso_restore_samplers(ctx->cso_context); |
| cso_restore_fragment_sampler_views(ctx->cso_context); |
| cso_restore_viewport(ctx->cso_context); |
| |
| pipe_surface_reference(&surface, NULL); |
| } |
| |
| |
| #ifdef OPENVG_VERSION_1_1 |
| |
| struct vg_mask_layer * mask_layer_create(VGint width, VGint height) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct vg_mask_layer *mask = 0; |
| |
| mask = CALLOC_STRUCT(vg_mask_layer); |
| vg_init_object(&mask->base, ctx, VG_OBJECT_MASK); |
| mask->width = width; |
| mask->height = height; |
| |
| { |
| struct pipe_resource pt; |
| struct pipe_context *pipe = ctx->pipe; |
| struct pipe_screen *screen = ctx->pipe->screen; |
| struct pipe_sampler_view view_templ; |
| struct pipe_sampler_view *view = NULL; |
| struct pipe_resource *texture; |
| |
| memset(&pt, 0, sizeof(pt)); |
| pt.target = PIPE_TEXTURE_2D; |
| pt.format = PIPE_FORMAT_B8G8R8A8_UNORM; |
| pt.last_level = 0; |
| pt.width0 = width; |
| pt.height0 = height; |
| pt.depth0 = 1; |
| pt.bind = PIPE_BIND_SAMPLER_VIEW; |
| pt.compressed = 0; |
| |
| texture = screen->resource_create(screen, &pt); |
| |
| if (texture) { |
| u_sampler_view_default_template(&view_templ, texture, texture->format); |
| view = pipe->create_sampler_view(pipe, texture, &view_templ); |
| } |
| pipe_resource_reference(&texture, NULL); |
| mask->sampler_view = view; |
| } |
| |
| vg_context_add_object(ctx, VG_OBJECT_MASK, mask); |
| |
| return mask; |
| } |
| |
| void mask_layer_destroy(struct vg_mask_layer *layer) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| |
| vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); |
| pipe_resource_release(&layer->texture); |
| FREE(layer); |
| } |
| |
| void mask_layer_fill(struct vg_mask_layer *layer, |
| VGint x, VGint y, |
| VGint width, VGint height, |
| VGfloat value) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| VGfloat alpha_color[4] = {0, 0, 0, 0}; |
| struct pipe_surface *surface; |
| |
| alpha_color[3] = value; |
| |
| surface = ctx->pipe->screen->get_tex_surface( |
| ctx->pipe->screen, layer->sampler_view->texture, |
| 0, 0, 0, |
| PIPE_BIND_RENDER_TARGET); |
| |
| surface_fill(surface, |
| layer->width, layer->height, |
| x, y, width, height, alpha_color); |
| |
| ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface); |
| } |
| |
| void mask_copy(struct vg_mask_layer *layer, |
| VGint sx, VGint sy, |
| VGint dx, VGint dy, |
| VGint width, VGint height) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct st_framebuffer *fb_buffers = ctx->draw_buffer; |
| |
| renderer_copy_texture(ctx->renderer, |
| layer->sampler_view, |
| sx, sy, |
| sx + width, sy + height, |
| fb_buffers->alpha_mask_view->texture, |
| dx, dy, |
| dx + width, dy + height); |
| } |
| |
| static void mask_layer_render_to(struct vg_mask_layer *layer, |
| struct path *path, |
| VGbitfield paint_modes) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f}; |
| struct pipe_screen *screen = ctx->pipe->screen; |
| struct pipe_surface *surface; |
| |
| surface = screen->get_tex_surface(screen, layer->sampler_view->texture, 0, 0, 0, |
| PIPE_BIND_RENDER_TARGET); |
| |
| cso_save_framebuffer(ctx->cso_context); |
| cso_save_fragment_shader(ctx->cso_context); |
| cso_save_viewport(ctx->cso_context); |
| |
| setup_mask_blend(); |
| setup_mask_fill(fill_color); |
| setup_mask_framebuffer(surface, layer->width, layer->height); |
| setup_mask_viewport(); |
| |
| if (paint_modes & VG_FILL_PATH) { |
| struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; |
| path_fill(path, mat); |
| } |
| |
| if (paint_modes & VG_STROKE_PATH){ |
| path_stroke(path); |
| } |
| |
| |
| /* make sure rendering has completed */ |
| ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); |
| |
| cso_restore_framebuffer(ctx->cso_context); |
| cso_restore_fragment_shader(ctx->cso_context); |
| cso_restore_viewport(ctx->cso_context); |
| ctx->state.dirty |= BLEND_DIRTY; |
| |
| screen->tex_surface_release(ctx->pipe->screen, &surface); |
| } |
| |
| void mask_render_to(struct path *path, |
| VGbitfield paint_modes, |
| VGMaskOperation operation) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| struct st_framebuffer *fb_buffers = ctx->draw_buffer; |
| struct vg_mask_layer *temp_layer; |
| VGint width, height; |
| |
| width = fb_buffers->alpha_mask_view->texture->width0; |
| height = fb_buffers->alpha_mask_view->texture->width0; |
| |
| temp_layer = mask_layer_create(width, height); |
| |
| mask_layer_render_to(temp_layer, path, paint_modes); |
| |
| mask_using_layer(temp_layer, 0, 0, width, height, |
| operation); |
| |
| mask_layer_destroy(temp_layer); |
| } |
| |
| void mask_using_layer(struct vg_mask_layer *layer, |
| VGMaskOperation operation, |
| VGint x, VGint y, |
| VGint width, VGint height) |
| { |
| mask_using_texture(layer->sampler_view, operation, |
| x, y, width, height); |
| } |
| |
| VGint mask_layer_width(struct vg_mask_layer *layer) |
| { |
| return layer->width; |
| } |
| |
| VGint mask_layer_height(struct vg_mask_layer *layer) |
| { |
| return layer->height; |
| } |
| |
| |
| #endif |
| |
| void mask_using_image(struct vg_image *image, |
| VGMaskOperation operation, |
| VGint x, VGint y, |
| VGint width, VGint height) |
| { |
| mask_using_texture(image->sampler_view, operation, |
| x, y, width, height); |
| } |
| |
| void mask_fill(VGint x, VGint y, VGint width, VGint height, |
| VGfloat value) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| VGfloat alpha_color[4] = {.0f, .0f, .0f, value}; |
| struct pipe_surface *surf = alpha_mask_surface( |
| ctx, PIPE_BIND_RENDER_TARGET); |
| |
| #if DEBUG_MASKS |
| debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n", |
| x, y, width, height, |
| alpha_color[0], alpha_color[1], |
| alpha_color[2], alpha_color[3]); |
| debug_printf("XXX %f === %f \n", |
| alpha_color[3], value); |
| #endif |
| |
| surface_fill(surf, surf->width, surf->height, |
| x, y, width, height, alpha_color); |
| |
| pipe_surface_reference(&surf, NULL); |
| } |
| |
| VGint mask_bind_samplers(struct pipe_sampler_state **samplers, |
| struct pipe_sampler_view **sampler_views) |
| { |
| struct vg_context *ctx = vg_current_context(); |
| |
| if (ctx->state.vg.masking) { |
| struct st_framebuffer *fb_buffers = ctx->draw_buffer; |
| |
| samplers[1] = &ctx->mask.sampler; |
| sampler_views[1] = fb_buffers->alpha_mask_view; |
| return 1; |
| } else |
| return 0; |
| } |