Refactor and fix core vblank support
[mesa.git] / src / mesa / drivers / dri / i810 / i810screen.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27 /* $XFree86: xc/lib/GL/mesa/src/drv/i810/i810screen.c,v 1.2 2002/10/30 12:51:33 alanh Exp $ */
28
29 /*
30 * Authors:
31 * Keith Whitwell <keith@tungstengraphics.com>
32 *
33 */
34
35
36 #include "glheader.h"
37 #include "imports.h"
38 #include "context.h"
39 #include "framebuffer.h"
40 #include "fbobject.h"
41 #include "matrix.h"
42 #include "renderbuffer.h"
43 #include "simple_list.h"
44 #include "utils.h"
45
46 #include "i810screen.h"
47 #include "i810_dri.h"
48
49 #include "i810state.h"
50 #include "i810tex.h"
51 #include "i810span.h"
52 #include "i810tris.h"
53 #include "i810ioctl.h"
54
55 #include "GL/internal/dri_interface.h"
56
57 extern const struct dri_extension card_extensions[];
58
59 static __GLcontextModes *fill_in_modes( __GLcontextModes *modes,
60 unsigned pixel_bits,
61 unsigned depth_bits,
62 unsigned stencil_bits,
63 const GLenum * db_modes,
64 unsigned num_db_modes,
65 int visType )
66 {
67 static const u_int8_t bits[1][4] = {
68 { 5, 6, 5, 0 }
69 };
70
71 static const u_int32_t masks[1][4] = {
72 { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }
73 };
74
75 unsigned i;
76 unsigned j;
77 const unsigned index = 0;
78
79 for ( i = 0 ; i < num_db_modes ; i++ ) {
80 for ( j = 0 ; j < 2 ; j++ ) {
81
82 modes->redBits = bits[index][0];
83 modes->greenBits = bits[index][1];
84 modes->blueBits = bits[index][2];
85 modes->alphaBits = bits[index][3];
86 modes->redMask = masks[index][0];
87 modes->greenMask = masks[index][1];
88 modes->blueMask = masks[index][2];
89 modes->alphaMask = masks[index][3];
90 modes->rgbBits = modes->redBits + modes->greenBits
91 + modes->blueBits + modes->alphaBits;
92
93 modes->accumRedBits = 16 * j;
94 modes->accumGreenBits = 16 * j;
95 modes->accumBlueBits = 16 * j;
96 modes->accumAlphaBits = (masks[index][3] != 0) ? 16 * j : 0;
97 modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG;
98
99 modes->stencilBits = stencil_bits;
100 modes->depthBits = depth_bits;
101
102 modes->visualType = visType;
103 modes->renderType = GLX_RGBA_BIT;
104 modes->drawableType = GLX_WINDOW_BIT;
105 modes->rgbMode = GL_TRUE;
106
107 if ( db_modes[i] == GLX_NONE ) {
108 modes->doubleBufferMode = GL_FALSE;
109 }
110 else {
111 modes->doubleBufferMode = GL_TRUE;
112 modes->swapMethod = db_modes[i];
113 }
114
115 modes = modes->next;
116 }
117 }
118
119 return modes;
120
121 }
122
123
124 static __GLcontextModes *
125 i810FillInModes( unsigned pixel_bits, unsigned depth_bits,
126 unsigned stencil_bits, GLboolean have_back_buffer )
127 { __GLcontextModes * modes;
128 __GLcontextModes * m;
129 unsigned num_modes;
130 unsigned depth_buffer_factor;
131 unsigned back_buffer_factor;
132 unsigned i;
133
134 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
135 * enough to add support. Basically, if a context is created with an
136 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
137 * will never be used.
138 */
139 static const GLenum back_buffer_modes[] = {
140 GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
141 };
142
143 int depth_buffer_modes[2][2];
144
145
146 depth_buffer_modes[0][0] = depth_bits;
147 depth_buffer_modes[1][0] = depth_bits;
148
149 /* Just like with the accumulation buffer, always provide some modes
150 * with a stencil buffer. It will be a sw fallback, but some apps won't
151 * care about that.
152 */
153 depth_buffer_modes[0][1] = 0;
154 depth_buffer_modes[1][1] = (stencil_bits == 0) ? 8 : stencil_bits;
155
156 depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
157 back_buffer_factor = (have_back_buffer) ? 2 : 1;
158
159 num_modes = depth_buffer_factor * back_buffer_factor * 4;
160
161 modes = (*dri_interface->createContextModes)( num_modes, sizeof( __GLcontextModes ) );
162 m = modes;
163 for ( i = 0 ; i < depth_buffer_factor ; i++ ) {
164 m = fill_in_modes( m, pixel_bits,
165 depth_buffer_modes[i][0], depth_buffer_modes[i][1],
166 back_buffer_modes, back_buffer_factor,
167 GLX_TRUE_COLOR );
168 }
169
170 for ( i = 0 ; i < depth_buffer_factor ; i++ ) {
171 m = fill_in_modes( m, pixel_bits,
172 depth_buffer_modes[i][0], depth_buffer_modes[i][1],
173 back_buffer_modes, back_buffer_factor,
174 GLX_DIRECT_COLOR );
175 }
176
177 /* Mark the visual as slow if there are "fake" stencil bits.
178 */
179 for ( m = modes ; m != NULL ; m = m->next ) {
180 if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
181 m->visualRating = GLX_SLOW_CONFIG;
182 }
183 }
184
185 return modes;
186
187 }
188
189
190 /* static int i810_malloc_proxy_buf(drmBufMapPtr buffers) */
191 /* { */
192 /* char *buffer; */
193 /* drmBufPtr buf; */
194 /* int i; */
195
196 /* buffer = CALLOC(I810_DMA_BUF_SZ); */
197 /* if(buffer == NULL) return -1; */
198 /* for(i = 0; i < I810_DMA_BUF_NR; i++) { */
199 /* buf = &(buffers->list[i]); */
200 /* buf->address = (drmAddress)buffer; */
201 /* } */
202 /* return 0; */
203 /* } */
204
205 static drmBufMapPtr i810_create_empty_buffers(void)
206 {
207 drmBufMapPtr retval;
208
209 retval = (drmBufMapPtr)ALIGN_MALLOC(sizeof(drmBufMap), 32);
210 if(retval == NULL) return NULL;
211 memset(retval, 0, sizeof(drmBufMap));
212 retval->list = (drmBufPtr)ALIGN_MALLOC(sizeof(drmBuf) * I810_DMA_BUF_NR, 32);
213 if(retval->list == NULL) {
214 ALIGN_FREE(retval);
215 return NULL;
216 }
217 memset(retval->list, 0, sizeof(drmBuf) * I810_DMA_BUF_NR);
218 return retval;
219 }
220
221
222 static GLboolean
223 i810InitDriver(__DRIscreenPrivate *sPriv)
224 {
225 i810ScreenPrivate *i810Screen;
226 I810DRIPtr gDRIPriv = (I810DRIPtr)sPriv->pDevPriv;
227
228 if (sPriv->devPrivSize != sizeof(I810DRIRec)) {
229 fprintf(stderr,"\nERROR! sizeof(I810DRIRec) does not match passed size from device driver\n");
230 return GL_FALSE;
231 }
232
233 /* Allocate the private area */
234 i810Screen = (i810ScreenPrivate *)CALLOC(sizeof(i810ScreenPrivate));
235 if (!i810Screen) {
236 __driUtilMessage("i810InitDriver: alloc i810ScreenPrivate struct failed");
237 return GL_FALSE;
238 }
239
240 i810Screen->driScrnPriv = sPriv;
241 sPriv->private = (void *)i810Screen;
242
243 i810Screen->deviceID=gDRIPriv->deviceID;
244 i810Screen->width=gDRIPriv->width;
245 i810Screen->height=gDRIPriv->height;
246 i810Screen->mem=gDRIPriv->mem;
247 i810Screen->cpp=gDRIPriv->cpp;
248 i810Screen->fbStride=gDRIPriv->fbStride;
249 i810Screen->fbOffset=gDRIPriv->fbOffset;
250
251 if (gDRIPriv->bitsPerPixel == 15)
252 i810Screen->fbFormat = DV_PF_555;
253 else
254 i810Screen->fbFormat = DV_PF_565;
255
256 i810Screen->backOffset=gDRIPriv->backOffset;
257 i810Screen->depthOffset=gDRIPriv->depthOffset;
258 i810Screen->backPitch = gDRIPriv->auxPitch;
259 i810Screen->backPitchBits = gDRIPriv->auxPitchBits;
260 i810Screen->textureOffset=gDRIPriv->textureOffset;
261 i810Screen->textureSize=gDRIPriv->textureSize;
262 i810Screen->logTextureGranularity = gDRIPriv->logTextureGranularity;
263
264 i810Screen->bufs = i810_create_empty_buffers();
265 if (i810Screen->bufs == NULL) {
266 __driUtilMessage("i810InitDriver: i810_create_empty_buffers() failed");
267 FREE(i810Screen);
268 return GL_FALSE;
269 }
270
271 i810Screen->back.handle = gDRIPriv->backbuffer;
272 i810Screen->back.size = gDRIPriv->backbufferSize;
273
274 if (drmMap(sPriv->fd,
275 i810Screen->back.handle,
276 i810Screen->back.size,
277 (drmAddress *)&i810Screen->back.map) != 0) {
278 FREE(i810Screen);
279 sPriv->private = NULL;
280 __driUtilMessage("i810InitDriver: drmMap failed");
281 return GL_FALSE;
282 }
283
284 i810Screen->depth.handle = gDRIPriv->depthbuffer;
285 i810Screen->depth.size = gDRIPriv->depthbufferSize;
286
287 if (drmMap(sPriv->fd,
288 i810Screen->depth.handle,
289 i810Screen->depth.size,
290 (drmAddress *)&i810Screen->depth.map) != 0) {
291 drmUnmap(i810Screen->back.map, i810Screen->back.size);
292 FREE(i810Screen);
293 sPriv->private = NULL;
294 __driUtilMessage("i810InitDriver: drmMap (2) failed");
295 return GL_FALSE;
296 }
297
298 i810Screen->tex.handle = gDRIPriv->textures;
299 i810Screen->tex.size = gDRIPriv->textureSize;
300
301 if (drmMap(sPriv->fd,
302 i810Screen->tex.handle,
303 i810Screen->tex.size,
304 (drmAddress *)&i810Screen->tex.map) != 0) {
305 drmUnmap(i810Screen->back.map, i810Screen->back.size);
306 drmUnmap(i810Screen->depth.map, i810Screen->depth.size);
307 FREE(i810Screen);
308 sPriv->private = NULL;
309 __driUtilMessage("i810InitDriver: drmMap (3) failed");
310 return GL_FALSE;
311 }
312
313 i810Screen->sarea_priv_offset = gDRIPriv->sarea_priv_offset;
314
315 return GL_TRUE;
316 }
317
318 static void
319 i810DestroyScreen(__DRIscreenPrivate *sPriv)
320 {
321 i810ScreenPrivate *i810Screen = (i810ScreenPrivate *)sPriv->private;
322
323 /* Need to unmap all the bufs and maps here:
324 */
325 drmUnmap(i810Screen->back.map, i810Screen->back.size);
326 drmUnmap(i810Screen->depth.map, i810Screen->depth.size);
327 drmUnmap(i810Screen->tex.map, i810Screen->tex.size);
328
329 FREE(i810Screen);
330 sPriv->private = NULL;
331 }
332
333
334 /**
335 * Create a buffer which corresponds to the window.
336 */
337 static GLboolean
338 i810CreateBuffer( __DRIscreenPrivate *driScrnPriv,
339 __DRIdrawablePrivate *driDrawPriv,
340 const __GLcontextModes *mesaVis,
341 GLboolean isPixmap )
342 {
343 i810ScreenPrivate *screen = (i810ScreenPrivate *) driScrnPriv->private;
344
345 if (isPixmap) {
346 return GL_FALSE; /* not implemented */
347 }
348 else {
349 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
350
351 {
352 driRenderbuffer *frontRb
353 = driNewRenderbuffer(GL_RGBA,
354 driScrnPriv->pFB,
355 screen->cpp,
356 /*screen->frontOffset*/0, screen->backPitch,
357 driDrawPriv);
358 i810SetSpanFunctions(frontRb, mesaVis);
359 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
360 }
361
362 if (mesaVis->doubleBufferMode) {
363 driRenderbuffer *backRb
364 = driNewRenderbuffer(GL_RGBA,
365 screen->back.map,
366 screen->cpp,
367 screen->backOffset, screen->backPitch,
368 driDrawPriv);
369 i810SetSpanFunctions(backRb, mesaVis);
370 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
371 }
372
373 if (mesaVis->depthBits == 16) {
374 driRenderbuffer *depthRb
375 = driNewRenderbuffer(GL_DEPTH_COMPONENT16,
376 screen->depth.map,
377 screen->cpp,
378 screen->depthOffset, screen->backPitch,
379 driDrawPriv);
380 i810SetSpanFunctions(depthRb, mesaVis);
381 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
382 }
383
384 _mesa_add_soft_renderbuffers(fb,
385 GL_FALSE, /* color */
386 GL_FALSE, /* depth */
387 mesaVis->stencilBits > 0,
388 mesaVis->accumRedBits > 0,
389 GL_FALSE, /* alpha */
390 GL_FALSE /* aux */);
391 driDrawPriv->driverPrivate = (void *) fb;
392
393 return (driDrawPriv->driverPrivate != NULL);
394 }
395 }
396
397
398 static void
399 i810DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
400 {
401 _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
402 }
403
404
405 static const struct __DriverAPIRec i810API = {
406 .DestroyScreen = i810DestroyScreen,
407 .CreateContext = i810CreateContext,
408 .DestroyContext = i810DestroyContext,
409 .CreateBuffer = i810CreateBuffer,
410 .DestroyBuffer = i810DestroyBuffer,
411 .SwapBuffers = i810SwapBuffers,
412 .MakeCurrent = i810MakeCurrent,
413 .UnbindContext = i810UnbindContext,
414 .GetSwapInfo = NULL,
415 .GetMSC = NULL,
416 .GetDrawableMSC = NULL,
417 .WaitForMSC = NULL,
418 .WaitForSBC = NULL,
419 .SwapBuffersMSC = NULL
420 };
421
422
423 /**
424 * This is the driver specific part of the createNewScreen entry point.
425 *
426 * \todo maybe fold this into intelInitDriver
427 *
428 * \return the __GLcontextModes supported by this driver
429 */
430 PUBLIC __GLcontextModes *__driDriverInitScreen(__DRIscreenPrivate *psp)
431 {
432 static const __DRIversion ddx_expected = { 1, 0, 0 };
433 static const __DRIversion dri_expected = { 4, 0, 0 };
434 static const __DRIversion drm_expected = { 1, 2, 0 };
435
436 if ( ! driCheckDriDdxDrmVersions2( "i810",
437 &psp->dri_version, & dri_expected,
438 &psp->ddx_version, & ddx_expected,
439 &psp->drm_version, & drm_expected ) ) {
440 return NULL;
441 }
442
443 psp->DriverAPI = i810API;
444 driInitExtensions( NULL, card_extensions, GL_TRUE );
445
446 if (!i810InitDriver(psp))
447 return NULL;
448
449 return i810FillInModes(16, 16, 0, 1);
450 }