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