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