ilo: replace a boolean by bool
[mesa.git] / src / gallium / state_trackers / vega / mask.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 "mask.h"
28
29 #include "path.h"
30 #include "image.h"
31 #include "shaders_cache.h"
32 #include "renderer.h"
33 #include "asm_util.h"
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_screen.h"
37 #include "util/u_inlines.h"
38 #include "util/u_format.h"
39 #include "util/u_memory.h"
40 #include "util/u_surface.h"
41 #include "util/u_sampler.h"
42
43 struct vg_mask_layer {
44 struct vg_object base;
45
46 VGint width;
47 VGint height;
48
49 struct pipe_sampler_view *sampler_view;
50 };
51
52 static INLINE VGboolean
53 intersect_rectangles(VGint dwidth, VGint dheight,
54 VGint swidth, VGint sheight,
55 VGint tx, VGint ty,
56 VGint twidth, VGint theight,
57 VGint *offsets,
58 VGint *location)
59 {
60 if (tx + twidth <= 0 || tx >= dwidth)
61 return VG_FALSE;
62 if (ty + theight <= 0 || ty >= dheight)
63 return VG_FALSE;
64
65 offsets[0] = 0;
66 offsets[1] = 0;
67 location[0] = tx;
68 location[1] = ty;
69
70 if (tx < 0) {
71 offsets[0] -= tx;
72 location[0] = 0;
73
74 location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth));
75 offsets[2] = location[2];
76 } else {
77 offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth ));
78 location[2] = offsets[2];
79 }
80
81 if (ty < 0) {
82 offsets[1] -= ty;
83 location[1] = 0;
84
85 location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight));
86 offsets[3] = location[3];
87 } else {
88 offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight));
89 location[3] = offsets[3];
90 }
91
92 return VG_TRUE;
93 }
94
95 #if DEBUG_MASKS
96 static void read_alpha_mask(void * data, VGint dataStride,
97 VGImageFormat dataFormat,
98 VGint sx, VGint sy,
99 VGint width, VGint height)
100 {
101 struct vg_context *ctx = vg_current_context();
102 struct pipe_context *pipe = ctx->pipe;
103
104 struct st_framebuffer *stfb = ctx->draw_buffer;
105 struct st_renderbuffer *strb = stfb->alpha_mask;
106
107 VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
108 VGfloat *df = (VGfloat*)temp;
109 VGint y = (stfb->height - sy) - 1, yStep = -1;
110 VGint i;
111 VGubyte *dst = (VGubyte *)data;
112 VGint xoffset = 0, yoffset = 0;
113
114 if (sx < 0) {
115 xoffset = -sx;
116 xoffset *= _vega_size_for_format(dataFormat);
117 width += sx;
118 sx = 0;
119 }
120 if (sy < 0) {
121 yoffset = -sy;
122 height += sy;
123 sy = 0;
124 y = (stfb->height - sy) - 1;
125 yoffset *= dataStride;
126 }
127
128 {
129 struct pipe_surface *surf;
130
131 surf = pipe->create_surface(pipe, strb->texture, 0, 0, 0,
132 PIPE_BIND_TRANSFER_READ);
133
134 /* Do a row at a time to flip image data vertically */
135 for (i = 0; i < height; i++) {
136 #if 0
137 debug_printf("%d-%d == %d\n", sy, height, y);
138 #endif
139 pipe_get_tile_rgba(surf, sx, y, width, 1, df);
140 y += yStep;
141 _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
142 dst + yoffset + xoffset);
143 dst += dataStride;
144 }
145
146 pipe_surface_reference(&surf, NULL);
147 }
148 }
149
150 void save_alpha_to_file(const char *filename)
151 {
152 struct vg_context *ctx = vg_current_context();
153 struct st_framebuffer *stfb = ctx->draw_buffer;
154 VGint *data;
155 int i, j;
156
157 data = malloc(sizeof(int) * stfb->width * stfb->height);
158 read_alpha_mask(data, stfb->width * sizeof(int),
159 VG_sRGBA_8888,
160 0, 0, stfb->width, stfb->height);
161 fprintf(stderr, "/*---------- start */\n");
162 fprintf(stderr, "const int image_width = %d;\n",
163 stfb->width);
164 fprintf(stderr, "const int image_height = %d;\n",
165 stfb->height);
166 fprintf(stderr, "const int image_data = {\n");
167 for (i = 0; i < stfb->height; ++i) {
168 for (j = 0; j < stfb->width; ++j) {
169 int rgba = data[i * stfb->height + j];
170 int argb = 0;
171 argb = (rgba >> 8);
172 argb |= ((rgba & 0xff) << 24);
173 fprintf(stderr, "0x%x, ", argb);
174 }
175 fprintf(stderr, "\n");
176 }
177 fprintf(stderr, "};\n");
178 fprintf(stderr, "/*---------- end */\n");
179 }
180 #endif
181
182 /* setup mask shader */
183 static void *setup_mask_operation(VGMaskOperation operation)
184 {
185 struct vg_context *ctx = vg_current_context();
186 void *shader = 0;
187
188 switch (operation) {
189 case VG_UNION_MASK: {
190 if (!ctx->mask.union_fs) {
191 ctx->mask.union_fs = shader_create_from_text(ctx->pipe,
192 union_mask_asm,
193 200,
194 PIPE_SHADER_FRAGMENT);
195 }
196 shader = ctx->mask.union_fs->driver;
197 }
198 break;
199 case VG_INTERSECT_MASK: {
200 if (!ctx->mask.intersect_fs) {
201 ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe,
202 intersect_mask_asm,
203 200,
204 PIPE_SHADER_FRAGMENT);
205 }
206 shader = ctx->mask.intersect_fs->driver;
207 }
208 break;
209 case VG_SUBTRACT_MASK: {
210 if (!ctx->mask.subtract_fs) {
211 ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe,
212 subtract_mask_asm,
213 200,
214 PIPE_SHADER_FRAGMENT);
215 }
216 shader = ctx->mask.subtract_fs->driver;
217 }
218 break;
219 case VG_SET_MASK: {
220 if (!ctx->mask.set_fs) {
221 ctx->mask.set_fs = shader_create_from_text(ctx->pipe,
222 set_mask_asm,
223 200,
224 PIPE_SHADER_FRAGMENT);
225 }
226 shader = ctx->mask.set_fs->driver;
227 }
228 break;
229 default:
230 assert(0);
231 break;
232 }
233
234 return shader;
235 }
236
237 static void mask_resource_fill(struct pipe_resource *dst,
238 int x, int y, int width, int height,
239 VGfloat coverage)
240 {
241 struct vg_context *ctx = vg_current_context();
242 VGfloat fs_consts[12] = {
243 0.0f, 0.0f, 0.0f, 0.0f, /* not used */
244 0.0f, 0.0f, 0.0f, 0.0f, /* not used */
245 0.0f, 0.0f, 0.0f, coverage /* color */
246 };
247 void *fs;
248
249 if (x < 0) {
250 width += x;
251 x = 0;
252 }
253 if (y < 0) {
254 height += y;
255 y = 0;
256 }
257
258 fs = shaders_cache_fill(ctx->sc, VEGA_SOLID_FILL_SHADER);
259
260 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE, ~0,
261 NULL, NULL, 0, fs, (const void *) fs_consts, sizeof(fs_consts))) {
262 renderer_filter(ctx->renderer, x, y, width, height, 0, 0, 0, 0);
263 renderer_filter_end(ctx->renderer);
264 }
265
266 #if DEBUG_MASKS
267 save_alpha_to_file(0);
268 #endif
269 }
270
271
272 static void mask_using_texture(struct pipe_sampler_view *sampler_view,
273 VGboolean is_layer,
274 VGMaskOperation operation,
275 VGint x, VGint y,
276 VGint width, VGint height)
277 {
278 struct vg_context *ctx = vg_current_context();
279 struct pipe_sampler_view *dst_view = vg_get_surface_mask(ctx);
280 struct pipe_resource *dst = dst_view->texture;
281 struct pipe_resource *texture = sampler_view->texture;
282 const struct pipe_sampler_state *samplers[2];
283 struct pipe_sampler_view *views[2];
284 struct pipe_sampler_state sampler;
285 VGint offsets[4], loc[4];
286 const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f};
287 void *fs;
288
289 if (!intersect_rectangles(dst->width0, dst->height0,
290 texture->width0, texture->height0,
291 x, y, width, height,
292 offsets, loc))
293 return;
294 #if 0
295 debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0],
296 offsets[1], offsets[2], offsets[3]);
297 debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0],
298 loc[1], loc[2], loc[3]);
299 #endif
300
301
302 sampler = ctx->mask.sampler;
303 sampler.normalized_coords = 1;
304 samplers[0] = &sampler;
305 views[0] = sampler_view;
306
307 /* prepare our blend surface */
308 samplers[1] = &ctx->mask.sampler;
309 views[1] = vg_prepare_blend_surface_from_mask(ctx);
310
311 fs = setup_mask_operation(operation);
312
313 if (renderer_filter_begin(ctx->renderer, dst, VG_FALSE,
314 ~0, samplers, views, 2, fs, (const void *) ones, sizeof(ones))) {
315 /* layer should be flipped when used as a texture */
316 if (is_layer) {
317 offsets[1] += offsets[3];
318 offsets[3] = -offsets[3];
319 }
320 renderer_filter(ctx->renderer,
321 loc[0], loc[1], loc[2], loc[3],
322 offsets[0], offsets[1], offsets[2], offsets[3]);
323 renderer_filter_end(ctx->renderer);
324 }
325 }
326
327
328 #ifdef OPENVG_VERSION_1_1
329
330 struct vg_mask_layer * mask_layer_create(VGint width, VGint height)
331 {
332 struct vg_context *ctx = vg_current_context();
333 struct vg_mask_layer *mask = 0;
334
335 mask = CALLOC_STRUCT(vg_mask_layer);
336 vg_init_object(&mask->base, ctx, VG_OBJECT_MASK);
337 mask->width = width;
338 mask->height = height;
339
340 {
341 struct pipe_resource pt;
342 struct pipe_context *pipe = ctx->pipe;
343 struct pipe_screen *screen = ctx->pipe->screen;
344 struct pipe_sampler_view view_templ;
345 struct pipe_sampler_view *view = NULL;
346 struct pipe_resource *texture;
347
348 memset(&pt, 0, sizeof(pt));
349 pt.target = PIPE_TEXTURE_2D;
350 pt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
351 pt.last_level = 0;
352 pt.width0 = width;
353 pt.height0 = height;
354 pt.depth0 = 1;
355 pt.array_size = 1;
356 pt.bind = PIPE_BIND_SAMPLER_VIEW;
357
358 texture = screen->resource_create(screen, &pt);
359
360 if (texture) {
361 u_sampler_view_default_template(&view_templ, texture, texture->format);
362 view = pipe->create_sampler_view(pipe, texture, &view_templ);
363 }
364 pipe_resource_reference(&texture, NULL);
365 mask->sampler_view = view;
366 }
367
368 vg_context_add_object(ctx, &mask->base);
369
370 return mask;
371 }
372
373 void mask_layer_destroy(struct vg_mask_layer *layer)
374 {
375 struct vg_context *ctx = vg_current_context();
376
377 vg_context_remove_object(ctx, &layer->base);
378 pipe_sampler_view_reference(&layer->sampler_view, NULL);
379 vg_free_object(&layer->base);
380 FREE(layer);
381 }
382
383 void mask_layer_fill(struct vg_mask_layer *layer,
384 VGint x, VGint y,
385 VGint width, VGint height,
386 VGfloat value)
387 {
388 mask_resource_fill(layer->sampler_view->texture,
389 x, y, width, height, value);
390 }
391
392 void mask_copy(struct vg_mask_layer *layer,
393 VGint sx, VGint sy,
394 VGint dx, VGint dy,
395 VGint width, VGint height)
396 {
397 struct vg_context *ctx = vg_current_context();
398 struct pipe_sampler_view *src = vg_get_surface_mask(ctx);
399 struct pipe_surface *surf, surf_tmpl;
400
401 /* get the destination surface */
402 u_surface_default_template(&surf_tmpl, layer->sampler_view->texture);
403 surf = ctx->pipe->create_surface(ctx->pipe, layer->sampler_view->texture,
404 &surf_tmpl);
405 if (surf && renderer_copy_begin(ctx->renderer, surf, VG_FALSE, src)) {
406 /* layer should be flipped when used as a texture */
407 sy += height;
408 height = -height;
409
410 renderer_copy(ctx->renderer,
411 dx, dy, width, height,
412 sx, sy, width, height);
413 renderer_copy_end(ctx->renderer);
414 }
415
416 pipe_surface_reference(&surf, NULL);
417 }
418
419 static void mask_layer_render_to(struct vg_mask_layer *layer,
420 struct path *path,
421 VGbitfield paint_modes)
422 {
423 struct vg_context *ctx = vg_current_context();
424 struct pipe_context *pipe = ctx->pipe;
425 struct pipe_sampler_view *view = vg_get_surface_mask(ctx);
426 struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
427 struct pipe_surface *surf, surf_tmpl;
428 u_surface_default_template(&surf_tmpl, view->texture);
429 surf = pipe->create_surface(pipe, view->texture, &surf_tmpl);
430
431 renderer_validate_for_mask_rendering(ctx->renderer, surf, mat);
432
433 if (paint_modes & VG_FILL_PATH) {
434 path_fill(path);
435 }
436
437 if (paint_modes & VG_STROKE_PATH){
438 path_stroke(path);
439 }
440
441 pipe_surface_reference(&surf, NULL);
442 }
443
444 void mask_render_to(struct path *path,
445 VGbitfield paint_modes,
446 VGMaskOperation operation)
447 {
448 struct vg_context *ctx = vg_current_context();
449 struct st_framebuffer *stfb = ctx->draw_buffer;
450 struct vg_mask_layer *temp_layer;
451 VGint width, height;
452
453 width = stfb->width;
454 height = stfb->height;
455
456 temp_layer = mask_layer_create(width, height);
457 mask_layer_fill(temp_layer, 0, 0, width, height, 0.0f);
458
459 mask_layer_render_to(temp_layer, path, paint_modes);
460
461 mask_using_layer(temp_layer, operation, 0, 0, width, height);
462
463 mask_layer_destroy(temp_layer);
464 }
465
466 void mask_using_layer(struct vg_mask_layer *layer,
467 VGMaskOperation operation,
468 VGint x, VGint y,
469 VGint width, VGint height)
470 {
471 mask_using_texture(layer->sampler_view, VG_TRUE, operation,
472 x, y, width, height);
473 }
474
475 VGint mask_layer_width(struct vg_mask_layer *layer)
476 {
477 return layer->width;
478 }
479
480 VGint mask_layer_height(struct vg_mask_layer *layer)
481 {
482 return layer->height;
483 }
484
485
486 #endif
487
488 void mask_using_image(struct vg_image *image,
489 VGMaskOperation operation,
490 VGint x, VGint y,
491 VGint width, VGint height)
492 {
493 mask_using_texture(image->sampler_view, VG_FALSE, operation,
494 x, y, width, height);
495 }
496
497 void mask_fill(VGint x, VGint y, VGint width, VGint height,
498 VGfloat value)
499 {
500 struct vg_context *ctx = vg_current_context();
501 struct pipe_sampler_view *view = vg_get_surface_mask(ctx);
502
503 #if DEBUG_MASKS
504 debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n",
505 x, y, width, height,
506 0.0f, 0.0f, 0.0f, value);
507 #endif
508
509 mask_resource_fill(view->texture, x, y, width, height, value);
510 }
511
512 VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
513 struct pipe_sampler_view **sampler_views)
514 {
515 struct vg_context *ctx = vg_current_context();
516
517 if (ctx->state.vg.masking) {
518 samplers[1] = &ctx->mask.sampler;
519 sampler_views[1] = vg_get_surface_mask(ctx);
520 return 1;
521 } else
522 return 0;
523 }