st/vega: Use vgapi.
[mesa.git] / src / gallium / state_trackers / vega / vg_manager.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright 2009 VMware, Inc. All Rights Reserved.
6 * Copyright (C) 2010 LunarG Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Chia-I Wu <olv@lunarg.com>
28 */
29
30 #include "state_tracker/st_api.h"
31
32 #include "pipe/p_context.h"
33 #include "pipe/p_screen.h"
34 #include "util/u_memory.h"
35 #include "util/u_inlines.h"
36 #include "util/u_format.h"
37 #include "util/u_sampler.h"
38
39 #include "vg_manager.h"
40 #include "vg_context.h"
41 #include "image.h"
42 #include "mask.h"
43 #include "api.h"
44
45 static struct pipe_resource *
46 create_texture(struct pipe_context *pipe, enum pipe_format format,
47 VGint width, VGint height)
48 {
49 struct pipe_resource templ;
50
51 memset(&templ, 0, sizeof(templ));
52
53 if (format != PIPE_FORMAT_NONE) {
54 templ.format = format;
55 }
56 else {
57 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
58 }
59
60 templ.target = PIPE_TEXTURE_2D;
61 templ.width0 = width;
62 templ.height0 = height;
63 templ.depth0 = 1;
64 templ.last_level = 0;
65
66 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
67 templ.bind = PIPE_BIND_DEPTH_STENCIL;
68 } else {
69 templ.bind = (PIPE_BIND_DISPLAY_TARGET |
70 PIPE_BIND_RENDER_TARGET |
71 PIPE_BIND_SAMPLER_VIEW);
72 }
73
74 return pipe->screen->resource_create(pipe->screen, &templ);
75 }
76
77 static struct pipe_sampler_view *
78 create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
79 VGint width, VGint height)
80 {
81 struct pipe_resource *texture;
82 struct pipe_sampler_view view_templ;
83 struct pipe_sampler_view *view;
84
85 texture = create_texture(pipe, format, width, height);
86
87 if (!texture)
88 return NULL;
89
90 u_sampler_view_default_template(&view_templ, texture, texture->format);
91 view = pipe->create_sampler_view(pipe, texture, &view_templ);
92 /* want the texture to go away if the view is freed */
93 pipe_resource_reference(&texture, NULL);
94
95 return view;
96 }
97
98 static void
99 setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb)
100 {
101 struct pipe_context *pipe = ctx->pipe;
102 struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view;
103
104 /*
105 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
106 this texture and use it as a sampler, so while this wastes some
107 space it makes both of those a lot simpler
108 */
109 stfb->alpha_mask_view = create_tex_and_view(pipe,
110 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
111
112 if (!stfb->alpha_mask_view) {
113 if (old_sampler_view)
114 pipe_sampler_view_reference(&old_sampler_view, NULL);
115 return;
116 }
117
118 /* XXX could this call be avoided? */
119 vg_validate_state(ctx);
120
121 /* alpha mask starts with 1.f alpha */
122 mask_fill(0, 0, stfb->width, stfb->height, 1.f);
123
124 /* if we had an old surface copy it over */
125 if (old_sampler_view) {
126 struct pipe_surface *surface = pipe->screen->get_tex_surface(
127 pipe->screen,
128 stfb->alpha_mask_view->texture,
129 0, 0, 0,
130 PIPE_BIND_RENDER_TARGET |
131 PIPE_BIND_BLIT_DESTINATION);
132 struct pipe_surface *old_surface = pipe->screen->get_tex_surface(
133 pipe->screen,
134 old_sampler_view->texture,
135 0, 0, 0,
136 PIPE_BIND_BLIT_SOURCE);
137 pipe->surface_copy(pipe,
138 surface,
139 0, 0,
140 old_surface,
141 0, 0,
142 MIN2(old_surface->width, surface->width),
143 MIN2(old_surface->height, surface->height));
144 if (surface)
145 pipe_surface_reference(&surface, NULL);
146 if (old_surface)
147 pipe_surface_reference(&old_surface, NULL);
148 }
149
150 /* Free the old texture
151 */
152 if (old_sampler_view)
153 pipe_sampler_view_reference(&old_sampler_view, NULL);
154 }
155
156 static boolean
157 vg_context_update_depth_stencil_rb(struct vg_context * ctx,
158 uint width, uint height)
159 {
160 struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
161 struct pipe_context *pipe = ctx->pipe;
162 unsigned surface_usage;
163
164 if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
165 return FALSE;
166
167 /* unreference existing ones */
168 pipe_surface_reference(&dsrb->surface, NULL);
169 pipe_resource_reference(&dsrb->texture, NULL);
170 dsrb->width = dsrb->height = 0;
171
172 /* Probably need dedicated flags for surface usage too:
173 */
174 surface_usage = (PIPE_BIND_RENDER_TARGET |
175 PIPE_BIND_BLIT_SOURCE |
176 PIPE_BIND_BLIT_DESTINATION);
177
178 dsrb->texture = create_texture(pipe, dsrb->format, width, height);
179 if (!dsrb->texture)
180 return TRUE;
181
182 dsrb->surface = pipe->screen->get_tex_surface(pipe->screen,
183 dsrb->texture,
184 0, 0, 0,
185 surface_usage);
186 if (!dsrb->surface) {
187 pipe_resource_reference(&dsrb->texture, NULL);
188 return TRUE;
189 }
190
191 dsrb->width = width;
192 dsrb->height = height;
193
194 assert(dsrb->surface->width == width);
195 assert(dsrb->surface->height == height);
196
197 return TRUE;
198 }
199
200 static boolean
201 vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt)
202 {
203 struct st_renderbuffer *strb = ctx->draw_buffer->strb;
204 struct pipe_screen *screen = ctx->pipe->screen;
205
206 if (strb->texture == pt) {
207 pipe_resource_reference(&pt, NULL);
208 return FALSE;
209 }
210
211 /* unreference existing ones */
212 pipe_surface_reference(&strb->surface, NULL);
213 pipe_resource_reference(&strb->texture, NULL);
214 strb->width = strb->height = 0;
215
216 strb->texture = pt;
217 strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
218 PIPE_BIND_RENDER_TARGET |
219 PIPE_BIND_BLIT_SOURCE |
220 PIPE_BIND_BLIT_DESTINATION);
221 if (!strb->surface) {
222 pipe_resource_reference(&strb->texture, NULL);
223 return TRUE;
224 }
225
226 strb->width = pt->width0;
227 strb->height = pt->height0;
228
229 return TRUE;
230 }
231
232 static void
233 vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt)
234 {
235 struct st_framebuffer *stfb = ctx->draw_buffer;
236 boolean new_cbuf, new_zsbuf, new_size;
237
238 new_cbuf = vg_context_update_color_rb(ctx, pt);
239 new_zsbuf =
240 vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0);
241
242 new_size = (stfb->width != pt->width0 || stfb->height != pt->height0);
243 stfb->width = pt->width0;
244 stfb->height = pt->height0;
245
246 if (new_cbuf || new_zsbuf || new_size) {
247 struct pipe_framebuffer_state *state = &ctx->state.g3d.fb;
248
249 memset(state, 0, sizeof(struct pipe_framebuffer_state));
250 state->width = stfb->width;
251 state->height = stfb->height;
252 state->nr_cbufs = 1;
253 state->cbufs[0] = stfb->strb->surface;
254 state->zsbuf = stfb->dsrb->surface;
255
256 cso_set_framebuffer(ctx->cso_context, state);
257 }
258
259 if (new_zsbuf || new_size) {
260 ctx->state.dirty |= VIEWPORT_DIRTY;
261 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/
262
263 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0);
264
265 /* we need all the other state already set */
266
267 setup_new_alpha_mask(ctx, stfb);
268
269 pipe_sampler_view_reference( &stfb->blend_texture_view, NULL);
270 stfb->blend_texture_view = create_tex_and_view(ctx->pipe,
271 PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
272 }
273 }
274
275 /**
276 * Flush the front buffer if the current context renders to the front buffer.
277 */
278 void
279 vg_manager_flush_frontbuffer(struct vg_context *ctx)
280 {
281 struct st_framebuffer *stfb = ctx->draw_buffer;
282
283 if (!stfb)
284 return;
285
286 switch (stfb->strb_att) {
287 case ST_ATTACHMENT_FRONT_LEFT:
288 case ST_ATTACHMENT_FRONT_RIGHT:
289 stfb->iface->flush_front(stfb->iface, stfb->strb_att);
290 break;
291 default:
292 break;
293 }
294 }
295
296 /**
297 * Re-validate the framebuffer.
298 */
299 void
300 vg_manager_validate_framebuffer(struct vg_context *ctx)
301 {
302 struct st_framebuffer *stfb = ctx->draw_buffer;
303 struct pipe_resource *pt;
304
305 /* no binding surface */
306 if (!stfb)
307 return;
308
309 if (!p_atomic_read(&ctx->draw_buffer_invalid))
310 return;
311
312 /* validate the fb */
313 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt)
314 return;
315
316 /*
317 * unset draw_buffer_invalid first because vg_context_update_draw_buffer
318 * will cause the framebuffer to be validated again because of a call to
319 * vg_validate_state
320 */
321 p_atomic_set(&ctx->draw_buffer_invalid, FALSE);
322 vg_context_update_draw_buffer(ctx, pt);
323 }
324
325
326 static void
327 vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi,
328 struct st_framebuffer_iface *stfbi)
329 {
330 struct vg_context *ctx = (struct vg_context *) stctxi;
331 p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
332 }
333
334 static void
335 vg_context_flush(struct st_context_iface *stctxi, unsigned flags,
336 struct pipe_fence_handle **fence)
337 {
338 struct vg_context *ctx = (struct vg_context *) stctxi;
339 ctx->pipe->flush(ctx->pipe, flags, fence);
340 if (flags & PIPE_FLUSH_RENDER_CACHE)
341 vg_manager_flush_frontbuffer(ctx);
342 }
343
344 static void
345 vg_context_destroy(struct st_context_iface *stctxi)
346 {
347 struct vg_context *ctx = (struct vg_context *) stctxi;
348 vg_destroy_context(ctx);
349 }
350
351 static struct st_context_iface *
352 vg_api_create_context(struct st_api *stapi, struct st_manager *smapi,
353 const struct st_visual *visual,
354 struct st_context_iface *shared_stctxi)
355 {
356 struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi;
357 struct vg_context *ctx;
358 struct pipe_context *pipe;
359
360 pipe = smapi->screen->context_create(smapi->screen, NULL);
361 if (!pipe)
362 return NULL;
363 ctx = vg_create_context(pipe, NULL, shared_ctx);
364 if (!ctx) {
365 pipe->destroy(pipe);
366 return NULL;
367 }
368
369 ctx->iface.destroy = vg_context_destroy;
370
371 ctx->iface.notify_invalid_framebuffer =
372 vg_context_notify_invalid_framebuffer;
373 ctx->iface.flush = vg_context_flush;
374
375 ctx->iface.teximage = NULL;
376 ctx->iface.copy = NULL;
377
378 ctx->iface.st_context_private = (void *) smapi;
379
380 return &ctx->iface;
381 }
382
383 static struct st_renderbuffer *
384 create_renderbuffer(enum pipe_format format)
385 {
386 struct st_renderbuffer *strb;
387
388 strb = CALLOC_STRUCT(st_renderbuffer);
389 if (strb)
390 strb->format = format;
391
392 return strb;
393 }
394
395 static void
396 destroy_renderbuffer(struct st_renderbuffer *strb)
397 {
398 pipe_surface_reference(&strb->surface, NULL);
399 pipe_resource_reference(&strb->texture, NULL);
400 free(strb);
401 }
402
403 /**
404 * Decide the buffer to render to.
405 */
406 static enum st_attachment_type
407 choose_attachment(struct st_framebuffer_iface *stfbi)
408 {
409 enum st_attachment_type statt;
410
411 statt = stfbi->visual->render_buffer;
412 if (statt != ST_ATTACHMENT_INVALID) {
413 /* use the buffer given by the visual, unless it is unavailable */
414 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) {
415 switch (statt) {
416 case ST_ATTACHMENT_BACK_LEFT:
417 statt = ST_ATTACHMENT_FRONT_LEFT;
418 break;
419 case ST_ATTACHMENT_BACK_RIGHT:
420 statt = ST_ATTACHMENT_FRONT_RIGHT;
421 break;
422 default:
423 break;
424 }
425
426 if (!st_visual_have_buffers(stfbi->visual, 1 << statt))
427 statt = ST_ATTACHMENT_INVALID;
428 }
429 }
430
431 return statt;
432 }
433
434 /**
435 * Bind the context to the given framebuffers.
436 */
437 static boolean
438 vg_context_bind_framebuffers(struct st_context_iface *stctxi,
439 struct st_framebuffer_iface *stdrawi,
440 struct st_framebuffer_iface *streadi)
441 {
442 struct vg_context *ctx = (struct vg_context *) stctxi;
443 struct st_framebuffer *stfb;
444 enum st_attachment_type strb_att;
445
446 /* the draw and read framebuffers must be the same */
447 if (stdrawi != streadi)
448 return FALSE;
449
450 p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
451
452 strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID;
453
454 if (ctx->draw_buffer) {
455 stfb = ctx->draw_buffer;
456
457 /* free the existing fb */
458 if (!stdrawi ||
459 stfb->strb_att != strb_att ||
460 stfb->strb->format != stdrawi->visual->color_format ||
461 stfb->dsrb->format != stdrawi->visual->depth_stencil_format) {
462 destroy_renderbuffer(stfb->strb);
463 destroy_renderbuffer(stfb->dsrb);
464 free(stfb);
465
466 ctx->draw_buffer = NULL;
467 }
468 }
469
470 if (!stdrawi)
471 return TRUE;
472
473 if (strb_att == ST_ATTACHMENT_INVALID)
474 return FALSE;
475
476 /* create a new fb */
477 if (!ctx->draw_buffer) {
478 stfb = CALLOC_STRUCT(st_framebuffer);
479 if (!stfb)
480 return FALSE;
481
482 stfb->strb = create_renderbuffer(stdrawi->visual->color_format);
483 if (!stfb->strb) {
484 free(stfb);
485 return FALSE;
486 }
487
488 stfb->dsrb = create_renderbuffer(stdrawi->visual->depth_stencil_format);
489 if (!stfb->dsrb) {
490 free(stfb->strb);
491 free(stfb);
492 return FALSE;
493 }
494
495 stfb->width = 0;
496 stfb->height = 0;
497 stfb->strb_att = strb_att;
498
499 ctx->draw_buffer = stfb;
500 }
501
502 ctx->draw_buffer->iface = stdrawi;
503
504 return TRUE;
505 }
506
507 static boolean
508 vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
509 struct st_framebuffer_iface *stdrawi,
510 struct st_framebuffer_iface *streadi)
511 {
512 struct vg_context *ctx = (struct vg_context *) stctxi;
513
514 if (stctxi)
515 vg_context_bind_framebuffers(stctxi, stdrawi, streadi);
516 vg_set_current_context(ctx);
517
518 return TRUE;
519 }
520
521 static struct st_context_iface *
522 vg_api_get_current(struct st_api *stapi)
523 {
524 struct vg_context *ctx = vg_current_context();
525
526 return (ctx) ? &ctx->iface : NULL;
527 }
528
529 static boolean
530 vg_api_is_visual_supported(struct st_api *stapi,
531 const struct st_visual *visual)
532 {
533 /* the impl requires a depth/stencil buffer */
534 return util_format_is_depth_and_stencil(visual->depth_stencil_format);
535 }
536
537 static st_proc_t
538 vg_api_get_proc_address(struct st_api *stapi, const char *procname)
539 {
540 return api_get_proc_address(procname);
541 }
542
543 static void
544 vg_api_destroy(struct st_api *stapi)
545 {
546 free(stapi);
547 }
548
549 struct st_api st_vg_api = {
550 vg_api_destroy,
551 vg_api_get_proc_address,
552 vg_api_is_visual_supported,
553 vg_api_create_context,
554 vg_api_make_current,
555 vg_api_get_current,
556 };
557
558 struct st_api *
559 st_api_create_OpenVG(void)
560 {
561 return &st_vg_api;
562 }