1cf2211d3023af10a9e6ec75b81d8c92415cd7fe
[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
38 #include "sis_context.h"
39 #include "sis_dri.h"
40 #include "sis_lock.h"
41
42 #include "xmlpool.h"
43
44 #include "GL/internal/dri_interface.h"
45
46 const char __driConfigOptions[] =
47 DRI_CONF_BEGIN
48 DRI_CONF_SECTION_DEBUG
49 DRI_CONF_OPT_BEGIN(agp_disable,bool,false)
50 DRI_CONF_DESC(en,"Disable AGP vertex dispatch")
51 DRI_CONF_OPT_END
52 DRI_CONF_OPT_BEGIN(fallback_force,bool,false)
53 DRI_CONF_DESC(en,"Force software fallback")
54 DRI_CONF_OPT_END
55 DRI_CONF_SECTION_END
56 DRI_CONF_END;
57 static const GLuint __driNConfigOptions = 2;
58
59 #ifdef USE_NEW_INTERFACE
60 static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
61 #endif /* USE_NEW_INTERFACE */
62
63 #ifdef USE_NEW_INTERFACE
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 uint8_t depth_bits_array[4];
78 uint8_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 = (*create_context_modes)(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 #endif /* USE_NEW_INTERFACE */
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 #ifndef USE_NEW_INTERFACE
134 /* XXX Should this still be around for the old interface? */
135 if ( !driCheckDriDdxDrmVersions( sPriv, "SiS", 4, 0, 0, 1, 1, 0 ) )
136 return NULL;
137 #endif
138
139 /* Allocate the private area */
140 sisScreen = (sisScreenPtr)CALLOC( sizeof(*sisScreen) );
141 if ( sisScreen == NULL )
142 return NULL;
143
144 sisScreen->screenX = sisDRIPriv->width;
145 sisScreen->screenY = sisDRIPriv->height;
146 sisScreen->cpp = sisDRIPriv->bytesPerPixel;
147 sisScreen->irqEnabled = sisDRIPriv->bytesPerPixel;
148 sisScreen->deviceID = sisDRIPriv->deviceID;
149 sisScreen->AGPCmdBufOffset = sisDRIPriv->AGPCmdBufOffset;
150 sisScreen->AGPCmdBufSize = sisDRIPriv->AGPCmdBufSize;
151 sisScreen->sarea_priv_offset = sizeof(drm_sarea_t);
152
153 sisScreen->mmio.handle = sisDRIPriv->regs.handle;
154 sisScreen->mmio.size = sisDRIPriv->regs.size;
155 if ( drmMap( sPriv->fd, sisScreen->mmio.handle, sisScreen->mmio.size,
156 &sisScreen->mmio.map ) )
157 {
158 FREE( sisScreen );
159 return NULL;
160 }
161
162 if (sisDRIPriv->agp.size) {
163 sisScreen->agp.handle = sisDRIPriv->agp.handle;
164 sisScreen->agp.size = sisDRIPriv->agp.size;
165 if ( drmMap( sPriv->fd, sisScreen->agp.handle, sisScreen->agp.size,
166 &sisScreen->agp.map ) )
167 {
168 sisScreen->agp.size = 0;
169 }
170 }
171
172 sisScreen->driScreen = sPriv;
173
174 /* parse information in __driConfigOptions */
175 driParseOptionInfo(&sisScreen->optionCache,
176 __driConfigOptions, __driNConfigOptions);
177
178 return sisScreen;
179 }
180
181 /* Destroy the device specific screen private data struct.
182 */
183 static void
184 sisDestroyScreen( __DRIscreenPrivate *sPriv )
185 {
186 sisScreenPtr sisScreen = (sisScreenPtr)sPriv->private;
187
188 if ( sisScreen == NULL )
189 return;
190
191 if (sisScreen->agp.size != 0)
192 drmUnmap( sisScreen->agp.map, sisScreen->agp.size );
193 drmUnmap( sisScreen->mmio.map, sisScreen->mmio.size );
194
195 FREE( sisScreen );
196 sPriv->private = NULL;
197 }
198
199 /* Create and initialize the Mesa and driver specific pixmap buffer
200 * data.
201 */
202 static GLboolean
203 sisCreateBuffer( __DRIscreenPrivate *driScrnPriv,
204 __DRIdrawablePrivate *driDrawPriv,
205 const __GLcontextModes *mesaVis,
206 GLboolean isPixmap )
207 {
208 if (isPixmap)
209 return GL_FALSE; /* not implemented */
210
211 driDrawPriv->driverPrivate = (void *)_mesa_create_framebuffer(
212 mesaVis,
213 GL_FALSE, /* software depth buffer? */
214 mesaVis->stencilBits > 0,
215 mesaVis->accumRedBits > 0,
216 mesaVis->alphaBits > 0 ); /* XXX */
217 return (driDrawPriv->driverPrivate != NULL);
218 }
219
220
221 static void
222 sisDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
223 {
224 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
225 }
226
227 __inline__ static void
228 sis_bitblt_copy_cmd (sisContextPtr smesa, ENGPACKET * pkt)
229 {
230 GLint *lpdwDest, *lpdwSrc;
231 int i;
232
233 lpdwSrc = (GLint *) pkt;
234 lpdwDest = (GLint *) (GET_IOBase (smesa) + REG_SRC_ADDR);
235
236 mWait3DCmdQueue (10);
237
238 for (i = 0; i < 7; i++)
239 *lpdwDest++ = *lpdwSrc++;
240
241 MMIO(REG_CMD0, *(GLint *)&pkt->stdwCmd);
242 MMIO(REG_CommandQueue, -1);
243 }
244
245 static void sisCopyBuffer( __DRIdrawablePrivate *dPriv )
246 {
247 sisContextPtr smesa = (sisContextPtr)dPriv->driContextPriv->driverPrivate;
248 int i;
249 ENGPACKET stEngPacket;
250
251 while ((*smesa->FrameCountPtr) - MMIO_READ(0x8a2c) > SIS_MAX_FRAME_LENGTH)
252 ;
253
254 LOCK_HARDWARE();
255
256 stEngPacket.dwSrcBaseAddr = smesa->backOffset;
257 stEngPacket.dwSrcPitch = smesa->backPitch |
258 ((smesa->bytesPerPixel == 2) ? 0x80000000 : 0xc0000000);
259 stEngPacket.dwDestBaseAddr = 0;
260 stEngPacket.wDestPitch = smesa->frontPitch;
261 /* TODO: set maximum value? */
262 stEngPacket.wDestHeight = smesa->virtualY;
263
264 stEngPacket.stdwCmd.cRop = 0xcc;
265
266 if (smesa->blockWrite)
267 stEngPacket.stdwCmd.cCmd0 = CMD0_PAT_FG_COLOR;
268 else
269 stEngPacket.stdwCmd.cCmd0 = 0;
270 stEngPacket.stdwCmd.cCmd1 = CMD1_DIR_X_INC | CMD1_DIR_Y_INC;
271
272 for (i = 0; i < dPriv->numClipRects; i++) {
273 drm_clip_rect_t *box = &dPriv->pClipRects[i];
274 stEngPacket.stdwSrcPos.wY = box->y1 - dPriv->y;
275 stEngPacket.stdwSrcPos.wX = box->x1 - dPriv->x;
276 stEngPacket.stdwDestPos.wY = box->y1;
277 stEngPacket.stdwDestPos.wX = box->x1;
278
279 stEngPacket.stdwDim.wWidth = (GLshort) box->x2 - box->x1;
280 stEngPacket.stdwDim.wHeight = (GLshort) box->y2 - box->y1;
281 sis_bitblt_copy_cmd( smesa, &stEngPacket );
282 }
283
284 *(GLint *)(smesa->IOBase+0x8a2c) = *smesa->FrameCountPtr;
285 (*smesa->FrameCountPtr)++;
286
287 UNLOCK_HARDWARE ();
288 }
289
290
291 /* Copy the back color buffer to the front color buffer */
292 static void
293 sisSwapBuffers(__DRIdrawablePrivate *dPriv)
294 {
295 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
296 sisContextPtr smesa = (sisContextPtr) dPriv->driContextPriv->driverPrivate;
297 GLcontext *ctx = smesa->glCtx;
298
299 if (ctx->Visual.doubleBufferMode) {
300 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
301 sisCopyBuffer( dPriv );
302 }
303 } else {
304 /* XXX this shouldn't be an error but we can't handle it for now */
305 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
306 }
307 }
308
309
310 /* Initialize the driver specific screen private data.
311 */
312 static GLboolean
313 sisInitDriver( __DRIscreenPrivate *sPriv )
314 {
315 sPriv->private = (void *) sisCreateScreen( sPriv );
316
317 if ( !sPriv->private ) {
318 sisDestroyScreen( sPriv );
319 return GL_FALSE;
320 }
321
322 return GL_TRUE;
323 }
324
325 static struct __DriverAPIRec sisAPI = {
326 .InitDriver = sisInitDriver,
327 .DestroyScreen = sisDestroyScreen,
328 .CreateContext = sisCreateContext,
329 .DestroyContext = sisDestroyContext,
330 .CreateBuffer = sisCreateBuffer,
331 .DestroyBuffer = sisDestroyBuffer,
332 .SwapBuffers = sisSwapBuffers,
333 .MakeCurrent = sisMakeCurrent,
334 .UnbindContext = sisUnbindContext,
335 .GetSwapInfo = NULL,
336 .GetMSC = NULL,
337 .WaitForMSC = NULL,
338 .WaitForSBC = NULL,
339 .SwapBuffersMSC = NULL
340
341 };
342
343 /*
344 * This is the bootstrap function for the driver.
345 * The __driCreateScreen name is the symbol that libGL.so fetches.
346 * Return: pointer to a __DRIscreenPrivate.
347 */
348 #if !defined(DRI_NEW_INTERFACE_ONLY)
349 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
350 int numConfigs, __GLXvisualConfig *config)
351 {
352 __DRIscreenPrivate *psp;
353 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &sisAPI);
354 return (void *)psp;
355 }
356 #endif /* !defined(DRI_NEW_INTERFACE_ONLY) */
357
358 /**
359 * This is the bootstrap function for the driver. libGL supplies all of the
360 * requisite information about the system, and the driver initializes itself.
361 * This routine also fills in the linked list pointed to by \c driver_modes
362 * with the \c __GLcontextModes that the driver can support for windows or
363 * pbuffers.
364 *
365 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
366 * failure.
367 */
368 #ifdef USE_NEW_INTERFACE
369 void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn,
370 __DRIscreen *psc,
371 const __GLcontextModes *modes,
372 const __DRIversion *ddx_version,
373 const __DRIversion *dri_version,
374 const __DRIversion *drm_version,
375 const __DRIframebuffer *frame_buffer,
376 drmAddress pSAREA, int fd,
377 int internal_api_version,
378 __GLcontextModes **driver_modes )
379
380 {
381 __DRIscreenPrivate *psp;
382 static const __DRIversion ddx_expected = {0, 1, 0};
383 static const __DRIversion dri_expected = {4, 0, 0};
384 static const __DRIversion drm_expected = {1, 0, 0};
385
386 if (!driCheckDriDdxDrmVersions2("SiS", dri_version, &dri_expected,
387 ddx_version, &ddx_expected,
388 drm_version, &drm_expected)) {
389 return NULL;
390 }
391
392 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
393 ddx_version, dri_version, drm_version,
394 frame_buffer, pSAREA, fd,
395 internal_api_version, &sisAPI);
396 if (psp != NULL) {
397 create_context_modes = (PFNGLXCREATECONTEXTMODES)
398 glXGetProcAddress((const GLubyte *)"__glXCreateContextModes");
399 if (create_context_modes != NULL) {
400 SISDRIPtr dri_priv = (SISDRIPtr)psp->pDevPriv;
401 *driver_modes = sisFillInModes(dri_priv->bytesPerPixel * 8);
402 }
403 }
404
405 return (void *)psp;
406 }
407 #endif /* USE_NEW_INTERFACE */