362c8696e3aff374a658cc37485e9672eb99fd8f
[mesa.git] / src / mesa / drivers / dri / sis / sis_screen.c
1 /* $XFree86$ */
2 /**************************************************************************
3
4 Copyright 2003 Eric Anholt
5 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 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27 /*
28 * Authors:
29 * Eric Anholt <anholt@FreeBSD.org>
30 */
31
32 #include "dri_util.h"
33
34 #include "context.h"
35 #include "utils.h"
36 #include "imports.h"
37 #include "framebuffer.h"
38 #include "renderbuffer.h"
39
40 #include "sis_context.h"
41 #include "sis_dri.h"
42 #include "sis_lock.h"
43 #include "sis_span.h"
44
45 #include "xmlpool.h"
46
47 #include "GL/internal/dri_interface.h"
48
49 PUBLIC const char __driConfigOptions[] =
50 DRI_CONF_BEGIN
51 DRI_CONF_SECTION_DEBUG
52 DRI_CONF_OPT_BEGIN(agp_disable,bool,false)
53 DRI_CONF_DESC(en,"Disable AGP vertex dispatch")
54 DRI_CONF_OPT_END
55 DRI_CONF_OPT_BEGIN(fallback_force,bool,false)
56 DRI_CONF_DESC(en,"Force software fallback")
57 DRI_CONF_OPT_END
58 DRI_CONF_SECTION_END
59 DRI_CONF_END;
60 static const GLuint __driNConfigOptions = 2;
61
62 extern const struct dri_extension card_extensions[];
63
64 static __GLcontextModes *
65 sisFillInModes(int bpp)
66 {
67 __GLcontextModes *modes;
68 __GLcontextModes *m;
69 unsigned num_modes;
70 unsigned depth_buffer_factor;
71 unsigned back_buffer_factor;
72 GLenum fb_format;
73 GLenum fb_type;
74 static const GLenum back_buffer_modes[] = {
75 GLX_NONE, GLX_SWAP_UNDEFINED_OML
76 };
77 u_int8_t depth_bits_array[4];
78 u_int8_t stencil_bits_array[4];
79
80 depth_bits_array[0] = 0;
81 stencil_bits_array[0] = 0;
82 depth_bits_array[1] = 16;
83 stencil_bits_array[1] = 0;
84 depth_bits_array[2] = 24;
85 stencil_bits_array[2] = 8;
86 depth_bits_array[3] = 32;
87 stencil_bits_array[3] = 0;
88
89 depth_buffer_factor = 4;
90 back_buffer_factor = 2;
91
92 /* Last 4 is for GLX_TRUE_COLOR & GLX_DIRECT_COLOR, with/without accum */
93 num_modes = depth_buffer_factor * back_buffer_factor * 4;
94
95 if (bpp == 16) {
96 fb_format = GL_RGB;
97 fb_type = GL_UNSIGNED_SHORT_5_6_5;
98 } else {
99 fb_format = GL_BGRA;
100 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
101 }
102
103 modes = (*dri_interface->createContextModes)(num_modes, sizeof(__GLcontextModes));
104 m = modes;
105 if (!driFillInModes(&m, fb_format, fb_type, depth_bits_array,
106 stencil_bits_array, depth_buffer_factor,
107 back_buffer_modes, back_buffer_factor,
108 GLX_TRUE_COLOR)) {
109 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, __LINE__);
110 return NULL;
111 }
112
113 if (!driFillInModes(&m, fb_format, fb_type, depth_bits_array,
114 stencil_bits_array, depth_buffer_factor,
115 back_buffer_modes, back_buffer_factor,
116 GLX_DIRECT_COLOR)) {
117 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, __LINE__);
118 return NULL;
119 }
120
121 return modes;
122 }
123
124
125 /* Create the device specific screen private data struct.
126 */
127 static sisScreenPtr
128 sisCreateScreen( __DRIscreenPrivate *sPriv )
129 {
130 sisScreenPtr sisScreen;
131 SISDRIPtr sisDRIPriv = (SISDRIPtr)sPriv->pDevPriv;
132
133 if (sPriv->devPrivSize != sizeof(SISDRIRec)) {
134 fprintf(stderr,"\nERROR! sizeof(SISDRIRec) does not match passed size from device driver\n");
135 return GL_FALSE;
136 }
137
138 /* Allocate the private area */
139 sisScreen = (sisScreenPtr)CALLOC( sizeof(*sisScreen) );
140 if ( sisScreen == NULL )
141 return NULL;
142
143 sisScreen->screenX = sisDRIPriv->width;
144 sisScreen->screenY = sisDRIPriv->height;
145 sisScreen->cpp = sisDRIPriv->bytesPerPixel;
146 sisScreen->deviceID = sisDRIPriv->deviceID;
147 sisScreen->AGPCmdBufOffset = sisDRIPriv->AGPCmdBufOffset;
148 sisScreen->AGPCmdBufSize = sisDRIPriv->AGPCmdBufSize;
149 sisScreen->sarea_priv_offset = sizeof(drm_sarea_t);
150
151 sisScreen->mmio.handle = sisDRIPriv->regs.handle;
152 sisScreen->mmio.size = sisDRIPriv->regs.size;
153 if ( drmMap( sPriv->fd, sisScreen->mmio.handle, sisScreen->mmio.size,
154 &sisScreen->mmio.map ) )
155 {
156 FREE( sisScreen );
157 return NULL;
158 }
159
160 if (sisDRIPriv->agp.size) {
161 sisScreen->agp.handle = sisDRIPriv->agp.handle;
162 sisScreen->agp.size = sisDRIPriv->agp.size;
163 if ( drmMap( sPriv->fd, sisScreen->agp.handle, sisScreen->agp.size,
164 &sisScreen->agp.map ) )
165 {
166 sisScreen->agp.size = 0;
167 }
168 }
169
170 sisScreen->driScreen = sPriv;
171
172 /* parse information in __driConfigOptions */
173 driParseOptionInfo(&sisScreen->optionCache,
174 __driConfigOptions, __driNConfigOptions);
175
176 return sisScreen;
177 }
178
179 /* Destroy the device specific screen private data struct.
180 */
181 static void
182 sisDestroyScreen( __DRIscreenPrivate *sPriv )
183 {
184 sisScreenPtr sisScreen = (sisScreenPtr)sPriv->private;
185
186 if ( sisScreen == NULL )
187 return;
188
189 if (sisScreen->agp.size != 0)
190 drmUnmap( sisScreen->agp.map, sisScreen->agp.size );
191 drmUnmap( sisScreen->mmio.map, sisScreen->mmio.size );
192
193 FREE( sisScreen );
194 sPriv->private = NULL;
195 }
196
197
198 /* Create and initialize the Mesa and driver specific pixmap buffer
199 * data.
200 */
201 static GLboolean
202 sisCreateBuffer( __DRIscreenPrivate *driScrnPriv,
203 __DRIdrawablePrivate *driDrawPriv,
204 const __GLcontextModes *mesaVis,
205 GLboolean isPixmap )
206 {
207 sisScreenPtr screen = (sisScreenPtr) driScrnPriv->private;
208 struct gl_framebuffer *fb;
209
210 if (isPixmap)
211 return GL_FALSE; /* not implemented */
212
213 fb = _mesa_create_framebuffer(mesaVis);
214
215 _mesa_add_soft_renderbuffers(fb,
216 GL_FALSE, /* color */
217 GL_FALSE, /* depth */
218 mesaVis->stencilBits > 0,
219 mesaVis->accumRedBits > 0,
220 GL_FALSE, /* alpha */
221 GL_FALSE /* aux */);
222 driDrawPriv->driverPrivate = (void *) fb;
223
224 return (driDrawPriv->driverPrivate != NULL);
225 }
226
227
228 static void
229 sisDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
230 {
231 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
232 }
233
234 __inline__ static void
235 sis_bitblt_copy_cmd (sisContextPtr smesa, ENGPACKET * pkt)
236 {
237 GLint *lpdwDest, *lpdwSrc;
238 int i;
239
240 lpdwSrc = (GLint *) pkt;
241 lpdwDest = (GLint *) (GET_IOBase (smesa) + REG_SRC_ADDR);
242
243 mWait3DCmdQueue (10);
244
245 for (i = 0; i < 7; i++)
246 *lpdwDest++ = *lpdwSrc++;
247
248 MMIO(REG_CMD0, *(GLint *)&pkt->stdwCmd);
249 MMIO(REG_CommandQueue, -1);
250 }
251
252 static void sisCopyBuffer( __DRIdrawablePrivate *dPriv )
253 {
254 sisContextPtr smesa = (sisContextPtr)dPriv->driContextPriv->driverPrivate;
255 int i;
256 ENGPACKET stEngPacket;
257
258 memset(&stEngPacket, 0, sizeof(ENGPACKET));
259
260 while ((*smesa->FrameCountPtr) - MMIO_READ(0x8a2c) > SIS_MAX_FRAME_LENGTH)
261 ;
262
263 LOCK_HARDWARE();
264
265 stEngPacket.dwSrcBaseAddr = smesa->back.offset;
266 stEngPacket.dwSrcPitch = smesa->back.pitch |
267 ((smesa->bytesPerPixel == 2) ? 0x80000000 : 0xc0000000);
268 stEngPacket.dwDestBaseAddr = 0;
269 stEngPacket.wDestPitch = smesa->front.pitch;
270 /* TODO: set maximum value? */
271 stEngPacket.wDestHeight = smesa->virtualY;
272
273 stEngPacket.stdwCmd.cRop = 0xcc;
274
275 if (smesa->blockWrite)
276 stEngPacket.stdwCmd.cCmd0 = CMD0_PAT_FG_COLOR;
277 else
278 stEngPacket.stdwCmd.cCmd0 = 0;
279 stEngPacket.stdwCmd.cCmd1 = CMD1_DIR_X_INC | CMD1_DIR_Y_INC;
280
281 for (i = 0; i < dPriv->numClipRects; i++) {
282 drm_clip_rect_t *box = &dPriv->pClipRects[i];
283 stEngPacket.stdwSrcPos.wY = box->y1 - dPriv->y;
284 stEngPacket.stdwSrcPos.wX = box->x1 - dPriv->x;
285 stEngPacket.stdwDestPos.wY = box->y1;
286 stEngPacket.stdwDestPos.wX = box->x1;
287
288 stEngPacket.stdwDim.wWidth = (GLshort) box->x2 - box->x1;
289 stEngPacket.stdwDim.wHeight = (GLshort) box->y2 - box->y1;
290 sis_bitblt_copy_cmd( smesa, &stEngPacket );
291 }
292
293 *(GLint *)(smesa->IOBase+0x8a2c) = *smesa->FrameCountPtr;
294 (*smesa->FrameCountPtr)++;
295
296 UNLOCK_HARDWARE ();
297 }
298
299
300 /* Copy the back color buffer to the front color buffer */
301 static void
302 sisSwapBuffers(__DRIdrawablePrivate *dPriv)
303 {
304 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
305 sisContextPtr smesa = (sisContextPtr) dPriv->driContextPriv->driverPrivate;
306 GLcontext *ctx = smesa->glCtx;
307
308 if (ctx->Visual.doubleBufferMode) {
309 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
310 sisCopyBuffer( dPriv );
311 }
312 } else {
313 /* XXX this shouldn't be an error but we can't handle it for now */
314 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
315 }
316 }
317
318
319 /* Initialize the driver specific screen private data.
320 */
321 static GLboolean
322 sisInitDriver( __DRIscreenPrivate *sPriv )
323 {
324 sPriv->private = (void *) sisCreateScreen( sPriv );
325
326 if ( !sPriv->private ) {
327 sisDestroyScreen( sPriv );
328 return GL_FALSE;
329 }
330
331 return GL_TRUE;
332 }
333
334 static struct __DriverAPIRec sisAPI = {
335 .InitDriver = sisInitDriver,
336 .DestroyScreen = sisDestroyScreen,
337 .CreateContext = sisCreateContext,
338 .DestroyContext = sisDestroyContext,
339 .CreateBuffer = sisCreateBuffer,
340 .DestroyBuffer = sisDestroyBuffer,
341 .SwapBuffers = sisSwapBuffers,
342 .MakeCurrent = sisMakeCurrent,
343 .UnbindContext = sisUnbindContext,
344 .GetSwapInfo = NULL,
345 .GetMSC = NULL,
346 .WaitForMSC = NULL,
347 .WaitForSBC = NULL,
348 .SwapBuffersMSC = NULL
349
350 };
351
352
353 /**
354 * This is the bootstrap function for the driver. libGL supplies all of the
355 * requisite information about the system, and the driver initializes itself.
356 * This routine also fills in the linked list pointed to by \c driver_modes
357 * with the \c __GLcontextModes that the driver can support for windows or
358 * pbuffers.
359 *
360 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
361 * failure.
362 */
363 PUBLIC
364 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn,
365 __DRIscreen *psc,
366 const __GLcontextModes *modes,
367 const __DRIversion *ddx_version,
368 const __DRIversion *dri_version,
369 const __DRIversion *drm_version,
370 const __DRIframebuffer *frame_buffer,
371 drmAddress pSAREA, int fd,
372 int internal_api_version,
373 const __DRIinterfaceMethods * interface,
374 __GLcontextModes **driver_modes )
375
376 {
377 __DRIscreenPrivate *psp;
378 static const __DRIversion ddx_expected = {0, 8, 0};
379 static const __DRIversion dri_expected = {4, 0, 0};
380 static const __DRIversion drm_expected = {1, 0, 0};
381
382 dri_interface = interface;
383
384 if (!driCheckDriDdxDrmVersions2("SiS", dri_version, &dri_expected,
385 ddx_version, &ddx_expected,
386 drm_version, &drm_expected)) {
387 return NULL;
388 }
389
390 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
391 ddx_version, dri_version, drm_version,
392 frame_buffer, pSAREA, fd,
393 internal_api_version, &sisAPI);
394 if (psp != NULL) {
395 SISDRIPtr dri_priv = (SISDRIPtr)psp->pDevPriv;
396 *driver_modes = sisFillInModes(dri_priv->bytesPerPixel * 8);
397
398 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
399 * enable the extensions. It just makes sure that all the dispatch offsets for all
400 * the extensions that *might* be enables are known. This is needed because the
401 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
402 * enable the extensions until we have a context pointer.
403 *
404 * Hello chicken. Hello egg. How are you two today?
405 */
406 driInitExtensions( NULL, card_extensions, GL_FALSE );
407 }
408
409 return (void *)psp;
410 }