drisw: probably better hack for stride and some comments
[mesa.git] / src / gallium / state_trackers / dri / sw / 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 dri1_api and use it to call the loader. This
42 * is predicated on support for calling the loader from the winsys, which has
43 * to grow for DRI2 as well.
44 *
45 * xshm / texture_from_pixmap / EGLImage:
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 other issues.
51 *
52 * fences:
53 *
54 * No fences are used, are they needed for llvmpipe / cell ?
55 */
56
57 #include "util/u_format.h"
58 #include "util/u_memory.h"
59 #include "util/u_inlines.h"
60 #include "pipe/p_context.h"
61 #include "state_tracker/drm_api.h"
62
63 #include "dri_screen.h"
64 #include "dri_context.h"
65 #include "dri_drawable.h"
66 #include "dri_st_api.h"
67 #include "dri1_helper.h"
68 #include "drisw.h"
69
70
71 static INLINE void
72 get_drawable_info(__DRIdrawable *dPriv, int *w, int *h)
73 {
74 __DRIscreen *sPriv = dPriv->driScreenPriv;
75 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
76 int x, y;
77
78 loader->getDrawableInfo(dPriv,
79 &x, &y, w, h,
80 dPriv->loaderPrivate);
81 }
82
83 /*
84 * Set the width to 'stride / cpp'. PutImage seems to correctly clip the width
85 * to the actual width of the dst drawable. Even if this is not specified but
86 * an implementation detail, it is the correct thing to do, so rely on it. XXX
87 */
88 static INLINE void
89 put_image(__DRIdrawable *dPriv, void *data, unsigned width)
90 {
91 __DRIscreen *sPriv = dPriv->driScreenPriv;
92 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
93
94 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
95 0, 0, width, dPriv->h,
96 data, dPriv->loaderPrivate);
97 }
98
99 void
100 drisw_update_drawable_info(__DRIdrawable *dPriv)
101 {
102 get_drawable_info(dPriv, &dPriv->w, &dPriv->h);
103 }
104
105 static INLINE void
106 drisw_present_texture(__DRIdrawable *dPriv,
107 struct pipe_texture *ptex)
108 {
109 struct dri_drawable *drawable = dri_drawable(dPriv);
110 struct dri_screen *screen = dri_screen(drawable->sPriv);
111 struct pipe_context *pipe;
112 struct pipe_surface *psurf;
113 struct pipe_transfer *ptrans;
114 void *pmap;
115 unsigned width;
116
117 pipe = dri1_get_pipe_context(screen);
118 psurf = dri1_get_pipe_surface(drawable, ptex);
119 if (!pipe || !psurf)
120 return;
121
122 ptrans = pipe->get_tex_transfer(pipe, ptex, 0, 0, 0,
123 PIPE_TRANSFER_READ,
124 0, 0, dPriv->w, dPriv->h);
125
126 width = ptrans->stride / util_format_get_blocksize(ptex->format);
127
128 pmap = pipe->transfer_map(pipe, ptrans);
129
130 assert(pmap);
131
132 put_image(dPriv, pmap, width);
133
134 pipe->transfer_unmap(pipe, ptrans);
135
136 pipe->tex_transfer_destroy(pipe, ptrans);
137 }
138
139 static INLINE void
140 drisw_invalidate_drawable(__DRIdrawable *dPriv)
141 {
142 struct dri_context *ctx = dri_get_current();
143 struct dri_drawable *drawable = dri_drawable(dPriv);
144
145 drawable->texture_stamp = dPriv->lastStamp - 1;
146
147 /* check if swapping currently bound buffer */
148 if (ctx && ctx->dPriv == dPriv)
149 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
150 }
151
152 static INLINE void
153 drisw_copy_to_front(__DRIdrawable * dPriv,
154 struct pipe_texture *ptex)
155 {
156 drisw_present_texture(dPriv, ptex);
157
158 drisw_invalidate_drawable(dPriv);
159 }
160
161 /*
162 * Backend functions for st_framebuffer interface and swap_buffers.
163 */
164
165 void
166 drisw_flush_frontbuffer(struct dri_drawable *drawable,
167 enum st_attachment_type statt)
168 {
169 struct dri_context *ctx = dri_get_current();
170 struct pipe_texture *ptex;
171
172 if (!ctx)
173 return;
174
175 ptex = drawable->textures[statt];
176
177 if (ptex) {
178 drisw_copy_to_front(ctx->dPriv, ptex);
179 }
180 }
181
182 void
183 drisw_swap_buffers(__DRIdrawable *dPriv)
184 {
185 struct dri_context *ctx = dri_get_current();
186 struct dri_drawable *drawable = dri_drawable(dPriv);
187 struct pipe_texture *ptex;
188
189 if (!ctx)
190 return;
191
192 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
193
194 if (ptex) {
195 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
196
197 drisw_copy_to_front(dPriv, ptex);
198 }
199 }
200
201 /**
202 * Allocate framebuffer attachments.
203 *
204 * During fixed-size operation, the function keeps allocating new attachments
205 * as they are requested. Unused attachments are not removed, not until the
206 * framebuffer is resized or destroyed.
207 *
208 * It should be possible for DRI1 and DRISW to share this function, but it
209 * seems a better seperation and safer for each DRI version to provide its own
210 * function.
211 */
212 void
213 drisw_allocate_textures(struct dri_drawable *drawable,
214 unsigned mask)
215 {
216 struct dri_screen *screen = dri_screen(drawable->sPriv);
217 struct pipe_texture templ;
218 unsigned width, height;
219 boolean resized;
220 int i;
221
222 width = drawable->dPriv->w;
223 height = drawable->dPriv->h;
224
225 resized = (drawable->old_w != width ||
226 drawable->old_h != height);
227
228 /* remove outdated textures */
229 if (resized) {
230 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
231 pipe_texture_reference(&drawable->textures[i], NULL);
232 }
233
234 memset(&templ, 0, sizeof(templ));
235 templ.target = PIPE_TEXTURE_2D;
236 templ.width0 = width;
237 templ.height0 = height;
238 templ.depth0 = 1;
239 templ.last_level = 0;
240
241 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
242 enum pipe_format format;
243 unsigned tex_usage;
244
245 /* the texture already exists or not requested */
246 if (drawable->textures[i] || !(mask & (1 << i))) {
247 continue;
248 }
249
250 switch (i) {
251 case ST_ATTACHMENT_FRONT_LEFT:
252 case ST_ATTACHMENT_BACK_LEFT:
253 case ST_ATTACHMENT_FRONT_RIGHT:
254 case ST_ATTACHMENT_BACK_RIGHT:
255 format = drawable->stvis.color_format;
256 tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
257 PIPE_TEXTURE_USAGE_RENDER_TARGET;
258 break;
259 case ST_ATTACHMENT_DEPTH_STENCIL:
260 format = drawable->stvis.depth_stencil_format;
261 tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
262 break;
263 default:
264 format = PIPE_FORMAT_NONE;
265 break;
266 }
267
268 if (format != PIPE_FORMAT_NONE) {
269 templ.format = format;
270 templ.tex_usage = tex_usage;
271
272 drawable->textures[i] =
273 screen->pipe_screen->texture_create(screen->pipe_screen, &templ);
274 }
275 }
276
277 drawable->old_w = width;
278 drawable->old_h = height;
279 }
280
281 /*
282 * Backend function for init_screen.
283 */
284
285 static const __DRIextension *drisw_screen_extensions[] = {
286 NULL
287 };
288
289 const __DRIconfig **
290 drisw_init_screen(__DRIscreen * sPriv)
291 {
292 const __DRIconfig **configs;
293 struct dri_screen *screen;
294 struct drm_create_screen_arg arg;
295
296 screen = CALLOC_STRUCT(dri_screen);
297 if (!screen)
298 return NULL;
299
300 screen->api = drm_api_create();
301 screen->sPriv = sPriv;
302 screen->fd = -1;
303
304 sPriv->private = (void *)screen;
305 sPriv->extensions = drisw_screen_extensions;
306
307 arg.mode = DRM_CREATE_DRISW;
308
309 configs = dri_init_screen_helper(screen, &arg, 32);
310 if (!configs)
311 goto fail;
312
313 return configs;
314 fail:
315 dri_destroy_screen_helper(screen);
316 FREE(screen);
317 return NULL;
318 }
319
320 /* This is the table of extensions that the loader will dlsym() for. */
321 PUBLIC const __DRIextension *__driDriverExtensions[] = {
322 &driCoreExtension.base,
323 &driSWRastExtension.base,
324 NULL
325 };
326
327 /* vim: set sw=3 ts=8 sts=3 expandtab: */