65adadd1fe917310ba143a28b24b893acbd8100b
[mesa.git] / src / gallium / state_trackers / vega / vg_context.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 "vg_context.h"
28
29 #include "paint.h"
30 #include "renderer.h"
31 #include "shaders_cache.h"
32 #include "shader.h"
33 #include "asm_util.h"
34 #include "st_inlines.h"
35 #include "vg_manager.h"
36 #include "api.h"
37 #include "mask.h"
38
39 #include "pipe/p_context.h"
40 #include "util/u_inlines.h"
41
42 #include "cso_cache/cso_context.h"
43
44 #include "util/u_simple_shaders.h"
45 #include "util/u_memory.h"
46 #include "util/u_blit.h"
47 #include "util/u_sampler.h"
48 #include "util/u_format.h"
49
50 struct vg_context *_vg_context = 0;
51
52 struct vg_context * vg_current_context(void)
53 {
54 return _vg_context;
55 }
56
57 /**
58 * A depth/stencil rb will be needed regardless of what the visual says.
59 */
60 static boolean
61 choose_depth_stencil_format(struct vg_context *ctx)
62 {
63 struct pipe_screen *screen = ctx->pipe->screen;
64 enum pipe_format formats[] = {
65 PIPE_FORMAT_Z24_UNORM_S8_USCALED,
66 PIPE_FORMAT_S8_USCALED_Z24_UNORM,
67 PIPE_FORMAT_NONE
68 };
69 enum pipe_format *fmt;
70
71 for (fmt = formats; *fmt != PIPE_FORMAT_NONE; fmt++) {
72 if (screen->is_format_supported(screen, *fmt,
73 PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0))
74 break;
75 }
76
77 ctx->ds_format = *fmt;
78
79 return (ctx->ds_format != PIPE_FORMAT_NONE);
80 }
81
82 void vg_set_current_context(struct vg_context *ctx)
83 {
84 _vg_context = ctx;
85 api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
86 }
87
88 struct vg_context * vg_create_context(struct pipe_context *pipe,
89 const void *visual,
90 struct vg_context *share)
91 {
92 struct vg_context *ctx;
93
94 ctx = CALLOC_STRUCT(vg_context);
95
96 ctx->pipe = pipe;
97 if (!choose_depth_stencil_format(ctx)) {
98 FREE(ctx);
99 return NULL;
100 }
101
102 ctx->dispatch = api_create_dispatch();
103
104 vg_init_state(&ctx->state.vg);
105 ctx->state.dirty = ALL_DIRTY;
106
107 ctx->cso_context = cso_create_context(pipe);
108
109 ctx->default_paint = paint_create(ctx);
110 ctx->state.vg.stroke_paint = ctx->default_paint;
111 ctx->state.vg.fill_paint = ctx->default_paint;
112
113
114 ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
115 ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
116 ctx->mask.sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
117 ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
118 ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
119 ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
120 ctx->mask.sampler.normalized_coords = 0;
121
122 ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
123 ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
124 ctx->blend_sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
125 ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
126 ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
127 ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
128 ctx->blend_sampler.normalized_coords = 0;
129
130 vg_set_error(ctx, VG_NO_ERROR);
131
132 ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
133 ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
134 ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
135 ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
136 ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
137
138 ctx->renderer = renderer_create(ctx);
139 ctx->sc = shaders_cache_create(ctx);
140 ctx->shader = shader_create(ctx);
141
142 ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
143
144 return ctx;
145 }
146
147 void vg_destroy_context(struct vg_context *ctx)
148 {
149 struct pipe_resource **cbuf = &ctx->mask.cbuf;
150
151 util_destroy_blit(ctx->blit);
152 renderer_destroy(ctx->renderer);
153 shaders_cache_destroy(ctx->sc);
154 shader_destroy(ctx->shader);
155 paint_destroy(ctx->default_paint);
156
157 if (*cbuf)
158 pipe_resource_reference(cbuf, NULL);
159
160 if (ctx->mask.union_fs)
161 vg_shader_destroy(ctx, ctx->mask.union_fs);
162 if (ctx->mask.intersect_fs)
163 vg_shader_destroy(ctx, ctx->mask.intersect_fs);
164 if (ctx->mask.subtract_fs)
165 vg_shader_destroy(ctx, ctx->mask.subtract_fs);
166 if (ctx->mask.set_fs)
167 vg_shader_destroy(ctx, ctx->mask.set_fs);
168
169 cso_release_all(ctx->cso_context);
170 cso_destroy_context(ctx->cso_context);
171
172 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
173 cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
174 cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
175 cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
176 cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
177
178 api_destroy_dispatch(ctx->dispatch);
179
180 FREE(ctx);
181 }
182
183 void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
184 {
185 obj->type = type;
186 obj->ctx = ctx;
187 }
188
189 VGboolean vg_context_is_object_valid(struct vg_context *ctx,
190 enum vg_object_type type,
191 void *ptr)
192 {
193 if (ctx) {
194 struct cso_hash *hash = ctx->owned_objects[type];
195 if (!hash)
196 return VG_FALSE;
197 return cso_hash_contains(hash, (unsigned)(long)ptr);
198 }
199 return VG_FALSE;
200 }
201
202 void vg_context_add_object(struct vg_context *ctx,
203 enum vg_object_type type,
204 void *ptr)
205 {
206 if (ctx) {
207 struct cso_hash *hash = ctx->owned_objects[type];
208 if (!hash)
209 return;
210 cso_hash_insert(hash, (unsigned)(long)ptr, ptr);
211 }
212 }
213
214 void vg_context_remove_object(struct vg_context *ctx,
215 enum vg_object_type type,
216 void *ptr)
217 {
218 if (ctx) {
219 struct cso_hash *hash = ctx->owned_objects[type];
220 if (!hash)
221 return;
222 cso_hash_take(hash, (unsigned)(long)ptr);
223 }
224 }
225
226 static struct pipe_resource *
227 create_texture(struct pipe_context *pipe, enum pipe_format format,
228 VGint width, VGint height)
229 {
230 struct pipe_resource templ;
231
232 memset(&templ, 0, sizeof(templ));
233
234 if (format != PIPE_FORMAT_NONE) {
235 templ.format = format;
236 }
237 else {
238 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
239 }
240
241 templ.target = PIPE_TEXTURE_2D;
242 templ.width0 = width;
243 templ.height0 = height;
244 templ.depth0 = 1;
245 templ.last_level = 0;
246
247 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
248 templ.bind = PIPE_BIND_DEPTH_STENCIL;
249 } else {
250 templ.bind = (PIPE_BIND_DISPLAY_TARGET |
251 PIPE_BIND_RENDER_TARGET |
252 PIPE_BIND_SAMPLER_VIEW);
253 }
254
255 return pipe->screen->resource_create(pipe->screen, &templ);
256 }
257
258 static struct pipe_sampler_view *
259 create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
260 VGint width, VGint height)
261 {
262 struct pipe_resource *texture;
263 struct pipe_sampler_view view_templ;
264 struct pipe_sampler_view *view;
265
266 texture = create_texture(pipe, format, width, height);
267
268 if (!texture)
269 return NULL;
270
271 u_sampler_view_default_template(&view_templ, texture, texture->format);
272 view = pipe->create_sampler_view(pipe, texture, &view_templ);
273 /* want the texture to go away if the view is freed */
274 pipe_resource_reference(&texture, NULL);
275
276 return view;
277 }
278
279 static void
280 vg_context_update_alpha_mask_view(struct vg_context *ctx,
281 uint width, uint height)
282 {
283 struct st_framebuffer *stfb = ctx->draw_buffer;
284 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view;
285 struct pipe_context *pipe = ctx->pipe;
286
287 if (old_sampler_view &&
288 old_sampler_view->texture->width0 == width &&
289 old_sampler_view->texture->height0 == height)
290 return;
291
292 /*
293 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
294 this texture and use it as a sampler, so while this wastes some
295 space it makes both of those a lot simpler
296 */
297 stfb->alpha_mask_view = create_tex_and_view(pipe,
298 PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
299
300 if (!stfb->alpha_mask_view) {
301 if (old_sampler_view)
302 pipe_sampler_view_reference(&old_sampler_view, NULL);
303 return;
304 }
305
306 /* XXX could this call be avoided? */
307 vg_validate_state(ctx);
308
309 /* alpha mask starts with 1.f alpha */
310 mask_fill(0, 0, width, height, 1.f);
311
312 /* if we had an old surface copy it over */
313 if (old_sampler_view) {
314 struct pipe_subresource subsurf, subold_surf;
315 subsurf.face = 0;
316 subsurf.level = 0;
317 subold_surf.face = 0;
318 subold_surf.level = 0;
319 pipe->resource_copy_region(pipe,
320 stfb->alpha_mask_view->texture,
321 subsurf,
322 0, 0, 0,
323 old_sampler_view->texture,
324 subold_surf,
325 0, 0, 0,
326 MIN2(old_sampler_view->texture->width0,
327 stfb->alpha_mask_view->texture->width0),
328 MIN2(old_sampler_view->texture->height0,
329 stfb->alpha_mask_view->texture->height0));
330 }
331
332 /* Free the old texture
333 */
334 if (old_sampler_view)
335 pipe_sampler_view_reference(&old_sampler_view, NULL);
336 }
337
338 static void
339 vg_context_update_blend_texture_view(struct vg_context *ctx,
340 uint width, uint height)
341 {
342 struct pipe_context *pipe = ctx->pipe;
343 struct st_framebuffer *stfb = ctx->draw_buffer;
344 struct pipe_sampler_view *old = stfb->blend_texture_view;
345
346 if (old &&
347 old->texture->width0 == width &&
348 old->texture->height0 == height)
349 return;
350
351 stfb->blend_texture_view = create_tex_and_view(pipe,
352 PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
353
354 pipe_sampler_view_reference(&old, NULL);
355 }
356
357 static boolean
358 vg_context_update_depth_stencil_rb(struct vg_context * ctx,
359 uint width, uint height)
360 {
361 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
362 struct pipe_context *pipe = ctx->pipe;
363 unsigned surface_usage;
364
365 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
366 return FALSE;
367
368 /* unreference existing ones */
369 pipe_surface_reference(&dsrb->surface, NULL);
370 pipe_resource_reference(&dsrb->texture, NULL);
371 dsrb->width = dsrb->height = 0;
372
373 /* Probably need dedicated flags for surface usage too:
374 */
375 surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */
376
377 dsrb->texture = create_texture(pipe, dsrb->format, width, height);
378 if (!dsrb->texture)
379 return TRUE;
380
381 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen,
382 dsrb->texture,
383 0, 0, 0,
384 surface_usage);
385 if (!dsrb->surface) {
386 pipe_resource_reference(&dsrb->texture, NULL);
387 return TRUE;
388 }
389
390 dsrb->width = width;
391 dsrb->height = height;
392
393 assert(dsrb->surface->width == width);
394 assert(dsrb->surface->height == height);
395
396 return TRUE;
397 }
398
399 void vg_validate_state(struct vg_context *ctx)
400 {
401 struct st_framebuffer *stfb = ctx->draw_buffer;
402
403 vg_manager_validate_framebuffer(ctx);
404
405 if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height))
406 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
407
408 /* TODO create as needed */
409 vg_context_update_alpha_mask_view(ctx, stfb->width, stfb->height);
410 vg_context_update_blend_texture_view(ctx, stfb->width, stfb->height);
411
412 renderer_validate(ctx->renderer, ctx->state.dirty,
413 ctx->draw_buffer, &ctx->state.vg);
414
415 ctx->state.dirty = NONE_DIRTY;
416
417 shader_set_masking(ctx->shader, ctx->state.vg.masking);
418 shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
419 shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform);
420 }
421
422 VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type)
423 {
424 struct vg_object *obj = ptr;
425 if (ptr && is_aligned(obj) && obj->type == type)
426 return VG_TRUE;
427 else
428 return VG_FALSE;
429 }
430
431 void vg_set_error(struct vg_context *ctx,
432 VGErrorCode code)
433 {
434 /*vgGetError returns the oldest error code provided by
435 * an API call on the current context since the previous
436 * call to vgGetError on that context (or since the creation
437 of the context).*/
438 if (ctx->_error == VG_NO_ERROR)
439 ctx->_error = code;
440 }
441
442 void vg_prepare_blend_surface(struct vg_context *ctx)
443 {
444 struct pipe_surface *dest_surface = NULL;
445 struct pipe_context *pipe = ctx->pipe;
446 struct pipe_sampler_view *view;
447 struct pipe_sampler_view view_templ;
448 struct st_framebuffer *stfb = ctx->draw_buffer;
449 struct st_renderbuffer *strb = stfb->strb;
450
451 /* first finish all pending rendering */
452 vgFinish();
453
454 u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format);
455 view = pipe->create_sampler_view(pipe, strb->texture, &view_templ);
456
457 dest_surface = pipe->screen->get_tex_surface(pipe->screen,
458 stfb->blend_texture_view->texture,
459 0, 0, 0,
460 PIPE_BIND_RENDER_TARGET);
461 util_blit_pixels_tex(ctx->blit,
462 view,
463 0, 0,
464 strb->width, strb->height,
465 dest_surface,
466 0, 0,
467 strb->width, strb->height,
468 0.0, PIPE_TEX_MIPFILTER_NEAREST);
469
470 if (dest_surface)
471 pipe_surface_reference(&dest_surface, NULL);
472
473 /* make sure it's complete */
474 vgFinish();
475
476 pipe_sampler_view_reference(&view, NULL);
477 }
478
479
480 void vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
481 {
482 struct pipe_surface *dest_surface = NULL;
483 struct pipe_context *pipe = ctx->pipe;
484 struct st_framebuffer *stfb = ctx->draw_buffer;
485 struct st_renderbuffer *strb = stfb->strb;
486
487 vg_validate_state(ctx);
488
489 /* first finish all pending rendering */
490 vgFinish();
491
492 dest_surface = pipe->screen->get_tex_surface(pipe->screen,
493 stfb->blend_texture_view->texture,
494 0, 0, 0,
495 PIPE_BIND_RENDER_TARGET);
496
497 util_blit_pixels_tex(ctx->blit,
498 stfb->alpha_mask_view,
499 0, 0,
500 strb->width, strb->height,
501 dest_surface,
502 0, 0,
503 strb->width, strb->height,
504 0.0, PIPE_TEX_MIPFILTER_NEAREST);
505
506 /* make sure it's complete */
507 vgFinish();
508
509 if (dest_surface)
510 pipe_surface_reference(&dest_surface, NULL);
511 }
512
513 /**
514 * A transformation from window coordinates to paint coordinates.
515 */
516 VGboolean vg_get_paint_matrix(struct vg_context *ctx,
517 const struct matrix *paint_to_user,
518 const struct matrix *user_to_surface,
519 struct matrix *mat)
520 {
521 struct matrix tmp;
522
523 /* get user-to-paint matrix */
524 memcpy(mat, paint_to_user, sizeof(*paint_to_user));
525 if (!matrix_invert(mat))
526 return VG_FALSE;
527
528 /* get surface-to-user matrix */
529 memcpy(&tmp, user_to_surface, sizeof(*user_to_surface));
530 if (!matrix_invert(&tmp))
531 return VG_FALSE;
532
533 matrix_mult(mat, &tmp);
534
535 return VG_TRUE;
536 }