Merge commit 'origin/7.8'
[mesa.git] / src / gallium / state_trackers / vega / vg_manager.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include "state_tracker/st_api.h"
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_screen.h"
33 #include "util/u_memory.h"
34 #include "util/u_inlines.h"
35 #include "util/u_format.h"
36
37 #include "vg_manager.h"
38 #include "vg_context.h"
39 #include "vg_tracker.h" /* for st_resize_framebuffer */
40 #include "image.h"
41
42 /**
43 * Flush the front buffer if the current context renders to the front buffer.
44 */
45 void
46 vg_manager_flush_frontbuffer(struct vg_context *ctx)
47 {
48 struct st_framebuffer *stfb = ctx->draw_buffer;
49
50 if (!stfb)
51 return;
52
53 /* st_public.h is used */
54 if (!stfb->iface) {
55 struct pipe_screen *screen = ctx->pipe->screen;
56 if (screen->flush_frontbuffer) {
57 screen->flush_frontbuffer(screen,
58 stfb->strb->surface, ctx->pipe->priv);
59 }
60 return;
61 }
62
63 switch (stfb->strb_att) {
64 case ST_ATTACHMENT_FRONT_LEFT:
65 case ST_ATTACHMENT_FRONT_RIGHT:
66 stfb->iface->flush_front(stfb->iface, stfb->strb_att);
67 break;
68 default:
69 break;
70 }
71 }
72
73 /**
74 * Re-validate the framebuffer.
75 */
76 void
77 vg_manager_validate_framebuffer(struct vg_context *ctx)
78 {
79 struct pipe_screen *screen = ctx->pipe->screen;
80 struct st_framebuffer *stfb = ctx->draw_buffer;
81 struct st_renderbuffer *rb;
82 struct pipe_resource *pt;
83
84 /* no binding surface */
85 if (!stfb)
86 return;
87
88 /* st_public.h is used */
89 if (!stfb->iface) {
90 struct pipe_screen *screen = ctx->pipe->screen;
91 if (screen->update_buffer)
92 screen->update_buffer(screen, ctx->pipe->priv);
93 return;
94 }
95
96 if (!p_atomic_read(&ctx->draw_buffer_invalid))
97 return;
98
99 /* validate the fb */
100 if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt)
101 return;
102
103 rb = stfb->strb;
104 if (rb->texture == pt) {
105 pipe_resource_reference(&pt, NULL);
106 return;
107 }
108
109 /* unreference existing ones */
110 pipe_surface_reference(&rb->surface, NULL);
111 pipe_resource_reference(&rb->texture, NULL);
112
113 rb->texture = pt;
114 rb->surface = screen->get_tex_surface(screen, rb->texture, 0, 0, 0,
115 PIPE_BIND_RENDER_TARGET |
116 PIPE_BIND_BLIT_SOURCE |
117 PIPE_BIND_BLIT_DESTINATION);
118
119 rb->width = rb->surface->width;
120 rb->height = rb->surface->height;
121
122 st_resize_framebuffer(stfb, rb->width, rb->height);
123
124 p_atomic_set(&ctx->draw_buffer_invalid, FALSE);
125 }
126
127
128 static void
129 vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi,
130 struct st_framebuffer_iface *stfbi)
131 {
132 struct vg_context *ctx = (struct vg_context *) stctxi;
133 p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
134 }
135
136 static void
137 vg_context_flush(struct st_context_iface *stctxi, unsigned flags,
138 struct pipe_fence_handle **fence)
139 {
140 struct vg_context *ctx = (struct vg_context *) stctxi;
141 ctx->pipe->flush(ctx->pipe, flags, fence);
142 if (flags & PIPE_FLUSH_RENDER_CACHE)
143 vg_manager_flush_frontbuffer(ctx);
144 }
145
146 static void
147 vg_context_destroy(struct st_context_iface *stctxi)
148 {
149 struct vg_context *ctx = (struct vg_context *) stctxi;
150 vg_destroy_context(ctx);
151 }
152
153 static struct st_context_iface *
154 vg_api_create_context(struct st_api *stapi, struct st_manager *smapi,
155 const struct st_visual *visual,
156 struct st_context_iface *shared_stctxi)
157 {
158 struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi;
159 struct vg_context *ctx;
160 struct pipe_context *pipe;
161
162 pipe = smapi->screen->context_create(smapi->screen, NULL);
163 if (!pipe)
164 return NULL;
165 ctx = vg_create_context(pipe, NULL, shared_ctx);
166 if (!ctx) {
167 pipe->destroy(pipe);
168 return NULL;
169 }
170
171 ctx->iface.destroy = vg_context_destroy;
172
173 ctx->iface.notify_invalid_framebuffer =
174 vg_context_notify_invalid_framebuffer;
175 ctx->iface.flush = vg_context_flush;
176
177 ctx->iface.teximage = NULL;
178 ctx->iface.copy = NULL;
179
180 ctx->iface.st_context_private = (void *) smapi;
181
182 return &ctx->iface;
183 }
184
185 static struct st_renderbuffer *
186 create_renderbuffer(enum pipe_format format)
187 {
188 struct st_renderbuffer *strb;
189
190 strb = CALLOC_STRUCT(st_renderbuffer);
191 if (strb)
192 strb->format = format;
193
194 return strb;
195 }
196
197 static void
198 destroy_renderbuffer(struct st_renderbuffer *strb)
199 {
200 pipe_surface_reference(&strb->surface, NULL);
201 pipe_resource_reference(&strb->texture, NULL);
202 free(strb);
203 }
204
205 /**
206 * Decide the buffer to render to.
207 */
208 static enum st_attachment_type
209 choose_attachment(struct st_framebuffer_iface *stfbi)
210 {
211 enum st_attachment_type statt;
212
213 statt = stfbi->visual->render_buffer;
214 if (statt != ST_ATTACHMENT_INVALID) {
215 /* use the buffer given by the visual, unless it is unavailable */
216 if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) {
217 switch (statt) {
218 case ST_ATTACHMENT_BACK_LEFT:
219 statt = ST_ATTACHMENT_FRONT_LEFT;
220 break;
221 case ST_ATTACHMENT_BACK_RIGHT:
222 statt = ST_ATTACHMENT_FRONT_RIGHT;
223 break;
224 default:
225 break;
226 }
227
228 if (!st_visual_have_buffers(stfbi->visual, 1 << statt))
229 statt = ST_ATTACHMENT_INVALID;
230 }
231 }
232
233 return statt;
234 }
235
236 /**
237 * Bind the context to the given framebuffers.
238 */
239 static boolean
240 vg_context_bind_framebuffers(struct st_context_iface *stctxi,
241 struct st_framebuffer_iface *stdrawi,
242 struct st_framebuffer_iface *streadi)
243 {
244 struct vg_context *ctx = (struct vg_context *) stctxi;
245 struct st_framebuffer *stfb;
246 enum st_attachment_type strb_att;
247
248 /* the draw and read framebuffers must be the same */
249 if (stdrawi != streadi)
250 return FALSE;
251
252 p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
253
254 strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID;
255
256 if (ctx->draw_buffer) {
257 stfb = ctx->draw_buffer;
258
259 /* free the existing fb */
260 if (!stdrawi ||
261 stfb->strb_att != strb_att ||
262 stfb->strb->format != stdrawi->visual->color_format ||
263 stfb->dsrb->format != stdrawi->visual->depth_stencil_format) {
264 destroy_renderbuffer(stfb->strb);
265 destroy_renderbuffer(stfb->dsrb);
266 free(stfb);
267
268 ctx->draw_buffer = NULL;
269 }
270 }
271
272 if (!stdrawi)
273 return TRUE;
274
275 if (strb_att == ST_ATTACHMENT_INVALID)
276 return FALSE;
277
278 /* create a new fb */
279 if (!ctx->draw_buffer) {
280 stfb = CALLOC_STRUCT(st_framebuffer);
281 if (!stfb)
282 return FALSE;
283
284 stfb->strb = create_renderbuffer(stdrawi->visual->color_format);
285 if (!stfb->strb) {
286 free(stfb);
287 return FALSE;
288 }
289
290 stfb->dsrb = create_renderbuffer(stdrawi->visual->depth_stencil_format);
291 if (!stfb->dsrb) {
292 free(stfb->strb);
293 free(stfb);
294 return FALSE;
295 }
296
297 stfb->width = 0;
298 stfb->height = 0;
299 stfb->strb_att = strb_att;
300
301 ctx->draw_buffer = stfb;
302 }
303
304 ctx->draw_buffer->iface = stdrawi;
305
306 return TRUE;
307 }
308
309 static boolean
310 vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
311 struct st_framebuffer_iface *stdrawi,
312 struct st_framebuffer_iface *streadi)
313 {
314 struct vg_context *ctx = (struct vg_context *) stctxi;
315
316 if (stctxi)
317 vg_context_bind_framebuffers(stctxi, stdrawi, streadi);
318 vg_set_current_context(ctx);
319
320 return TRUE;
321 }
322
323 static struct st_context_iface *
324 vg_api_get_current(struct st_api *stapi)
325 {
326 struct vg_context *ctx = vg_current_context();
327
328 return (ctx) ? &ctx->iface : NULL;
329 }
330
331 static boolean
332 vg_api_is_visual_supported(struct st_api *stapi,
333 const struct st_visual *visual)
334 {
335 /* the impl requires a depth/stencil buffer */
336 return util_format_is_depth_and_stencil(visual->depth_stencil_format);
337 }
338
339 static st_proc_t
340 vg_api_get_proc_address(struct st_api *stapi, const char *procname)
341 {
342 /* TODO */
343 return (st_proc_t) NULL;
344 }
345
346 static void
347 vg_api_destroy(struct st_api *stapi)
348 {
349 free(stapi);
350 }
351
352 static struct st_api *
353 vg_module_create_api(void)
354 {
355 struct st_api *stapi;
356
357 stapi = CALLOC_STRUCT(st_api);
358 if (stapi) {
359 stapi->destroy = vg_api_destroy;
360 stapi->get_proc_address = vg_api_get_proc_address;
361 stapi->is_visual_supported = vg_api_is_visual_supported;
362
363 stapi->create_context = vg_api_create_context;
364 stapi->make_current = vg_api_make_current;
365 stapi->get_current = vg_api_get_current;
366 }
367
368 return stapi;
369 }
370
371 PUBLIC const struct st_module st_module_OpenVG = {
372 .api = ST_API_OPENVG,
373 .create_api = vg_module_create_api,
374 };