st/dri mv __driDriverExtensions to drisw.c and dri2.c
[mesa.git] / src / gallium / state_trackers / dri / drm / dri2.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright 2009, VMware, Inc.
6 * All Rights Reserved.
7 * Copyright (C) 2010 LunarG Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions 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 MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Keith Whitwell <keithw@vmware.com>
28 * Jakob Bornecrantz <wallbraker@gmail.com>
29 * Chia-I Wu <olv@lunarg.com>
30 */
31
32 #include "util/u_memory.h"
33 #include "util/u_inlines.h"
34 #include "util/u_format.h"
35 #include "util/u_debug.h"
36 #include "state_tracker/drm_api.h"
37
38 #include "dri_screen.h"
39 #include "dri_context.h"
40 #include "dri_drawable.h"
41 #include "dri_st_api.h"
42 #include "dri2.h"
43
44 /**
45 * DRI2 flush extension.
46 */
47 static void
48 dri2_flush_drawable(__DRIdrawable *draw)
49 {
50 }
51
52 static void
53 dri2_invalidate_drawable(__DRIdrawable *dPriv)
54 {
55 struct dri_drawable *drawable = dri_drawable(dPriv);
56 struct dri_context *ctx = dri_context(dPriv->driContextPriv);
57
58 dri2InvalidateDrawable(dPriv);
59 drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
60
61 if (ctx)
62 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
63 }
64
65 static const __DRI2flushExtension dri2FlushExtension = {
66 { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
67 dri2_flush_drawable,
68 dri2_invalidate_drawable,
69 };
70
71 /**
72 * These are used for GLX_EXT_texture_from_pixmap
73 */
74 static void
75 dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
76 GLint format, __DRIdrawable *dPriv)
77 {
78 struct dri_context *ctx = dri_context(pDRICtx);
79 struct dri_drawable *drawable = dri_drawable(dPriv);
80 struct pipe_texture *pt;
81
82 dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT);
83
84 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
85
86 if (pt) {
87 ctx->st->teximage(ctx->st,
88 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
89 0, drawable->stvis.color_format, pt, FALSE);
90 }
91 }
92
93 static void
94 dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
95 __DRIdrawable *dPriv)
96 {
97 dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
98 }
99
100 static const __DRItexBufferExtension dri2TexBufferExtension = {
101 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
102 dri2_set_tex_buffer,
103 dri2_set_tex_buffer2,
104 };
105
106 /**
107 * Get the format of an attachment.
108 */
109 static INLINE enum pipe_format
110 dri2_drawable_get_format(struct dri_drawable *drawable,
111 enum st_attachment_type statt)
112 {
113 enum pipe_format format;
114
115 switch (statt) {
116 case ST_ATTACHMENT_FRONT_LEFT:
117 case ST_ATTACHMENT_BACK_LEFT:
118 case ST_ATTACHMENT_FRONT_RIGHT:
119 case ST_ATTACHMENT_BACK_RIGHT:
120 format = drawable->stvis.color_format;
121 break;
122 case ST_ATTACHMENT_DEPTH_STENCIL:
123 format = drawable->stvis.depth_stencil_format;
124 break;
125 default:
126 format = PIPE_FORMAT_NONE;
127 break;
128 }
129
130 return format;
131 }
132
133 /**
134 * Retrieve __DRIbuffer from the DRI loader.
135 */
136 static __DRIbuffer *
137 dri2_drawable_get_buffers(struct dri_drawable *drawable,
138 const enum st_attachment_type *statts,
139 unsigned *count)
140 {
141 __DRIdrawable *dri_drawable = drawable->dPriv;
142 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
143 boolean with_format;
144 __DRIbuffer *buffers;
145 int num_buffers;
146 unsigned attachments[10];
147 unsigned num_attachments, i;
148
149 assert(loader);
150 with_format = dri_with_format(drawable->sPriv);
151
152 num_attachments = 0;
153
154 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
155 if (!with_format)
156 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
157
158 for (i = 0; i < *count; i++) {
159 enum pipe_format format;
160 int att, bpp;
161
162 format = dri2_drawable_get_format(drawable, statts[i]);
163 if (format == PIPE_FORMAT_NONE)
164 continue;
165
166 switch (statts[i]) {
167 case ST_ATTACHMENT_FRONT_LEFT:
168 /* already added */
169 if (!with_format)
170 continue;
171 att = __DRI_BUFFER_FRONT_LEFT;
172 break;
173 case ST_ATTACHMENT_BACK_LEFT:
174 att = __DRI_BUFFER_BACK_LEFT;
175 break;
176 case ST_ATTACHMENT_FRONT_RIGHT:
177 att = __DRI_BUFFER_FRONT_RIGHT;
178 break;
179 case ST_ATTACHMENT_BACK_RIGHT:
180 att = __DRI_BUFFER_BACK_RIGHT;
181 break;
182 case ST_ATTACHMENT_DEPTH_STENCIL:
183 att = __DRI_BUFFER_DEPTH_STENCIL;
184 break;
185 default:
186 att = -1;
187 break;
188 }
189
190 bpp = util_format_get_blocksizebits(format);
191
192 if (att >= 0) {
193 attachments[num_attachments++] = att;
194 if (with_format) {
195 attachments[num_attachments++] = bpp;
196 }
197 }
198 }
199
200 if (with_format) {
201 num_attachments /= 2;
202 buffers = loader->getBuffersWithFormat(dri_drawable,
203 &dri_drawable->w, &dri_drawable->h,
204 attachments, num_attachments,
205 &num_buffers, dri_drawable->loaderPrivate);
206 }
207 else {
208 buffers = loader->getBuffers(dri_drawable,
209 &dri_drawable->w, &dri_drawable->h,
210 attachments, num_attachments,
211 &num_buffers, dri_drawable->loaderPrivate);
212 }
213
214 if (buffers) {
215 /* set one cliprect to cover the whole dri_drawable */
216 dri_drawable->x = 0;
217 dri_drawable->y = 0;
218 dri_drawable->backX = 0;
219 dri_drawable->backY = 0;
220 dri_drawable->numClipRects = 1;
221 dri_drawable->pClipRects[0].x1 = 0;
222 dri_drawable->pClipRects[0].y1 = 0;
223 dri_drawable->pClipRects[0].x2 = dri_drawable->w;
224 dri_drawable->pClipRects[0].y2 = dri_drawable->h;
225 dri_drawable->numBackClipRects = 1;
226 dri_drawable->pBackClipRects[0].x1 = 0;
227 dri_drawable->pBackClipRects[0].y1 = 0;
228 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
229 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
230
231 *count = num_buffers;
232 }
233
234 return buffers;
235 }
236
237 /**
238 * Process __DRIbuffer and convert them into pipe_textures.
239 */
240 static void
241 dri2_drawable_process_buffers(struct dri_drawable *drawable,
242 __DRIbuffer *buffers, unsigned count)
243 {
244 struct dri_screen *screen = dri_screen(drawable->sPriv);
245 __DRIdrawable *dri_drawable = drawable->dPriv;
246 struct pipe_texture templ;
247 struct winsys_handle whandle;
248 boolean have_depth = FALSE;
249 unsigned i;
250
251 if (drawable->old_num == count &&
252 drawable->old_w == dri_drawable->w &&
253 drawable->old_h == dri_drawable->h &&
254 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
255 return;
256
257 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
258 pipe_texture_reference(&drawable->textures[i], NULL);
259
260 memset(&templ, 0, sizeof(templ));
261 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
262 templ.target = PIPE_TEXTURE_2D;
263 templ.last_level = 0;
264 templ.width0 = dri_drawable->w;
265 templ.height0 = dri_drawable->h;
266 templ.depth0 = 1;
267
268 memset(&whandle, 0, sizeof(whandle));
269
270 for (i = 0; i < count; i++) {
271 __DRIbuffer *buf = &buffers[i];
272 enum st_attachment_type statt;
273 enum pipe_format format;
274
275 switch (buf->attachment) {
276 case __DRI_BUFFER_FRONT_LEFT:
277 if (!screen->auto_fake_front) {
278 statt = ST_ATTACHMENT_INVALID;
279 break;
280 }
281 /* fallthrough */
282 case __DRI_BUFFER_FAKE_FRONT_LEFT:
283 statt = ST_ATTACHMENT_FRONT_LEFT;
284 break;
285 case __DRI_BUFFER_BACK_LEFT:
286 statt = ST_ATTACHMENT_BACK_LEFT;
287 break;
288 case __DRI_BUFFER_DEPTH:
289 case __DRI_BUFFER_DEPTH_STENCIL:
290 case __DRI_BUFFER_STENCIL:
291 /* use only the first depth/stencil buffer */
292 if (!have_depth) {
293 have_depth = TRUE;
294 statt = ST_ATTACHMENT_DEPTH_STENCIL;
295 }
296 else {
297 statt = ST_ATTACHMENT_INVALID;
298 }
299 break;
300 default:
301 statt = ST_ATTACHMENT_INVALID;
302 break;
303 }
304
305 format = dri2_drawable_get_format(drawable, statt);
306 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
307 continue;
308
309 templ.format = format;
310 whandle.handle = buf->name;
311 whandle.stride = buf->pitch;
312
313 drawable->textures[statt] =
314 screen->pipe_screen->texture_from_handle(screen->pipe_screen,
315 &templ, &whandle);
316 }
317
318 drawable->old_num = count;
319 drawable->old_w = dri_drawable->w;
320 drawable->old_h = dri_drawable->h;
321 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
322 }
323
324 /*
325 * Backend functions for st_framebuffer interface.
326 */
327
328 void
329 dri2_allocate_textures(struct dri_drawable *drawable,
330 const enum st_attachment_type *statts,
331 unsigned count)
332 {
333 __DRIbuffer *buffers;
334 unsigned num_buffers = count;
335
336 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
337 dri2_drawable_process_buffers(drawable, buffers, num_buffers);
338 }
339
340 void
341 dri2_flush_frontbuffer(struct dri_drawable *drawable,
342 enum st_attachment_type statt)
343 {
344 __DRIdrawable *dri_drawable = drawable->dPriv;
345 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
346
347 if (loader->flushFrontBuffer == NULL)
348 return;
349
350 if (statt == ST_ATTACHMENT_FRONT_LEFT) {
351 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
352 }
353 }
354
355 /*
356 * Backend function init_screen.
357 */
358
359 static const __DRIextension *dri_screen_extensions[] = {
360 &driReadDrawableExtension,
361 &driCopySubBufferExtension.base,
362 &driSwapControlExtension.base,
363 &driFrameTrackingExtension.base,
364 &driMediaStreamCounterExtension.base,
365 &dri2TexBufferExtension.base,
366 &dri2FlushExtension.base,
367 NULL
368 };
369
370 /**
371 * This is the driver specific part of the createNewScreen entry point.
372 *
373 * Returns the __GLcontextModes supported by this driver.
374 */
375 const __DRIconfig **
376 dri2_init_screen(__DRIscreen * sPriv)
377 {
378 struct dri_screen *screen;
379 struct drm_create_screen_arg arg;
380
381 screen = CALLOC_STRUCT(dri_screen);
382 if (!screen)
383 return NULL;
384
385 screen->api = drm_api_create();
386 screen->sPriv = sPriv;
387 screen->fd = sPriv->fd;
388 sPriv->private = (void *)screen;
389 sPriv->extensions = dri_screen_extensions;
390 arg.mode = DRM_CREATE_NORMAL;
391
392 screen->pipe_screen = screen->api->create_screen(screen->api, screen->fd, &arg);
393 if (!screen->pipe_screen) {
394 debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__);
395 goto fail;
396 }
397
398 screen->smapi = dri_create_st_manager(screen);
399 if (!screen->smapi)
400 goto fail;
401
402 driParseOptionInfo(&screen->optionCache,
403 __driConfigOptions, __driNConfigOptions);
404
405 screen->auto_fake_front = dri_with_format(sPriv);
406
407 return dri_fill_in_modes(screen, 32);
408 fail:
409 dri_destroy_screen(sPriv);
410 return NULL;
411 }
412
413 /* This is the table of extensions that the loader will dlsym() for. */
414 PUBLIC const __DRIextension *__driDriverExtensions[] = {
415 &driCoreExtension.base,
416 &driLegacyExtension.base,
417 &driDRI2Extension.base,
418 NULL
419 };
420
421 /* vim: set sw=3 ts=8 sts=3 expandtab: */