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