f6274ac1f2bd7790ce6e45c71b8fd9472354c12e
[platform/upstream/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 #include "nouveau_msg.h"
38
39 #include "utils.h"
40 #include "context.h"
41 #include "vblank.h"
42 #include "drirenderbuffer.h"
43
44 #include "GL/internal/dri_interface.h"
45
46 #include "xmlpool.h"
47
48 PUBLIC const char __driConfigOptions[] =
49 DRI_CONF_BEGIN
50     DRI_CONF_SECTION_DEBUG
51         DRI_CONF_NO_RAST(false)
52     DRI_CONF_SECTION_END
53 DRI_CONF_END;
54 static const GLuint __driNConfigOptions = 1;
55
56 extern const struct dri_extension common_extensions[];
57 extern const struct dri_extension nv10_extensions[];
58 extern const struct dri_extension nv20_extensions[];
59 extern const struct dri_extension nv30_extensions[];
60 extern const struct dri_extension nv40_extensions[];
61 extern const struct dri_extension nv50_extensions[];
62
63 static nouveauScreenPtr nouveauCreateScreen(__DRIscreenPrivate *sPriv)
64 {
65         nouveauScreenPtr screen;
66         NOUVEAUDRIPtr dri_priv=(NOUVEAUDRIPtr)sPriv->pDevPriv;
67
68         /* allocate screen */
69         screen = (nouveauScreenPtr) CALLOC( sizeof(*screen) );
70         if ( !screen ) {         
71                 __driUtilMessage("%s: Could not allocate memory for screen structure",__FUNCTION__);
72                 return NULL;
73         }
74         
75         screen->card=nouveau_card_lookup(dri_priv->device_id);
76         if (!screen->card) {
77                 __driUtilMessage("%s: Unknown card type 0x%04x:0x%04x\n",
78                         __func__, dri_priv->device_id >> 16, dri_priv->device_id & 0xFFFF);
79                 FREE(screen);
80                 return NULL;
81         }
82
83         /* parse information in __driConfigOptions */
84         driParseOptionInfo (&screen->optionCache,__driConfigOptions, __driNConfigOptions);
85
86         screen->fbFormat    = dri_priv->bpp / 8;
87         screen->frontOffset = dri_priv->front_offset;
88         screen->frontPitch  = dri_priv->front_pitch;
89         screen->backOffset  = dri_priv->back_offset;
90         screen->backPitch   = dri_priv->back_pitch;
91         screen->depthOffset = dri_priv->depth_offset;
92         screen->depthPitch  = dri_priv->depth_pitch;
93
94         screen->driScreen = sPriv;
95         return screen;
96 }
97
98 static void
99 nouveauDestroyScreen(__DRIscreenPrivate *sPriv)
100 {
101         nouveauScreenPtr screen = (nouveauScreenPtr)sPriv->private;
102
103         if (!screen) return;
104
105         /* free all option information */
106         driDestroyOptionInfo (&screen->optionCache);
107
108         FREE(screen);
109         sPriv->private = NULL;
110 }
111
112 static GLboolean nouveauInitDriver(__DRIscreenPrivate *sPriv)
113 {
114         sPriv->private = (void *) nouveauCreateScreen( sPriv );
115         if ( !sPriv->private ) {
116                 nouveauDestroyScreen( sPriv );
117                 return GL_FALSE;
118         }
119
120         return GL_TRUE;
121 }
122
123 /**
124  * Create the Mesa framebuffer and renderbuffers for a given window/drawable.
125  *
126  * \todo This function (and its interface) will need to be updated to support
127  * pbuffers.
128  */
129 static GLboolean
130 nouveauCreateBuffer(__DRIscreenPrivate *driScrnPriv,
131                     __DRIdrawablePrivate *driDrawPriv,
132                     const __GLcontextModes *mesaVis,
133                     GLboolean isPixmap)
134 {
135         nouveauScreenPtr screen = (nouveauScreenPtr) driScrnPriv->private;
136         nouveau_renderbuffer_t *nrb;
137         struct gl_framebuffer *fb;
138         const GLboolean swAccum = mesaVis->accumRedBits > 0;
139         const GLboolean swStencil = (mesaVis->stencilBits > 0 &&
140                                      mesaVis->depthBits != 24);
141         GLenum color_format = screen->fbFormat == 4 ? GL_RGBA8 : GL_RGB5;
142
143         if (isPixmap)
144                 return GL_FALSE; /* not implemented */
145
146         fb = _mesa_create_framebuffer(mesaVis);
147         if (!fb)
148                 return GL_FALSE;
149
150         /* Front buffer */
151         nrb = nouveau_renderbuffer_new(color_format);
152         _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &nrb->mesa);
153
154         if (mesaVis->doubleBufferMode) {
155                 nrb = nouveau_renderbuffer_new(color_format);
156                 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &nrb->mesa);
157         }
158
159         if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
160                 nrb = nouveau_renderbuffer_new(GL_DEPTH24_STENCIL8_EXT);
161                 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
162                 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &nrb->mesa);
163         } else
164         if (mesaVis->depthBits == 24) {
165                 nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT24);
166                 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
167         } else
168         if (mesaVis->depthBits == 16) {
169                 nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT16);
170                 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
171         }
172
173         _mesa_add_soft_renderbuffers(fb,
174                                      GL_FALSE, /* color */
175                                      GL_FALSE, /* depth */
176                                      swStencil,
177                                      swAccum,
178                                      GL_FALSE, /* alpha */
179                                      GL_FALSE  /* aux */);
180
181         driDrawPriv->driverPrivate = (void *) fb;
182         return (driDrawPriv->driverPrivate != NULL);
183 }
184
185
186 static void
187 nouveauDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
188 {
189         _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
190 }
191
192 static int
193 nouveauGetSwapInfo(__DRIdrawablePrivate *dpriv, __DRIswapInfo *sInfo)
194 {
195         return -1;
196 }
197
198 static const struct __DriverAPIRec nouveauAPI = {
199         .DestroyScreen   = nouveauDestroyScreen,
200         .CreateContext   = nouveauCreateContext,
201         .DestroyContext  = nouveauDestroyContext,
202         .CreateBuffer    = nouveauCreateBuffer,
203         .DestroyBuffer   = nouveauDestroyBuffer,
204         .SwapBuffers     = nouveauSwapBuffers,
205         .MakeCurrent     = nouveauMakeCurrent,
206         .UnbindContext   = nouveauUnbindContext,
207         .GetSwapInfo     = nouveauGetSwapInfo,
208         .GetDrawableMSC  = driDrawableGetMSC32,
209         .WaitForMSC      = driWaitForMSC32,
210         .WaitForSBC      = NULL,
211         .SwapBuffersMSC  = NULL,
212         .CopySubBuffer   = nouveauCopySubBuffer
213 };
214
215
216 static __GLcontextModes *
217 nouveauFillInModes( unsigned pixel_bits, unsigned depth_bits,
218                  unsigned stencil_bits, GLboolean have_back_buffer )
219 {
220         __GLcontextModes * modes;
221         __GLcontextModes * m;
222         unsigned num_modes;
223         unsigned depth_buffer_factor;
224         unsigned back_buffer_factor;
225         int i;
226
227         static const struct {
228                 GLenum format;
229                 GLenum type;
230         } fb_format_array[] = {
231                 { GL_RGB , GL_UNSIGNED_SHORT_5_6_5     },
232                 { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
233                 { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
234         };
235
236         /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
237          * support pageflipping at all.
238          */
239         static const GLenum back_buffer_modes[] = {
240                 GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
241         };
242
243         u_int8_t depth_bits_array[4]   = { 0, 16, 24, 24 };
244         u_int8_t stencil_bits_array[4] = { 0,  0,  0,  8 };
245
246         depth_buffer_factor = 4;
247         back_buffer_factor  = (have_back_buffer) ? 3 : 1;
248
249         num_modes = ((pixel_bits==16) ? 1 : 2) *
250                 depth_buffer_factor * back_buffer_factor * 4;
251         modes = (*dri_interface->createContextModes)(num_modes,
252                                                      sizeof(__GLcontextModes));
253         m = modes;
254
255         for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
256                 if (!driFillInModes(&m, fb_format_array[i].format,
257                                         fb_format_array[i].type,
258                                         depth_bits_array,
259                                         stencil_bits_array,
260                                         depth_buffer_factor,
261                                         back_buffer_modes,
262                                         back_buffer_factor,
263                                         GLX_TRUE_COLOR)) {
264                 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
265                                 __func__, __LINE__ );
266                 return NULL;
267                 }
268
269                 if (!driFillInModes(&m, fb_format_array[i].format,
270                                         fb_format_array[i].type,
271                                         depth_bits_array,
272                                         stencil_bits_array,
273                                         depth_buffer_factor,
274                                         back_buffer_modes,
275                                         back_buffer_factor,
276                                         GLX_DIRECT_COLOR)) {
277                 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
278                                 __func__, __LINE__ );
279                 return NULL;
280                 }
281         }
282
283         return modes;
284 }
285
286
287 /**
288  * This is the driver specific part of the createNewScreen entry point.
289  * 
290  * \todo maybe fold this into intelInitDriver
291  *
292  * \return the __GLcontextModes supported by this driver
293  */
294 __GLcontextModes *__driDriverInitScreen(__DRIscreenPrivate *psp)
295 {
296         static const __DRIversion ddx_expected = { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
297         static const __DRIversion dri_expected = { 4, 0, 0 };
298         static const __DRIversion drm_expected = { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
299         NOUVEAUDRIPtr dri_priv = (NOUVEAUDRIPtr)psp->pDevPriv;
300
301         WARN_ONCE("\nThis driver is not currently maintained\n\n"
302                   "Current work on 3D is in the gallium-0.1 branch of:\n"
303                   "  git://anongit.freedesktop.org/git/nouveau/mesa\n");
304
305 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 10
306 #error nouveau_drm.h version doesn't match expected version
307 #endif
308
309         if (!driCheckDriDdxDrmVersions2("nouveau",
310                                         &psp->dri_version, & dri_expected,
311                                         &psp->ddx_version, & ddx_expected,
312                                         &psp->drm_version, & drm_expected))
313                 return NULL;
314
315         // temporary lock step versioning
316         if (drm_expected.patch != psp->drm_version.patch) {
317                 __driUtilMessage("%s: wrong DRM version, expected %d, got %d\n",
318                                  __func__,
319                                  drm_expected.patch, psp->drm_version.patch);
320                 return NULL;
321         }
322
323         psp->DriverAPI = nouveauAPI;
324
325         /* Calling driInitExtensions here, with a NULL context
326          * pointer, does not actually enable the extensions.  It just
327          * makes sure that all the dispatch offsets for all the
328          * extensions that *might* be enables are known.  This is
329          * needed because the dispatch offsets need to be known when
330          * _mesa_context_create is called, but we can't enable the
331          * extensions until we have a context pointer.
332          * 
333          * Hello chicken.  Hello egg.  How are you two today?
334          */
335         driInitExtensions( NULL, common_extensions, GL_FALSE );
336         driInitExtensions( NULL,   nv10_extensions, GL_FALSE );
337         driInitExtensions( NULL,   nv10_extensions, GL_FALSE );
338         driInitExtensions( NULL,   nv30_extensions, GL_FALSE );
339         driInitExtensions( NULL,   nv40_extensions, GL_FALSE );
340         driInitExtensions( NULL,   nv50_extensions, GL_FALSE );
341
342         if (!nouveauInitDriver(psp))
343                 return NULL;
344
345         return nouveauFillInModes(dri_priv->bpp,
346                                   (dri_priv->bpp == 16) ? 16 : 24,
347                                   (dri_priv->bpp == 16) ? 0  : 8,
348                                   1);
349 }
350