st/dri: add TODO list for DRISW
[mesa.git] / src / gallium / state_trackers / dri / drisw.c
1 /**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 /* TODO:
30 *
31 * stride:
32 *
33 * The driver and the loaders (libGL, xserver/glx) compute the stride from the
34 * width independently. winsys has a workaround that works for softpipe but may
35 * explode for other drivers or platforms, rendering- or performance-wise.
36 * Solving this issue properly requires extending the DRISW loader extension,
37 * in order to make the stride available to the putImage callback.
38 *
39 * drisw_api:
40 *
41 * Define drisw_api similarly to dri_api and use it to call the loader. This is
42 * predicated on support for calling the loader from the winsys, which has to
43 * grow for DRI2 as well.
44 *
45 * xshm:
46 *
47 * Allow the loaders to use the XSHM extension. It probably requires callbacks
48 * for createImage/destroyImage similar to DRI2 getBuffers. Probably not worth
49 * it, given the scope of DRISW, unless it falls naturally from properly
50 * solving the above two issues.
51 *
52 * swrast_create_screen:
53 *
54 * Allow for any software renderer to be used. Factor out the code from
55 * targets/libgl-xlib/xlib.c, put it in targets/common or winsys/sw/common and
56 * use it in all software targets.
57 */
58
59 #include "util/u_memory.h"
60 #include "util/u_inlines.h"
61 #include "pipe/p_context.h"
62 #include "state_tracker/drm_api.h"
63
64 #include "dri_screen.h"
65 #include "dri_context.h"
66 #include "dri_drawable.h"
67 #include "dri_st_api.h"
68 #include "dri1_helper.h"
69 #include "drisw.h"
70
71
72 static INLINE void
73 get_drawable_info(__DRIdrawable *dPriv, int *w, int *h)
74 {
75 __DRIscreen *sPriv = dPriv->driScreenPriv;
76 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
77 int x, y;
78
79 loader->getDrawableInfo(dPriv,
80 &x, &y, w, h,
81 dPriv->loaderPrivate);
82 }
83
84 static INLINE void
85 put_image(__DRIdrawable *dPriv, void *data)
86 {
87 __DRIscreen *sPriv = dPriv->driScreenPriv;
88 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
89
90 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
91 0, 0, dPriv->w, dPriv->h,
92 data, dPriv->loaderPrivate);
93 }
94
95 void
96 drisw_update_drawable_info(__DRIdrawable *dPriv)
97 {
98 get_drawable_info(dPriv, &dPriv->w, &dPriv->h);
99 }
100
101 static INLINE void
102 drisw_present_texture(__DRIdrawable *dPriv,
103 struct pipe_texture *ptex)
104 {
105 struct dri_drawable *drawable = dri_drawable(dPriv);
106 struct dri_screen *screen = dri_screen(drawable->sPriv);
107 struct pipe_context *pipe;
108 struct pipe_surface *psurf;
109 struct pipe_transfer *ptrans;
110 void *pmap;
111
112 pipe = dri1_get_pipe_context(screen);
113 psurf = dri1_get_pipe_surface(drawable, ptex);
114 if (!pipe || !psurf)
115 return;
116
117 ptrans = pipe->get_tex_transfer(pipe, ptex, 0, 0, 0,
118 PIPE_TRANSFER_READ,
119 0, 0, dPriv->w, dPriv->h);
120
121 pmap = pipe->transfer_map(pipe, ptrans);
122
123 assert(pmap);
124
125 put_image(dPriv, pmap);
126
127 pipe->transfer_unmap(pipe, ptrans);
128
129 pipe->tex_transfer_destroy(pipe, ptrans);
130 }
131
132 static INLINE void
133 drisw_invalidate_drawable(__DRIdrawable *dPriv)
134 {
135 struct dri_context *ctx = dri_get_current();
136 struct dri_drawable *drawable = dri_drawable(dPriv);
137
138 drawable->texture_stamp = dPriv->lastStamp - 1;
139
140 /* check if swapping currently bound buffer */
141 if (ctx && ctx->dPriv == dPriv)
142 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
143 }
144
145 static INLINE void
146 drisw_copy_to_front(__DRIdrawable * dPriv,
147 struct pipe_texture *ptex)
148 {
149 drisw_present_texture(dPriv, ptex);
150
151 drisw_invalidate_drawable(dPriv);
152 }
153
154 /*
155 * Backend functions for st_framebuffer interface and swap_buffers.
156 */
157
158 void
159 drisw_flush_frontbuffer(struct dri_drawable *drawable,
160 enum st_attachment_type statt)
161 {
162 struct dri_context *ctx = dri_get_current();
163 struct pipe_texture *ptex;
164
165 if (!ctx)
166 return;
167
168 ptex = drawable->textures[statt];
169
170 if (ptex) {
171 drisw_copy_to_front(ctx->dPriv, ptex);
172 }
173 }
174
175 void
176 drisw_swap_buffers(__DRIdrawable *dPriv)
177 {
178 struct dri_context *ctx = dri_get_current();
179 struct dri_drawable *drawable = dri_drawable(dPriv);
180 struct pipe_texture *ptex;
181
182 if (!ctx)
183 return;
184
185 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
186
187 if (ptex) {
188 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
189
190 drisw_copy_to_front(dPriv, ptex);
191 }
192 }
193
194 /**
195 * Allocate framebuffer attachments.
196 *
197 * During fixed-size operation, the function keeps allocating new attachments
198 * as they are requested. Unused attachments are not removed, not until the
199 * framebuffer is resized or destroyed.
200 *
201 * It should be possible for DRI1 and DRISW to share this function, but it
202 * seems a better seperation and safer for each DRI version to provide its own
203 * function.
204 */
205 void
206 drisw_allocate_textures(struct dri_drawable *drawable,
207 unsigned mask)
208 {
209 struct dri_screen *screen = dri_screen(drawable->sPriv);
210 struct pipe_texture templ;
211 unsigned width, height;
212 boolean resized;
213 int i;
214
215 width = drawable->dPriv->w;
216 height = drawable->dPriv->h;
217
218 resized = (drawable->old_w != width ||
219 drawable->old_h != height);
220
221 /* remove outdated textures */
222 if (resized) {
223 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
224 pipe_texture_reference(&drawable->textures[i], NULL);
225 }
226
227 memset(&templ, 0, sizeof(templ));
228 templ.target = PIPE_TEXTURE_2D;
229 templ.width0 = width;
230 templ.height0 = height;
231 templ.depth0 = 1;
232 templ.last_level = 0;
233
234 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
235 enum pipe_format format;
236 unsigned tex_usage;
237
238 /* the texture already exists or not requested */
239 if (drawable->textures[i] || !(mask & (1 << i))) {
240 continue;
241 }
242
243 switch (i) {
244 case ST_ATTACHMENT_FRONT_LEFT:
245 case ST_ATTACHMENT_BACK_LEFT:
246 case ST_ATTACHMENT_FRONT_RIGHT:
247 case ST_ATTACHMENT_BACK_RIGHT:
248 format = drawable->stvis.color_format;
249 tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
250 PIPE_TEXTURE_USAGE_RENDER_TARGET;
251 break;
252 case ST_ATTACHMENT_DEPTH_STENCIL:
253 format = drawable->stvis.depth_stencil_format;
254 tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
255 break;
256 default:
257 format = PIPE_FORMAT_NONE;
258 break;
259 }
260
261 if (format != PIPE_FORMAT_NONE) {
262 templ.format = format;
263 templ.tex_usage = tex_usage;
264
265 drawable->textures[i] =
266 screen->pipe_screen->texture_create(screen->pipe_screen, &templ);
267 }
268 }
269
270 drawable->old_w = width;
271 drawable->old_h = height;
272 }
273
274 /*
275 * Backend function for init_screen.
276 */
277
278 static const __DRIextension *drisw_screen_extensions[] = {
279 NULL
280 };
281
282 const __DRIconfig **
283 drisw_init_screen(__DRIscreen * sPriv)
284 {
285 struct dri_screen *screen;
286 struct drm_create_screen_arg arg;
287
288 screen = CALLOC_STRUCT(dri_screen);
289 if (!screen)
290 return NULL;
291
292 screen->api = drm_api_create();
293 screen->sPriv = sPriv;
294 screen->fd = -1;
295 sPriv->private = (void *)screen;
296 sPriv->extensions = drisw_screen_extensions;
297 arg.mode = DRM_CREATE_DRISW;
298
299 screen->pipe_screen = screen->api->create_screen(screen->api, -1, &arg);
300 if (!screen->pipe_screen) {
301 debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__);
302 goto fail;
303 }
304
305 screen->smapi = dri_create_st_manager(screen);
306 if (!screen->smapi)
307 goto fail;
308
309 driParseOptionInfo(&screen->optionCache,
310 __driConfigOptions, __driNConfigOptions);
311
312 return dri_fill_in_modes(screen, 32);
313 fail:
314 dri_destroy_screen(sPriv);
315 return NULL;
316 }
317
318 /* vim: set sw=3 ts=8 sts=3 expandtab: */