Merge branch 'lp-offset-twoside'
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_screen.c
index 53d00e17a12edd2a7737040375a5d5b35b682f19..a6e2186cf4370b9bd92549dea99fc78a9b468aa1 100644 (file)
-/**************************************************************************
-
-Copyright 2006 Stephane Marchesin
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-on the rights to use, copy, modify, merge, publish, distribute, sub
-license, and/or sell copies of the Software, and to permit persons to whom
-the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice (including the next
-paragraph) shall be included in all copies or substantial portions of the
-Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-ERIC ANHOLT OR SILICON INTEGRATED SYSTEMS CORP BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************/
-
-#include "glheader.h"
-#include "imports.h"
-#include "mtypes.h"
-#include "framebuffer.h"
-#include "renderbuffer.h"
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
 
+#include "nouveau_driver.h"
 #include "nouveau_context.h"
-#include "nouveau_screen.h"
-#include "nouveau_object.h"
-#include "nouveau_span.h"
-#include "nouveau_msg.h"
-
-#include "utils.h"
-#include "context.h"
-#include "vblank.h"
-#include "drirenderbuffer.h"
-
-#include "GL/internal/dri_interface.h"
-
-#include "xmlpool.h"
-
-PUBLIC const char __driConfigOptions[] =
-DRI_CONF_BEGIN
-    DRI_CONF_SECTION_DEBUG
-        DRI_CONF_NO_RAST(false)
-    DRI_CONF_SECTION_END
-DRI_CONF_END;
-static const GLuint __driNConfigOptions = 1;
-
-extern const struct dri_extension common_extensions[];
-extern const struct dri_extension nv10_extensions[];
-extern const struct dri_extension nv20_extensions[];
-extern const struct dri_extension nv30_extensions[];
-extern const struct dri_extension nv40_extensions[];
-extern const struct dri_extension nv50_extensions[];
-
-static nouveauScreenPtr nouveauCreateScreen(__DRIscreenPrivate *sPriv)
+#include "nouveau_fbo.h"
+#include "nouveau_texture.h"
+#include "nouveau_drmif.h"
+#include "nv04_driver.h"
+#include "nv10_driver.h"
+#include "nv20_driver.h"
+
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
+
+static const __DRIextension *nouveau_screen_extensions[];
+
+static void
+nouveau_destroy_screen(__DRIscreen *dri_screen);
+
+static const __DRIconfig **
+nouveau_get_configs(void)
 {
-       nouveauScreenPtr screen;
-       NOUVEAUDRIPtr dri_priv=(NOUVEAUDRIPtr)sPriv->pDevPriv;
+       __DRIconfig **configs = NULL;
+       int i;
 
-       /* allocate screen */
-       screen = (nouveauScreenPtr) CALLOC( sizeof(*screen) );
-       if ( !screen ) {         
-               __driUtilMessage("%s: Could not allocate memory for screen structure",__FUNCTION__);
-               return NULL;
+       const uint8_t depth_bits[]   = { 0, 16, 24, 24 };
+       const uint8_t stencil_bits[] = { 0,  0,  0,  8 };
+       const uint8_t msaa_samples[] = { 0 };
+
+       const struct {
+               GLenum format;
+               GLenum type;
+       } fb_formats[] = {
+               { GL_RGB , GL_UNSIGNED_SHORT_5_6_5     },
+               { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
+               { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
+       };
+
+       const GLenum back_buffer_modes[] = {
+               GLX_NONE, GLX_SWAP_UNDEFINED_OML
+       };
+
+       for (i = 0; i < Elements(fb_formats); i++) {
+               __DRIconfig **config;
+
+               config = driCreateConfigs(fb_formats[i].format,
+                                         fb_formats[i].type,
+                                         depth_bits, stencil_bits,
+                                         Elements(depth_bits),
+                                         back_buffer_modes,
+                                         Elements(back_buffer_modes),
+                                         msaa_samples,
+                                         Elements(msaa_samples),
+                                         GL_TRUE);
+               assert(config);
+
+               configs = configs ? driConcatConfigs(configs, config)
+                       : config;
        }
-       
-       screen->card=nouveau_card_lookup(dri_priv->device_id);
-       if (!screen->card) {
-               __driUtilMessage("%s: Unknown card type 0x%04x:0x%04x\n",
-                       __func__, dri_priv->device_id >> 16, dri_priv->device_id & 0xFFFF);
-               FREE(screen);
+
+       return (const __DRIconfig **)configs;
+}
+
+static const __DRIconfig **
+nouveau_init_screen2(__DRIscreen *dri_screen)
+{
+       const __DRIconfig **configs;
+       struct nouveau_screen *screen;
+       int ret;
+
+       /* Allocate the screen. */
+       screen = CALLOC_STRUCT(nouveau_screen);
+       if (!screen)
                return NULL;
+
+       dri_screen->private = screen;
+       dri_screen->extensions = nouveau_screen_extensions;
+       screen->dri_screen = dri_screen;
+
+       /* Open the DRM device. */
+       ret = nouveau_device_open_existing(&screen->device, 0, dri_screen->fd,
+                                          0);
+       if (ret) {
+               nouveau_error("Error opening the DRM device.\n");
+               goto fail;
+       }
+
+       /* Choose the card specific function pointers. */
+       switch (screen->device->chipset & 0xf0) {
+       case 0x00:
+               screen->driver = &nv04_driver;
+               break;
+       case 0x10:
+               screen->driver = &nv10_driver;
+               break;
+       case 0x20:
+               screen->driver = &nv20_driver;
+               break;
+       default:
+               assert(0);
        }
 
-       /* parse information in __driConfigOptions */
-       driParseOptionInfo (&screen->optionCache,__driConfigOptions, __driNConfigOptions);
+       configs = nouveau_get_configs();
+       if (!configs)
+               goto fail;
 
-       screen->fbFormat    = dri_priv->bpp / 8;
-       screen->frontOffset = dri_priv->front_offset;
-       screen->frontPitch  = dri_priv->front_pitch;
-       screen->backOffset  = dri_priv->back_offset;
-       screen->backPitch   = dri_priv->back_pitch;
-       screen->depthOffset = dri_priv->depth_offset;
-       screen->depthPitch  = dri_priv->depth_pitch;
+       return configs;
+fail:
+       nouveau_destroy_screen(dri_screen);
+       return NULL;
 
-       screen->driScreen = sPriv;
-       return screen;
 }
 
 static void
-nouveauDestroyScreen(__DRIscreenPrivate *sPriv)
+nouveau_destroy_screen(__DRIscreen *dri_screen)
 {
-       nouveauScreenPtr screen = (nouveauScreenPtr)sPriv->private;
+       struct nouveau_screen *screen = dri_screen->private;
 
-       if (!screen) return;
+       if (!screen)
+               return;
 
-       /* free all option information */
-       driDestroyOptionInfo (&screen->optionCache);
+       if (screen->device)
+               nouveau_device_close(&screen->device);
 
        FREE(screen);
-       sPriv->private = NULL;
-}
-
-static GLboolean nouveauInitDriver(__DRIscreenPrivate *sPriv)
-{
-       sPriv->private = (void *) nouveauCreateScreen( sPriv );
-       if ( !sPriv->private ) {
-               nouveauDestroyScreen( sPriv );
-               return GL_FALSE;
-       }
-
-       return GL_TRUE;
+       dri_screen->private = NULL;
 }
 
-/**
- * Create the Mesa framebuffer and renderbuffers for a given window/drawable.
- *
- * \todo This function (and its interface) will need to be updated to support
- * pbuffers.
- */
 static GLboolean
-nouveauCreateBuffer(__DRIscreenPrivate *driScrnPriv,
-                    __DRIdrawablePrivate *driDrawPriv,
-                    const __GLcontextModes *mesaVis,
-                    GLboolean isPixmap)
+nouveau_create_buffer(__DRIscreen *dri_screen,
+                     __DRIdrawable *drawable,
+                     const struct gl_config *visual,
+                     GLboolean is_pixmap)
 {
-       nouveauScreenPtr screen = (nouveauScreenPtr) driScrnPriv->private;
-       nouveau_renderbuffer_t *nrb;
+       struct gl_renderbuffer *rb;
        struct gl_framebuffer *fb;
-       const GLboolean swAccum = mesaVis->accumRedBits > 0;
-       const GLboolean swStencil = (mesaVis->stencilBits > 0 &&
-                                    mesaVis->depthBits != 24);
-       GLenum color_format = screen->fbFormat == 4 ? GL_RGBA8 : GL_RGB5;
+       GLenum color_format;
 
-       if (isPixmap)
+       if (is_pixmap)
                return GL_FALSE; /* not implemented */
 
-       fb = _mesa_create_framebuffer(mesaVis);
+       if (visual->redBits == 5)
+               color_format = GL_RGB5;
+       else if (visual->alphaBits == 0)
+               color_format = GL_RGB8;
+       else
+               color_format = GL_RGBA8;
+
+       fb = nouveau_framebuffer_dri_new(visual);
        if (!fb)
                return GL_FALSE;
 
-       /* Front buffer */
-       nrb = nouveau_renderbuffer_new(color_format);
-       _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &nrb->mesa);
+       /* Front buffer. */
+       rb = nouveau_renderbuffer_dri_new(color_format, drawable);
+       _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, rb);
 
-       if (mesaVis->doubleBufferMode) {
-               nrb = nouveau_renderbuffer_new(color_format);
-               _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &nrb->mesa);
+       /* Back buffer */
+       if (visual->doubleBufferMode) {
+               rb = nouveau_renderbuffer_dri_new(color_format, drawable);
+               _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, rb);
        }
 
-       if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
-               nrb = nouveau_renderbuffer_new(GL_DEPTH24_STENCIL8_EXT);
-               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
-               _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &nrb->mesa);
-       } else
-       if (mesaVis->depthBits == 24) {
-               nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT24);
-               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
-       } else
-       if (mesaVis->depthBits == 16) {
-               nrb = nouveau_renderbuffer_new(GL_DEPTH_COMPONENT16);
-               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &nrb->mesa);
+       /* Depth/stencil buffer. */
+       if (visual->depthBits == 24 && visual->stencilBits == 8) {
+               rb = nouveau_renderbuffer_dri_new(GL_DEPTH24_STENCIL8_EXT, drawable);
+               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
+               _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
+
+       } else if (visual->depthBits == 24) {
+               rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT24, drawable);
+               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
+
+       } else if (visual->depthBits == 16) {
+               rb = nouveau_renderbuffer_dri_new(GL_DEPTH_COMPONENT16, drawable);
+               _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
        }
 
