unfinished SOLO driver for TDFX
[mesa.git] / src / mesa / drivers / dri / tdfx / server / tdfx_dri.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
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
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /* Authors:
26 * Keith Whitwell
27 * Daniel Borca
28 */
29
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36
37 #include "driver.h"
38 #include "drm.h"
39 #include "imports.h"
40
41 #include "dri_util.h"
42
43 #include "tdfx_context.h"
44 #include "tdfx_dri.h"
45 #include "xf86drm.h"
46
47
48 #define TILE_WIDTH 128
49 #define TILE_HEIGHT 32
50
51 #define CMDFIFO_PAGES 64
52
53
54 static int
55 calcBufferStride (int xres, int tiled, int cpp)
56 {
57 int strideInTiles;
58
59 if (tiled) {
60 /* Calculate tile width stuff */
61 strideInTiles = (xres+TILE_WIDTH-1)/TILE_WIDTH;
62
63 return strideInTiles*cpp*TILE_WIDTH;
64 } else {
65 return xres*cpp;
66 }
67 } /* calcBufferStride */
68
69
70 static int
71 calcBufferHeightInTiles (int yres)
72 {
73 int heightInTiles; /* Height of buffer in tiles */
74
75 /* Calculate tile height stuff */
76 heightInTiles = yres >> 5;
77
78 if (yres & (TILE_HEIGHT - 1))
79 heightInTiles++;
80
81 return heightInTiles;
82
83 } /* calcBufferHeightInTiles */
84
85
86 static int
87 calcBufferSize (int xres, int yres, int tiled, int cpp)
88 {
89 int stride, height, bufSize;
90
91 if (tiled) {
92 stride = calcBufferStride(xres, tiled, cpp);
93 height = TILE_HEIGHT * calcBufferHeightInTiles(yres);
94 } else {
95 stride = xres*cpp;
96 height = yres;
97 }
98
99 bufSize = stride * height;
100
101 return bufSize;
102 } /* calcBufferSize */
103
104
105 static void allocateMemory (const DRIDriverContext *ctx, TDFXDRIPtr pTDFX)
106 {
107 int memRemaining, fifoSize, screenSizeInTiles;
108 int fbSize;
109 char *str;
110 int pixmapCacheLinesMin;
111 int cursorOffset, cursorSize;
112
113 pTDFX->stride = calcBufferStride(pTDFX->width, !0, pTDFX->cpp);
114
115 /* enough to do DVD */
116 pixmapCacheLinesMin = ((720*480*pTDFX->cpp) +
117 pTDFX->stride - 1)/pTDFX->stride;
118
119 if (pTDFX->deviceID > PCI_CHIP_VOODOO3) {
120 if ((pixmapCacheLinesMin + pTDFX->height) > 4095)
121 pixmapCacheLinesMin = 4095 - pTDFX->height;
122 } else {
123 if ((pixmapCacheLinesMin + pTDFX->height) > 2047)
124 pixmapCacheLinesMin = 2047 - pTDFX->height;
125 }
126
127 if (pTDFX->cpp!=3) {
128 screenSizeInTiles=calcBufferSize(pTDFX->width, pTDFX->height,
129 !0, pTDFX->cpp);
130 }
131 else {
132 /* cpp==3 needs to bump up to 4 */
133 screenSizeInTiles=calcBufferSize(pTDFX->width, pTDFX->height,
134 !0, 4);
135 }
136
137 /*
138 * Layout is:
139 * cursor, fifo, fb, tex, bb, db
140 */
141
142 fbSize = (pTDFX->height + pixmapCacheLinesMin) * pTDFX->stride;
143
144 memRemaining=(pTDFX->mem - 1) &~ 0xFFF;
145 /* Note that a page is 4096 bytes, and a */
146 /* tile is 32 x 128 = 4096 bytes. So, */
147 /* page and tile boundaries are the same */
148 /* Place the depth offset first, forcing */
149 /* it to be on an *odd* page boundary. */
150 pTDFX->depthOffset = (memRemaining - screenSizeInTiles) &~ 0xFFF;
151 if ((pTDFX->depthOffset & (0x1 << 12)) == 0) {
152 pTDFX->depthOffset -= (0x1 << 12);
153 }
154 /* Now, place the back buffer, forcing it */
155 /* to be on an *even* page boundary. */
156 pTDFX->backOffset = (pTDFX->depthOffset - screenSizeInTiles) &~ 0xFFF;
157 if (pTDFX->backOffset & (0x1 << 12)) {
158 pTDFX->backOffset -= (0x1 << 12);
159 }
160 /* Give the cmd fifo at least */
161 /* CMDFIFO_PAGES pages, but no more than */
162 /* 64. NOTE: Don't go higher than 64, as */
163 /* there is suspect code in Glide3 ! */
164 fifoSize = ((64 <= CMDFIFO_PAGES) ? 64 : CMDFIFO_PAGES) << 12;
165
166 /* We give 4096 bytes to the cursor */
167 cursorSize = 0/*4096*/;
168 cursorOffset = 0;
169
170 pTDFX->fifoOffset = cursorOffset + cursorSize;
171 pTDFX->fifoSize = fifoSize;
172 /* Now, place the front buffer, forcing */
173 /* it to be on a page boundary too, just */
174 /* for giggles. */
175 pTDFX->fbOffset = pTDFX->fifoOffset + pTDFX->fifoSize;
176 pTDFX->textureOffset = pTDFX->fbOffset + fbSize;
177 if (pTDFX->depthOffset <= pTDFX->textureOffset ||
178 pTDFX->backOffset <= pTDFX->textureOffset) {
179 /*
180 * pTDFX->textureSize < 0 means that the DRI is disabled. pTDFX->backOffset
181 * is used to calculate the maximum amount of memory available for
182 * 2D offscreen use. With DRI disabled, set this to the top of memory.
183 */
184
185 pTDFX->textureSize = -1;
186 pTDFX->backOffset = pTDFX->mem;
187 pTDFX->depthOffset = -1;
188 fprintf(stderr,
189 "Not enough video memory available for textures and depth buffer\n"
190 "\tand/or back buffer. Disabling DRI. To use DRI try lower\n"
191 "\tresolution modes and/or a smaller virtual screen size\n");
192 } else {
193 pTDFX->textureSize = pTDFX->backOffset - pTDFX->textureOffset;
194 }
195 }
196
197
198 static int createScreen (DRIDriverContext *ctx, TDFXDRIPtr pTDFX)
199 {
200 int err;
201
202 {
203 int width_bytes = (ctx->shared.virtualWidth * ctx->cpp);
204 int maxy = ctx->shared.fbSize / width_bytes;
205
206
207 if (maxy <= ctx->shared.virtualHeight * 3) {
208 fprintf(stderr,
209 "Static buffer allocation failed -- "
210 "need at least %d kB video memory (have %d kB)\n",
211 (ctx->shared.virtualWidth * ctx->shared.virtualHeight *
212 ctx->cpp * 3 + 1023) / 1024,
213 ctx->shared.fbSize / 1024);
214 return 0;
215 }
216 }
217
218 ctx->shared.SAREASize = SAREA_MAX;
219 pTDFX->regsSize = ctx->MMIOSize;
220
221 /* Note that drmOpen will try to load the kernel module, if needed. */
222 ctx->drmFD = drmOpen("tdfx", NULL );
223 if (ctx->drmFD < 0) {
224 fprintf(stderr, "[drm] drmOpen failed\n");
225 return 0;
226 }
227
228 if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) {
229 fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
230 ctx->drmFD, ctx->pciBusID, strerror(-err));
231 return 0;
232 }
233
234 if (drmAddMap( ctx->drmFD,
235 0,
236 ctx->shared.SAREASize,
237 DRM_SHM,
238 DRM_CONTAINS_LOCK,
239 &ctx->shared.hSAREA) < 0)
240 {
241 fprintf(stderr, "[drm] drmAddMap failed\n");
242 return 0;
243 }
244 fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
245 ctx->shared.SAREASize, ctx->shared.hSAREA);
246
247 if (drmMap( ctx->drmFD,
248 ctx->shared.hSAREA,
249 ctx->shared.SAREASize,
250 (drmAddressPtr)(&ctx->pSAREA)) < 0)
251 {
252 fprintf(stderr, "[drm] drmMap failed\n");
253 return 0;
254 }
255 memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
256 fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
257 ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
258
259 /* Need to AddMap the framebuffer and mmio regions here:
260 */
261 if (drmAddMap( ctx->drmFD,
262 (drmHandle)ctx->FBStart,
263 ctx->FBSize,
264 DRM_FRAME_BUFFER,
265 #ifndef _EMBEDDED
266 0,
267 #else
268 DRM_READ_ONLY,
269 #endif
270 &ctx->shared.hFrameBuffer) < 0)
271 {
272 fprintf(stderr, "[drm] drmAddMap framebuffer failed\n");
273 return 0;
274 }
275
276 fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n",
277 ctx->shared.hFrameBuffer);
278
279
280 if (drmAddMap(ctx->drmFD,
281 ctx->MMIOStart,
282 ctx->MMIOSize,
283 DRM_REGISTERS,
284 DRM_READ_ONLY,
285 &pTDFX->regs) < 0) {
286 fprintf(stderr, "[drm] drmAddMap mmio failed\n");
287 return 0;
288 }
289 fprintf(stderr,
290 "[drm] register handle = 0x%08lx\n", pTDFX->regs);
291
292
293 /* Create a 'server' context so we can grab the lock for
294 * initialization ioctls.
295 */
296 if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
297 fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
298 return 0;
299 }
300
301 DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);
302
303 /* Initialize the kernel data structures */
304
305 /* Initialize kernel gart memory manager */
306 allocateMemory(ctx, pTDFX);
307
308 /* Initialize the SAREA private data structure */
309
310
311 /* Quick hack to clear the front & back buffers. Could also use
312 * the clear ioctl to do this, but would need to setup hw state
313 * first.
314 */
315
316
317 /* This is the struct passed to tdfx_dri.so for its initialization */
318 ctx->driverClientMsg = malloc(sizeof(TDFXDRIRec));
319 ctx->driverClientMsgSize = sizeof(TDFXDRIRec);
320 memcpy(ctx->driverClientMsg, pTDFX, ctx->driverClientMsgSize);
321 pTDFX = (TDFXDRIPtr)ctx->driverClientMsg;
322
323 /* Don't release the lock now - let the VT switch handler do it. */
324
325 return 1;
326 }
327
328
329 /**
330 * \brief Establish the set of modes available for the display.
331 *
332 * \param ctx display handle.
333 * \param numModes will receive the number of supported modes.
334 * \param modes will point to the list of supported modes.
335 *
336 * \return one on success, or zero on failure.
337 *
338 * Allocates a single visual and fills it with information according to the
339 * display bit depth. Supports only 16 and 32 bpp bit depths, aborting
340 * otherwise.
341 */
342 const __GLcontextModes __glModes[] = {
343
344 /* 32 bit, RGBA Depth=24 Stencil=8 */
345 {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
346 .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_TRUE,
347 .redBits = 8, .greenBits = 8, .blueBits = 8, .alphaBits = 8,
348 .redMask = 0xff0000, .greenMask = 0xff00, .blueMask = 0xff, .alphaMask = 0xff000000,
349 .rgbBits = 32, .indexBits = 0,
350 .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
351 .depthBits = 24, .stencilBits = 8,
352 .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
353
354 /* 16 bit, RGB Depth=16 */
355 {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
356 .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_FALSE,
357 .redBits = 5, .greenBits = 6, .blueBits = 5, .alphaBits = 0,
358 .redMask = 0xf800, .greenMask = 0x07e0, .blueMask = 0x001f, .alphaMask = 0x0,
359 .rgbBits = 16, .indexBits = 0,
360 .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
361 .depthBits = 16, .stencilBits = 0,
362 .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
363 };
364 static int tdfxInitContextModes( const DRIDriverContext *ctx,
365 int *numModes, const __GLcontextModes **modes)
366 {
367 int n = sizeof(__glModes)/sizeof(__glModes[0]);
368 const __GLcontextModes *m = &__glModes[0];
369
370 if (ctx->chipset < PCI_CHIP_VOODOO4) {
371 n /= 2;
372 m += n;
373 }
374
375 *numModes = n;
376 *modes = m;
377
378 return 1;
379 }
380
381
382 /**
383 * \brief Validate the fbdev mode.
384 *
385 * \param ctx display handle.
386 *
387 * \return one on success, or zero on failure.
388 *
389 * Saves some registers and returns 1.
390 *
391 * \sa tdfxValidateMode().
392 */
393 static int tdfxValidateMode( const DRIDriverContext *ctx )
394 {
395 return 1;
396 }
397
398
399 /**
400 * \brief Examine mode returned by fbdev.
401 *
402 * \param ctx display handle.
403 *
404 * \return one on success, or zero on failure.
405 *
406 * Restores registers that fbdev has clobbered and returns 1.
407 *
408 * \sa tdfxValidateMode().
409 */
410 static int tdfxPostValidateMode( const DRIDriverContext *ctx )
411 {
412 return 1;
413 }
414
415
416 /**
417 * \brief Initialize the framebuffer device mode
418 *
419 * \param ctx display handle.
420 *
421 * \return one on success, or zero on failure.
422 *
423 * Before exiting clears the framebuffer memory accessing it directly.
424 */
425 static int tdfxInitFBDev( DRIDriverContext *ctx )
426 {
427 TDFXDRIPtr pTDFX = calloc(1, sizeof(TDFXDRIRec));
428
429 {
430 int dummy = ctx->shared.virtualWidth;
431
432 switch (ctx->bpp / 8) {
433 case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break;
434 case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break;
435 case 3:
436 case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break;
437 }
438
439 ctx->shared.virtualWidth = dummy;
440 }
441
442 ctx->driverPrivate = (void *)pTDFX;
443
444 pTDFX->deviceID = ctx->chipset;
445 pTDFX->width = ctx->shared.virtualWidth;
446 pTDFX->height = ctx->shared.virtualHeight;
447 pTDFX->cpp = ctx->cpp;
448 pTDFX->mem = ctx->FBSize; /* ->shared.fbSize? mem probe? */
449 pTDFX->sarea_priv_offset = sizeof(drm_sarea_t);
450
451 if (!createScreen(ctx, pTDFX))
452 return 0;
453
454 return 1;
455 }
456
457
458 /**
459 * \brief The screen is being closed, so clean up any state and free any
460 * resources used by the DRI.
461 *
462 * \param ctx display handle.
463 *
464 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
465 * private data.
466 */
467 static void tdfxHaltFBDev( DRIDriverContext *ctx )
468 {
469 drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
470 drmClose(ctx->drmFD);
471
472 if (ctx->driverPrivate) {
473 free(ctx->driverPrivate);
474 ctx->driverPrivate = 0;
475 }
476 }
477
478
479 /**
480 * \brief Shutdown the drawing engine.
481 *
482 * \param ctx display handle
483 *
484 * Turns off the 3D engine & restores the graphics card
485 * to a state that fbdev understands.
486 */
487 static int tdfxEngineShutdown( const DRIDriverContext *ctx )
488 {
489 fprintf(stderr, "%s: not implemented\n", __FUNCTION__);
490 return 1;
491 }
492
493
494 /**
495 * \brief Restore the drawing engine.
496 *
497 * \param ctx display handle
498 *
499 * Resets the graphics card and sets initial values for several registers of
500 * the card's drawing engine.
501 *
502 * Turns on 3dfx
503 */
504 static int tdfxEngineRestore( const DRIDriverContext *ctx )
505 {
506 fprintf(stderr, "%s: not implemented\n", __FUNCTION__);
507 return 1;
508 }
509
510
511 /**
512 * \brief Exported driver interface for Mini GLX.
513 *
514 * \sa DRIDriverRec.
515 */
516 struct DRIDriverRec __driDriver = {
517 tdfxInitContextModes,
518 tdfxValidateMode,
519 tdfxPostValidateMode,
520 tdfxInitFBDev,
521 tdfxHaltFBDev,
522 tdfxEngineShutdown,
523 tdfxEngineRestore,
524 0
525 };