nouveau: get 16bpp working
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_screen.c
1 /**************************************************************************
2
3 Copyright 2006 Stephane Marchesin
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 "Software"),
8 to deal in the Software without restriction, including without limitation
9 on the rights to use, copy, modify, merge, publish, distribute, sub
10 license, and/or sell copies of the Software, and to permit persons to whom
11 the Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice (including the next
14 paragraph) shall be included in all copies or substantial portions of the
15 Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 ERIC ANHOLT OR SILICON INTEGRATED SYSTEMS CORP BE LIABLE FOR ANY CLAIM,
21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27 #include "glheader.h"
28 #include "imports.h"
29 #include "mtypes.h"
30 #include "framebuffer.h"
31 #include "renderbuffer.h"
32
33 #include "nouveau_context.h"
34 #include "nouveau_screen.h"
35 #include "nouveau_object.h"
36 #include "nouveau_span.h"
37
38 #include "utils.h"
39 #include "context.h"
40 #include "vblank.h"
41 #include "drirenderbuffer.h"
42
43 #include "GL/internal/dri_interface.h"
44
45 #include "xmlpool.h"
46
47 PUBLIC const char __driConfigOptions[] =
48 DRI_CONF_BEGIN
49 DRI_CONF_SECTION_DEBUG
50 DRI_CONF_NO_RAST(false)
51 DRI_CONF_SECTION_END
52 DRI_CONF_END;
53 static const GLuint __driNConfigOptions = 1;
54
55 extern const struct dri_extension common_extensions[];
56 extern const struct dri_extension nv10_extensions[];
57 extern const struct dri_extension nv20_extensions[];
58 extern const struct dri_extension nv30_extensions[];
59 extern const struct dri_extension nv40_extensions[];
60 extern const struct dri_extension nv50_extensions[];
61
62 static nouveauScreenPtr nouveauCreateScreen(__DRIscreenPrivate *sPriv)
63 {
64 nouveauScreenPtr screen;
65 NOUVEAUDRIPtr dri_priv=(NOUVEAUDRIPtr)sPriv->pDevPriv;
66
67 /* allocate screen */
68 screen = (nouveauScreenPtr) CALLOC( sizeof(*screen) );
69 if ( !screen ) {
70 __driUtilMessage("%s: Could not allocate memory for screen structure",__FUNCTION__);
71 return NULL;
72 }
73
74 /* parse information in __driConfigOptions */
75 driParseOptionInfo (&screen->optionCache,__driConfigOptions, __driNConfigOptions);
76
77 screen->fbFormat = dri_priv->bpp / 8;
78 screen->frontOffset = dri_priv->front_offset;
79 screen->frontPitch = dri_priv->front_pitch;
80 screen->backOffset = dri_priv->back_offset;
81 screen->backPitch = dri_priv->back_pitch;
82 screen->depthOffset = dri_priv->depth_offset;
83 screen->depthPitch = dri_priv->depth_pitch;
84
85 screen->card=nouveau_card_lookup(dri_priv->device_id);
86 screen->driScreen = sPriv;
87 return screen;
88 }
89
90 static void
91 nouveauDestroyScreen(__DRIscreenPrivate *sPriv)
92 {
93 nouveauScreenPtr screen = (nouveauScreenPtr)sPriv->private;
94
95 if (!screen) return;
96
97 /* free all option information */
98 driDestroyOptionInfo (&screen->optionCache);
99
100 FREE(screen);
101 sPriv->private = NULL;
102 }
103
104 static GLboolean nouveauInitDriver(__DRIscreenPrivate *sPriv)
105 {
106 sPriv->private = (void *) nouveauCreateScreen( sPriv );
107 if ( !sPriv->private ) {
108 nouveauDestroyScreen( sPriv );
109 return GL_FALSE;
110 }
111
112 return GL_TRUE;
113 }
114
115 /**
116 * Create the Mesa framebuffer and renderbuffers for a given window/drawable.
117 *
118 * \todo This function (and its interface) will need to be updated to support
119 * pbuffers.
120 */
121 static GLboolean
122 nouveauCreateBuffer(__DRIscreenPrivate *driScrnPriv,
123 __DRIdrawablePrivate *driDrawPriv,
124 const __GLcontextModes *mesaVis,
125 GLboolean isPixmap)
126 {
127 nouveauScreenPtr screen = (nouveauScreenPtr) driScrnPriv->private;
128 nouveau_renderbuffer *nrb;
129 struct gl_framebuffer *fb;
130 const GLboolean swAccum = mesaVis->accumRedBits > 0;
131 const GLboolean swStencil = mesaVis->stencilBits > 0 && mesaVis->depthBits != 24;
132 GLenum color_format = screen->fbFormat == 4 ? GL_RGBA8 : GL_RGB5;
133
134 if (isPixmap)
135 return GL_FALSE; /* not implemented */
136
137 fb = _mesa_create_framebuffer(mesaVis);
138 if (!fb)
139 return GL_FALSE;
140
141 /* Front buffer */
142 nrb = nouveau_renderbuffer_new(color_format,
143 driScrnPriv->pFB + screen->frontOffset,
144 screen->frontOffset,
145 screen->frontPitch * screen->fbFormat,
146 driDrawPriv);
147 nouveauSpanSetFunctions(nrb, mesaVis);
148 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &nrb->mesa);
149
150 if (0 /* unified buffers if we choose to support them.. */) {
151 } else {
152 if (mesaVis->doubleBufferMode) {
153 nrb = nouveau_renderbuffer_new(color_format, NULL,
154 0, 0,
155 driDrawPriv);
156 nouveauSpanSetFunctions(nrb, mesaVis);
157 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &nrb->mesa);
158 }
159
160 if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
161 nrb = nouveau_renderbuffer_new(GL_DEPTH24_STENCIL8_EXT, NULL,
162 0, 0,
163 driDrawPriv);
164 nouveauSpanSetFunctions(nrb, mesaVis);
165 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
166 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &nrb->mesa);
167 } else if (mesaVis->depthBits == 24) {
168 nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT24, NULL,
169 0, 0,
170 driDrawPriv);
171 nouveauSpanSetFunctions(nrb, mesaVis);
172 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
173 } else if (mesaVis->depthBits == 16) {
174 nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT16, NULL,
175 0, 0,
176 driDrawPriv);
177 nouveauSpanSetFunctions(nrb, mesaVis);
178 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
179 }
180 }
181
182 _mesa_add_soft_renderbuffers(fb,
183 GL_FALSE, /* color */
184 GL_FALSE, /* depth */
185 swStencil,
186 swAccum,
187 GL_FALSE, /* alpha */
188 GL_FALSE /* aux */);
189
190 driDrawPriv->driverPrivate = (void *) fb;
191 return (driDrawPriv->driverPrivate != NULL);
192 }
193
194
195 static void
196 nouveauDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
197 {
198 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
199 }
200
201 static int
202 nouveauGetSwapInfo(__DRIdrawablePrivate *dpriv, __DRIswapInfo *sInfo)
203 {
204 return -1;
205 }
206
207 static const struct __DriverAPIRec nouveauAPI = {
208 .InitDriver = nouveauInitDriver,
209 .DestroyScreen = nouveauDestroyScreen,
210 .CreateContext = nouveauCreateContext,
211 .DestroyContext = nouveauDestroyContext,
212 .CreateBuffer = nouveauCreateBuffer,
213 .DestroyBuffer = nouveauDestroyBuffer,
214 .SwapBuffers = nouveauSwapBuffers,
215 .MakeCurrent = nouveauMakeCurrent,
216 .UnbindContext = nouveauUnbindContext,
217 .GetSwapInfo = nouveauGetSwapInfo,
218 .GetMSC = driGetMSC32,
219 .WaitForMSC = driWaitForMSC32,
220 .WaitForSBC = NULL,
221 .SwapBuffersMSC = NULL,
222 .CopySubBuffer = nouveauCopySubBuffer
223 };
224
225
226 static __GLcontextModes *
227 nouveauFillInModes( unsigned pixel_bits, unsigned depth_bits,
228 unsigned stencil_bits, GLboolean have_back_buffer )
229 {
230 __GLcontextModes * modes;
231 __GLcontextModes * m;
232 unsigned num_modes;
233 unsigned depth_buffer_factor;
234 unsigned back_buffer_factor;
235 unsigned fb_format_factor;
236 int i;
237
238 static const struct {
239 GLenum format;
240 GLenum type;
241 } fb_format_array[] = {
242 { GL_RGB , GL_UNSIGNED_SHORT_5_6_5 },
243 { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
244 { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
245 };
246
247 /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
248 * support pageflipping at all.
249 */
250 static const GLenum back_buffer_modes[] = {
251 GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
252 };
253
254 u_int8_t depth_bits_array[4] = { 0, 16, 24, 24 };
255 u_int8_t stencil_bits_array[4] = { 0, 0, 0, 8 };
256
257 depth_buffer_factor = 4;
258 back_buffer_factor = (have_back_buffer) ? 3 : 1;
259
260 num_modes = ((pixel_bits==16) ? 1 : 2) *
261 depth_buffer_factor * back_buffer_factor * 4;
262 modes = (*dri_interface->createContextModes)(num_modes,
263 sizeof(__GLcontextModes));
264 m = modes;
265
266 for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
267 if (!driFillInModes(&m, fb_format_array[i].format,
268 fb_format_array[i].type,
269 depth_bits_array,
270 stencil_bits_array,
271 depth_buffer_factor,
272 back_buffer_modes,
273 back_buffer_factor,
274 GLX_TRUE_COLOR)) {
275 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
276 __func__, __LINE__ );
277 return NULL;
278 }
279
280 if (!driFillInModes(&m, fb_format_array[i].format,
281 fb_format_array[i].type,
282 depth_bits_array,
283 stencil_bits_array,
284 depth_buffer_factor,
285 back_buffer_modes,
286 back_buffer_factor,
287 GLX_DIRECT_COLOR)) {
288 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
289 __func__, __LINE__ );
290 return NULL;
291 }
292 }
293
294 return modes;
295 }
296
297
298 /**
299 * This is the bootstrap function for the driver. libGL supplies all of the
300 * requisite information about the system, and the driver initializes itself.
301 * This routine also fills in the linked list pointed to by \c driver_modes
302 * with the \c __GLcontextModes that the driver can support for windows or
303 * pbuffers.
304 *
305 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
306 * failure.
307 */
308 PUBLIC
309 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
310 const __GLcontextModes * modes,
311 const __DRIversion * ddx_version,
312 const __DRIversion * dri_version,
313 const __DRIversion * drm_version,
314 const __DRIframebuffer * frame_buffer,
315 drmAddress pSAREA, int fd,
316 int internal_api_version,
317 const __DRIinterfaceMethods * interface,
318 __GLcontextModes ** driver_modes)
319
320 {
321 __DRIscreenPrivate *psp;
322 static const __DRIversion ddx_expected = { 1, 2, 0 };
323 static const __DRIversion dri_expected = { 4, 0, 0 };
324 static const __DRIversion drm_expected = { 0, 0, 1 };
325
326 dri_interface = interface;
327
328 if (!driCheckDriDdxDrmVersions2("nouveau",
329 dri_version, & dri_expected,
330 ddx_version, & ddx_expected,
331 drm_version, & drm_expected)) {
332 return NULL;
333 }
334
335 // temporary lock step versioning
336 if (drm_expected.patch!=drm_version->patch)
337 return NULL;
338
339 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
340 ddx_version, dri_version, drm_version,
341 frame_buffer, pSAREA, fd,
342 internal_api_version, &nouveauAPI);
343 if ( psp != NULL ) {
344 NOUVEAUDRIPtr dri_priv = (NOUVEAUDRIPtr)psp->pDevPriv;
345
346 *driver_modes = nouveauFillInModes(dri_priv->bpp,
347 (dri_priv->bpp == 16) ? 16 : 24,
348 (dri_priv->bpp == 16) ? 0 : 8,
349 1
350 );
351
352 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
353 * enable the extensions. It just makes sure that all the dispatch offsets for all
354 * the extensions that *might* be enables are known. This is needed because the
355 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
356 * enable the extensions until we have a context pointer.
357 *
358 * Hello chicken. Hello egg. How are you two today?
359 */
360 driInitExtensions( NULL, common_extensions, GL_FALSE );
361 driInitExtensions( NULL, nv10_extensions, GL_FALSE );
362 driInitExtensions( NULL, nv10_extensions, GL_FALSE );
363 driInitExtensions( NULL, nv30_extensions, GL_FALSE );
364 driInitExtensions( NULL, nv40_extensions, GL_FALSE );
365 driInitExtensions( NULL, nv50_extensions, GL_FALSE );
366 }
367
368 return (void *) psp;
369 }
370