Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa
[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 #define SIS_AGP_DISABLE(def) \
50 DRI_CONF_OPT_BEGIN(agp_disable,bool,def) \
51 DRI_CONF_DESC(en,"Disable AGP vertex dispatch") \
52 DRI_CONF_OPT_END
53
54 PUBLIC const char __driConfigOptions[] =
55 DRI_CONF_BEGIN
56 DRI_CONF_SECTION_QUALITY
57 DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB)
58 DRI_CONF_SECTION_END
59 DRI_CONF_SECTION_DEBUG
60 SIS_AGP_DISABLE(true)
61 DRI_CONF_NO_RAST(false)
62 DRI_CONF_SECTION_END
63 DRI_CONF_END;
64 static const GLuint __driNConfigOptions = 3;
65
66 extern const struct dri_extension card_extensions[];
67
68 static __GLcontextModes *
69 sisFillInModes(int bpp)
70 {
71 __GLcontextModes *modes;
72 __GLcontextModes *m;
73 unsigned num_modes;
74 unsigned depth_buffer_factor;
75 unsigned back_buffer_factor;
76 GLenum fb_format;
77 GLenum fb_type;
78 static const GLenum back_buffer_modes[] = {
79 GLX_NONE, GLX_SWAP_UNDEFINED_OML
80 };
81 u_int8_t depth_bits_array[4];
82 u_int8_t stencil_bits_array[4];
83
84 depth_bits_array[0] = 0;
85 stencil_bits_array[0] = 0;
86 depth_bits_array[1] = 16;
87 stencil_bits_array[1] = 0;
88 depth_bits_array[2] = 24;
89 stencil_bits_array[2] = 8;
90 depth_bits_array[3] = 32;
91 stencil_bits_array[3] = 0;
92
93 depth_buffer_factor = 4;
94 back_buffer_factor = 2;
95
96 /* Last 4 is for GLX_TRUE_COLOR & GLX_DIRECT_COLOR, with/without accum */
97 num_modes = depth_buffer_factor * back_buffer_factor * 4;
98
99 if (bpp == 16) {
100 fb_format = GL_RGB;
101 fb_type = GL_UNSIGNED_SHORT_5_6_5;
102 } else {
103 fb_format = GL_BGRA;
104 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
105 }
106
107 modes = (*dri_interface->createContextModes)(num_modes, sizeof(__GLcontextModes));
108 m = modes;
109 if (!driFillInModes(&m, fb_format, fb_type, depth_bits_array,
110 stencil_bits_array, depth_buffer_factor,
111 back_buffer_modes, back_buffer_factor,
112 GLX_TRUE_COLOR)) {
113 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, __LINE__);
114 return NULL;
115 }
116
117 if (!driFillInModes(&m, fb_format, fb_type, depth_bits_array,
118 stencil_bits_array, depth_buffer_factor,
119 back_buffer_modes, back_buffer_factor,
120 GLX_DIRECT_COLOR)) {
121 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, __LINE__);
122 return NULL;
123 }
124
125 return modes;
126 }
127
128
129 /* Create the device specific screen private data struct.
130 */
131 static sisScreenPtr
132 sisCreateScreen( __DRIscreenPrivate *sPriv )
133 {
134 sisScreenPtr sisScreen;
135 SISDRIPtr sisDRIPriv = (SISDRIPtr)sPriv->pDevPriv;
136
137 if (sPriv->devPrivSize != sizeof(SISDRIRec)) {
138 fprintf(stderr,"\nERROR! sizeof(SISDRIRec) does not match passed size from device driver\n");
139 return GL_FALSE;
140 }
141
142 /* Allocate the private area */
143 sisScreen = (sisScreenPtr)CALLOC( sizeof(*sisScreen) );
144 if ( sisScreen == NULL )
145 return NULL;
146
147 sisScreen->screenX = sisDRIPriv->width;
148 sisScreen->screenY = sisDRIPriv->height;
149 sisScreen->cpp = sisDRIPriv->bytesPerPixel;
150 sisScreen->deviceID = sisDRIPriv->deviceID;
151 sisScreen->AGPCmdBufOffset = sisDRIPriv->AGPCmdBufOffset;
152 sisScreen->AGPCmdBufSize = sisDRIPriv->AGPCmdBufSize;
153 sisScreen->sarea_priv_offset = sizeof(drm_sarea_t);
154
155 sisScreen->mmio.handle = sisDRIPriv->regs.handle;
156 sisScreen->mmio.size = sisDRIPriv->regs.size;
157 if ( drmMap( sPriv->fd, sisScreen->mmio.handle, sisScreen->mmio.size,
158 &sisScreen->mmio.map ) )
159 {
160 FREE( sisScreen );
161 return NULL;
162 }
163
164 if (sisDRIPriv->agp.size) {
165 sisScreen->agp.handle = sisDRIPriv->agp.handle;
166 sisScreen->agpBaseOffset = drmAgpBase(sPriv->fd);
167 sisScreen->agp.size = sisDRIPriv->agp.size;
168 if ( drmMap( sPriv->fd, sisScreen->agp.handle, sisScreen->agp.size,
169 &sisScreen->agp.map ) )
170 {
171 sisScreen->agp.size = 0;
172 }
173 }
174
175 sisScreen->driScreen = sPriv;
176
177 /* parse information in __driConfigOptions */
178 driParseOptionInfo(&sisScreen->optionCache,
179 __driConfigOptions, __driNConfigOptions);
180
181 return sisScreen;
182 }
183
184 /* Destroy the device specific screen private data struct.
185 */
186 static void
187 sisDestroyScreen( __DRIscreenPrivate *sPriv )
188 {
189 sisScreenPtr sisScreen = (sisScreenPtr)sPriv->private;
190
191 if ( sisScreen == NULL )
192 return;
193
194 if (sisScreen->agp.size != 0)
195 drmUnmap( sisScreen->agp.map, sisScreen->agp.size );
196 drmUnmap( sisScreen->mmio.map, sisScreen->mmio.size );
197
198 FREE( sisScreen );
199 sPriv->private = NULL;
200 }
201
202
203 /* Create and initialize the Mesa and driver specific pixmap buffer
204 * data.
205 */
206 static GLboolean
207 sisCreateBuffer( __DRIscreenPrivate *driScrnPriv,
208 __DRIdrawablePrivate *driDrawPriv,
209 const __GLcontextModes *mesaVis,
210 GLboolean isPixmap )
211 {
212 /*sisScreenPtr screen = (sisScreenPtr) driScrnPriv->private;*/
213 struct gl_framebuffer *fb;
214
215 if (isPixmap)
216 return GL_FALSE; /* not implemented */
217
218 fb = _mesa_create_framebuffer(mesaVis);
219
220 _mesa_add_soft_renderbuffers(fb,
221 GL_FALSE, /* color */
222 GL_FALSE, /* depth */
223 mesaVis->stencilBits > 0,
224 mesaVis->accumRedBits > 0,
225 GL_FALSE, /* alpha */
226 GL_FALSE /* aux */);
227 driDrawPriv->driverPrivate = (void *) fb;
228
229 return (driDrawPriv->driverPrivate != NULL);
230 }
231
232
233 static void
234 sisDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
235 {
236 _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
237 }
238
239 static void sisCopyBuffer( __DRIdrawablePrivate *dPriv )
240 {
241 sisContextPtr smesa = (sisContextPtr)dPriv->driContextPriv->driverPrivate;
242 int i;
243
244 while ((*smesa->FrameCountPtr) - MMIO_READ(0x8a2c) > SIS_MAX_FRAME_LENGTH)
245 ;
246
247 LOCK_HARDWARE();
248
249 for (i = 0; i < dPriv->numClipRects; i++) {
250 drm_clip_rect_t *box = &dPriv->pClipRects[i];
251
252 mWait3DCmdQueue(10);
253 MMIO(REG_SRC_ADDR, smesa->back.offset);
254 MMIO(REG_SRC_PITCH, smesa->back.pitch | ((smesa->bytesPerPixel == 4) ?
255 BLIT_DEPTH_32 : BLIT_DEPTH_16));
256 MMIO(REG_SRC_X_Y, ((box->x1 - dPriv->x) << 16) | (box->y1 - dPriv->y));
257 MMIO(REG_DST_X_Y, ((box->x1 - dPriv->x) << 16) | (box->y1 - dPriv->y));
258 MMIO(REG_DST_ADDR, smesa->front.offset);
259 MMIO(REG_DST_PITCH_HEIGHT, (smesa->virtualY << 16) | smesa->front.pitch);
260 MMIO(REG_WIDTH_HEIGHT, ((box->y2 - box->y1) << 16) | (box->x2 - box->x1));
261 MMIO(REG_BLIT_CMD, CMD_DIR_X_INC | CMD_DIR_Y_INC | CMD_ROP_SRC);
262 MMIO(REG_CommandQueue, -1);
263 }
264
265 *(GLint *)(smesa->IOBase+0x8a2c) = *smesa->FrameCountPtr;
266 (*smesa->FrameCountPtr)++;
267
268 UNLOCK_HARDWARE ();
269 }
270
271
272 /* Copy the back color buffer to the front color buffer */
273 static void
274 sisSwapBuffers(__DRIdrawablePrivate *dPriv)
275 {
276 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
277 sisContextPtr smesa = (sisContextPtr) dPriv->driContextPriv->driverPrivate;
278 GLcontext *ctx = smesa->glCtx;
279
280 if (ctx->Visual.doubleBufferMode) {
281 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
282 sisCopyBuffer( dPriv );
283 }
284 } else {
285 /* XXX this shouldn't be an error but we can't handle it for now */
286 _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
287 }
288 }
289
290
291 /* Initialize the driver specific screen private data.
292 */
293 static GLboolean
294 sisInitDriver( __DRIscreenPrivate *sPriv )
295 {
296 sPriv->private = (void *) sisCreateScreen( sPriv );
297
298 if ( !sPriv->private ) {
299 sisDestroyScreen( sPriv );
300 return GL_FALSE;
301 }
302
303 return GL_TRUE;
304 }
305
306 static struct __DriverAPIRec sisAPI = {
307 .DestroyScreen = sisDestroyScreen,
308 .CreateContext = sisCreateContext,
309 .DestroyContext = sisDestroyContext,
310 .CreateBuffer = sisCreateBuffer,
311 .DestroyBuffer = sisDestroyBuffer,
312 .SwapBuffers = sisSwapBuffers,
313 .MakeCurrent = sisMakeCurrent,
314 .UnbindContext = sisUnbindContext,
315 .GetSwapInfo = NULL,
316 .GetMSC = NULL,
317 .GetDrawableMSC = NULL,
318 .WaitForMSC = NULL,
319 .WaitForSBC = NULL,
320 .SwapBuffersMSC = NULL
321
322 };
323
324
325 /**
326 * This is the driver specific part of the createNewScreen entry point.
327 *
328 * \todo maybe fold this into intelInitDriver
329 *
330 * \return the __GLcontextModes supported by this driver
331 */
332 __GLcontextModes *__driDriverInitScreen(__DRIscreenPrivate *psp)
333 {
334 static const __DRIversion ddx_expected = {0, 8, 0};
335 static const __DRIversion dri_expected = {4, 0, 0};
336 static const __DRIversion drm_expected = {1, 0, 0};
337 static const char *driver_name = "SiS";
338 SISDRIPtr dri_priv = (SISDRIPtr)psp->pDevPriv;
339
340 if (!driCheckDriDdxDrmVersions2(driver_name,
341 &psp->dri_version, &dri_expected,
342 &psp->ddx_version, &ddx_expected,
343 &psp->drm_version, &drm_expected))
344 return NULL;
345
346 psp->DriverAPI = sisAPI;
347
348 /* Calling driInitExtensions here, with a NULL context pointer,
349 * does not actually enable the extensions. It just makes sure
350 * that all the dispatch offsets for all the extensions that
351 * *might* be enables are known. This is needed because the
352 * dispatch offsets need to be known when _mesa_context_create is
353 * called, but we can't enable the extensions until we have a
354 * context pointer.
355 *
356 * Hello chicken. Hello egg. How are you two today?
357 */
358 driInitExtensions( NULL, card_extensions, GL_FALSE );
359
360 if (!sisInitDriver(psp))
361 return NULL;
362
363 return sisFillInModes(dri_priv->bytesPerPixel * 8);
364 }