-       _mesa_add_soft_renderbuffers(fb,
-                                    GL_FALSE, /* color */
-                                    GL_FALSE, /* depth */
-                                    swStencil,
-                                    swAccum,
-                                    GL_FALSE, /* alpha */
-                                    GL_FALSE  /* aux */);
+       /* Software renderbuffers. */
+       _mesa_add_soft_renderbuffers(fb, GL_FALSE, GL_FALSE, GL_FALSE,
+                                    visual->accumRedBits > 0,
+                                    GL_FALSE, GL_FALSE);
 
-       driDrawPriv->driverPrivate = (void *) fb;
-       return (driDrawPriv->driverPrivate != NULL);
-}
+       drawable->driverPrivate = fb;
 
+       return GL_TRUE;
+}
 
 static void
-nouveauDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+nouveau_destroy_buffer(__DRIdrawable *drawable)
 {
-       _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
+       _mesa_reference_framebuffer(
+               (struct gl_framebuffer **)&drawable->driverPrivate, NULL);
 }
 
-static int
-nouveauGetSwapInfo(__DRIdrawablePrivate *dpriv, __DRIswapInfo *sInfo)
+static void
+nouveau_drawable_flush(__DRIdrawable *draw)
 {
-       return -1;
 }
 
-static const struct __DriverAPIRec nouveauAPI = {
-       .DestroyScreen   = nouveauDestroyScreen,
-       .CreateContext   = nouveauCreateContext,
-       .DestroyContext  = nouveauDestroyContext,
-       .CreateBuffer    = nouveauCreateBuffer,
-       .DestroyBuffer   = nouveauDestroyBuffer,
-       .SwapBuffers     = nouveauSwapBuffers,
-       .MakeCurrent     = nouveauMakeCurrent,
-       .UnbindContext   = nouveauUnbindContext,
-       .GetSwapInfo     = nouveauGetSwapInfo,
-       .GetDrawableMSC  = driDrawableGetMSC32,
-       .WaitForMSC      = driWaitForMSC32,
-       .WaitForSBC      = NULL,
-       .SwapBuffersMSC  = NULL,
-       .CopySubBuffer   = nouveauCopySubBuffer
+static const struct __DRI2flushExtensionRec nouveau_flush_extension = {
+    { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
+    nouveau_drawable_flush,
+    dri2InvalidateDrawable,
 };
 
+static const struct __DRItexBufferExtensionRec nouveau_texbuffer_extension = {
+    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
+    NULL,
+    nouveau_set_texbuffer,
+};
 
-static __GLcontextModes *
-nouveauFillInModes( __DRIscreenPrivate *psp,
-                   unsigned pixel_bits, unsigned depth_bits,
-                   unsigned stencil_bits, GLboolean have_back_buffer )
-{
-       __GLcontextModes * modes;
-       __GLcontextModes * m;
-       unsigned num_modes;
-       unsigned depth_buffer_factor;
-       unsigned back_buffer_factor;
-       int i;
-
-       static const struct {
-               GLenum format;
-               GLenum type;
-       } fb_format_array[] = {
-               { GL_RGB , GL_UNSIGNED_SHORT_5_6_5     },
-               { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
-               { GL_BGR , GL_UNSIGNED_INT_8_8_8_8_REV },
-       };
-
-       /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
-        * support pageflipping at all.
-        */
-       static const GLenum back_buffer_modes[] = {
-               GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
-       };
-
-       u_int8_t depth_bits_array[4]   = { 0, 16, 24, 24 };
-       u_int8_t stencil_bits_array[4] = { 0,  0,  0,  8 };
-
-       depth_buffer_factor = 4;
-       back_buffer_factor  = (have_back_buffer) ? 3 : 1;
-
-       num_modes = ((pixel_bits==16) ? 1 : 2) *
-               depth_buffer_factor * back_buffer_factor * 4;
-       modes = (*psp->contextModes->createContextModes)(num_modes,
-                                                        sizeof(__GLcontextModes));
-       m = modes;
-
-       for (i=((pixel_bits==16)?0:1);i<((pixel_bits==16)?1:3);i++) {
-               if (!driFillInModes(&m, fb_format_array[i].format,
-                                       fb_format_array[i].type,
-                                       depth_bits_array,
-                                       stencil_bits_array,
-                                       depth_buffer_factor,
-                                       back_buffer_modes,
-                                       back_buffer_factor,
-                                       GLX_TRUE_COLOR)) {
-               fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
-                               __func__, __LINE__ );
-               return NULL;
-               }
-
-               if (!driFillInModes(&m, fb_format_array[i].format,
-                                       fb_format_array[i].type,
-                                       depth_bits_array,
-                                       stencil_bits_array,
-                                       depth_buffer_factor,
-                                       back_buffer_modes,
-                                       back_buffer_factor,
-                                       GLX_DIRECT_COLOR)) {
-               fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
-                               __func__, __LINE__ );
-               return NULL;
-               }
-       }
-
-       return modes;
-}
-
-
-/**
- * This is the driver specific part of the createNewScreen entry point.
- * 
- * \todo maybe fold this into intelInitDriver
- *
- * \return the __GLcontextModes supported by this driver
- */
-__GLcontextModes *__driDriverInitScreen(__DRIscreenPrivate *psp)
-{
-       static const __DRIversion ddx_expected = { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
-       static const __DRIversion dri_expected = { 4, 0, 0 };
-       static const __DRIversion drm_expected = { 0, 0, NOUVEAU_DRM_HEADER_PATCHLEVEL };
-       NOUVEAUDRIPtr dri_priv = (NOUVEAUDRIPtr)psp->pDevPriv;
-
-       WARN_ONCE("\nThis driver is not currently maintained\n\n"
-                 "Current work on 3D is in the gallium-0.1 branch of:\n"
-                 "  git://anongit.freedesktop.org/git/nouveau/mesa\n");
-
-#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 10
-#error nouveau_drm.h version does not match expected version
-#endif
-
-       if (!driCheckDriDdxDrmVersions2("nouveau",
-                                       &psp->dri_version, & dri_expected,
-                                       &psp->ddx_version, & ddx_expected,
-                                       &psp->drm_version, & drm_expected))
-               return NULL;
-
-       // temporary lock step versioning
-       if (drm_expected.patch != psp->drm_version.patch) {
-               __driUtilMessage("%s: wrong DRM version, expected %d, got %d\n",
-                                __func__,
-                                drm_expected.patch, psp->drm_version.patch);
-               return NULL;
-       }
-
-       psp->DriverAPI = nouveauAPI;
-
-       /* Calling driInitExtensions here, with a NULL context
-        * pointer, does not actually enable the extensions.  It just
-        * makes sure that all the dispatch offsets for all the
-        * extensions that *might* be enables are known.  This is
-        * needed because the dispatch offsets need to be known when
-        * _mesa_context_create is called, but we can't enable the
-        * extensions until we have a context pointer.
-        * 
-        * Hello chicken.  Hello egg.  How are you two today?
-        */
-       driInitExtensions( NULL, common_extensions, GL_FALSE );
-       driInitExtensions( NULL,   nv10_extensions, GL_FALSE );
-       driInitExtensions( NULL,   nv10_extensions, GL_FALSE );
-       driInitExtensions( NULL,   nv30_extensions, GL_FALSE );
-       driInitExtensions( NULL,   nv40_extensions, GL_FALSE );
-       driInitExtensions( NULL,   nv50_extensions, GL_FALSE );
-
-       if (!nouveauInitDriver(psp))
-               return NULL;
+static const __DRIextension *nouveau_screen_extensions[] = {
+    &nouveau_flush_extension.base,
+    &nouveau_texbuffer_extension.base,
+    &dri2ConfigQueryExtension.base,
+    NULL
+};
 
-       return nouveauFillInModes(psp,
-                                 dri_priv->bpp,
-                                 (dri_priv->bpp == 16) ? 16 : 24,
-                                 (dri_priv->bpp == 16) ? 0  : 8,
-                                 1);
-}
+const struct __DriverAPIRec driDriverAPI = {
+       .InitScreen2     = nouveau_init_screen2,
+       .DestroyScreen   = nouveau_destroy_screen,
+       .CreateBuffer    = nouveau_create_buffer,
+       .DestroyBuffer   = nouveau_destroy_buffer,
+       .CreateContext   = nouveau_context_create,
+       .DestroyContext  = nouveau_context_destroy,
+       .MakeCurrent     = nouveau_context_make_current,
+       .UnbindContext   = nouveau_context_unbind,
+};
 
+/* This is the table of extensions that the loader will dlsym() for. */
+PUBLIC const __DRIextension *__driDriverExtensions[] = {
+       &driCoreExtension.base,
+       &driDRI2Extension.base,
+       NULL
+};