Merge remote branch 'origin/7.8'
[mesa.git] / src / gallium / state_trackers / dri / common / dri_st_api.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 "util/u_memory.h"
30 #include "util/u_inlines.h"
31 #include "util/u_format.h"
32 #include "util/u_debug.h"
33 #include "state_tracker/st_manager.h" /* for st_manager_create_api */
34
35 #include "dri_screen.h"
36 #include "dri_context.h"
37 #include "dri_drawable.h"
38 #include "dri_st_api.h"
39 #ifndef __NOT_HAVE_DRM_H
40 #include "dri1.h"
41 #include "dri2.h"
42 #else
43 #include "drisw.h"
44 #endif
45
46 static boolean
47 dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
48 const enum st_attachment_type *statts,
49 unsigned count,
50 struct pipe_resource **out)
51 {
52 struct dri_drawable *drawable =
53 (struct dri_drawable *) stfbi->st_manager_private;
54 unsigned statt_mask, new_mask;
55 boolean new_stamp;
56 int i;
57
58 statt_mask = 0x0;
59 for (i = 0; i < count; i++)
60 statt_mask |= (1 << statts[i]);
61
62 /* record newly allocated textures */
63 new_mask = (statt_mask & ~drawable->texture_mask);
64
65 /*
66 * dPriv->pStamp is the server stamp. It should be accessed with a lock, at
67 * least for DRI1. dPriv->lastStamp is the client stamp. It has the value
68 * of the server stamp when last checked.
69 */
70 new_stamp = (drawable->texture_stamp != drawable->dPriv->lastStamp);
71
72 if (new_stamp || new_mask) {
73
74 #ifndef __NOT_HAVE_DRM_H
75 if (__dri1_api_hooks) {
76 dri1_allocate_textures(drawable, statt_mask);
77 }
78 else {
79 dri2_allocate_textures(drawable, statts, count);
80 }
81 #else
82 if (new_stamp)
83 drisw_update_drawable_info(drawable);
84
85 drisw_allocate_textures(drawable, statt_mask);
86 #endif
87
88 /* add existing textures */
89 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
90 if (drawable->textures[i])
91 statt_mask |= (1 << i);
92 }
93
94 drawable->texture_stamp = drawable->dPriv->lastStamp;
95 drawable->texture_mask = statt_mask;
96 }
97
98 if (!out)
99 return TRUE;
100
101 for (i = 0; i < count; i++) {
102 out[i] = NULL;
103 pipe_resource_reference(&out[i], drawable->textures[statts[i]]);
104 }
105
106 return TRUE;
107 }
108
109 static boolean
110 dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
111 enum st_attachment_type statt)
112 {
113 struct dri_drawable *drawable =
114 (struct dri_drawable *) stfbi->st_manager_private;
115
116 #ifndef __NOT_HAVE_DRM_H
117 if (__dri1_api_hooks) {
118 dri1_flush_frontbuffer(drawable, statt);
119 }
120 else {
121 dri2_flush_frontbuffer(drawable, statt);
122 }
123 #else
124 drisw_flush_frontbuffer(drawable, statt);
125 #endif
126
127 return TRUE;
128 }
129
130 /**
131 * Create a framebuffer from the given drawable.
132 */
133 struct st_framebuffer_iface *
134 dri_create_st_framebuffer(struct dri_drawable *drawable)
135 {
136 struct st_framebuffer_iface *stfbi;
137
138 stfbi = CALLOC_STRUCT(st_framebuffer_iface);
139 if (stfbi) {
140 stfbi->visual = &drawable->stvis;
141 stfbi->flush_front = dri_st_framebuffer_flush_front;
142 stfbi->validate = dri_st_framebuffer_validate;
143 stfbi->st_manager_private = (void *) drawable;
144 }
145
146 return stfbi;
147 }
148
149 /**
150 * Destroy a framebuffer.
151 */
152 void
153 dri_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
154 {
155 struct dri_drawable *drawable =
156 (struct dri_drawable *) stfbi->st_manager_private;
157 int i;
158
159 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
160 pipe_resource_reference(&drawable->textures[i], NULL);
161
162 FREE(stfbi);
163 }
164
165 /**
166 * Validate the texture at an attachment. Allocate the texture if it does not
167 * exist.
168 */
169 void
170 dri_st_framebuffer_validate_att(struct st_framebuffer_iface *stfbi,
171 enum st_attachment_type statt)
172 {
173 struct dri_drawable *drawable =
174 (struct dri_drawable *) stfbi->st_manager_private;
175 enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
176 unsigned i, count = 0;
177
178 /* check if buffer already exists */
179 if (drawable->texture_mask & (1 << statt))
180 return;
181
182 /* make sure DRI2 does not destroy existing buffers */
183 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
184 if (drawable->texture_mask & (1 << i)) {
185 statts[count++] = i;
186 }
187 }
188 statts[count++] = statt;
189
190 drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
191
192 stfbi->validate(stfbi, statts, count, NULL);
193 }
194
195 /**
196 * Reference counted st_api.
197 */
198 static struct {
199 int32_t refcnt;
200 struct st_api *stapi;
201 } dri_st_api;
202
203 /**
204 * Add a reference to the st_api of the state tracker.
205 */
206 static void
207 _dri_get_st_api(void)
208 {
209 p_atomic_inc(&dri_st_api.refcnt);
210 if (p_atomic_read(&dri_st_api.refcnt) == 1)
211 dri_st_api.stapi = st_manager_create_api();
212 }
213
214 /**
215 * Remove a reference to the st_api of the state tracker.
216 */
217 static void
218 _dri_put_st_api(void)
219 {
220 struct st_api *stapi = dri_st_api.stapi;
221
222 if (p_atomic_dec_zero(&dri_st_api.refcnt)) {
223 stapi->destroy(dri_st_api.stapi);
224 dri_st_api.stapi = NULL;
225 }
226 }
227
228 static boolean
229 dri_st_manager_get_egl_image(struct st_manager *smapi,
230 struct st_egl_image *stimg)
231 {
232 __DRIimage *img = NULL;
233
234 #ifndef __NOT_HAVE_DRM_H
235 if (!__dri1_api_hooks) {
236 struct dri_context *ctx = (struct dri_context *)
237 stimg->stctxi->st_manager_private;
238 img = dri2_lookup_egl_image(ctx, stimg->egl_image);
239 }
240 #endif
241 if (!img)
242 return FALSE;
243
244 stimg->texture = NULL;
245 pipe_resource_reference(&stimg->texture, img->texture);
246 stimg->face = img->face;
247 stimg->level = img->level;
248 stimg->zslice = img->zslice;
249
250 return TRUE;
251 }
252
253 /**
254 * Create a state tracker manager from the given screen.
255 */
256 struct st_manager *
257 dri_create_st_manager(struct dri_screen *screen)
258 {
259 struct st_manager *smapi;
260
261 smapi = CALLOC_STRUCT(st_manager);
262 if (smapi) {
263 smapi->screen = screen->pipe_screen;
264 smapi->get_egl_image = dri_st_manager_get_egl_image;
265 _dri_get_st_api();
266 }
267
268 return smapi;
269 }
270
271 /**
272 * Destroy a state tracker manager.
273 */
274 void
275 dri_destroy_st_manager(struct st_manager *smapi)
276 {
277 _dri_put_st_api();
278 FREE(smapi);
279 }
280
281 /**
282 * Return the st_api of OpenGL state tracker.
283 */
284 struct st_api *
285 dri_get_st_api(void)
286 {
287 assert(dri_st_api.stapi);
288 return dri_st_api.stapi;
289 }