nouveau: Map correct mip level when using the shadow (nv30, nv40).
[mesa.git] / src / gallium / drivers / nv40 / nv40_screen.c
index c64c3b1c39da4e8cd06b2ca09be619ba3e57d286..ab128fecda7bedda6ff919508b6c8055febf2a97 100644 (file)
@@ -1,5 +1,4 @@
 #include "pipe/p_screen.h"
-#include "pipe/p_util.h"
 
 #include "nv40_context.h"
 #include "nv40_screen.h"
@@ -12,9 +11,10 @@ static const char *
 nv40_screen_get_name(struct pipe_screen *pscreen)
 {
        struct nv40_screen *screen = nv40_screen(pscreen);
+       struct nouveau_device *dev = screen->nvws->channel->device;
        static char buffer[128];
 
-       snprintf(buffer, sizeof(buffer), "NV%02X", screen->chipset);
+       snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset);
        return buffer;
 }
 
@@ -56,6 +56,11 @@ nv40_screen_get_param(struct pipe_screen *pscreen, int param)
                return 10;
        case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
                return 13;
+       case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
+       case PIPE_CAP_TEXTURE_MIRROR_REPEAT:
+               return 1;
+       case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS:
+               return 0; /* We have 4 - but unsupported currently */
        case NOUVEAU_CAP_HW_VTXBUF:
                return 1;
        case NOUVEAU_CAP_HW_IDXBUF:
@@ -82,8 +87,6 @@ nv40_screen_get_paramf(struct pipe_screen *pscreen, int param)
                return 16.0;
        case PIPE_CAP_MAX_TEXTURE_LOD_BIAS:
                return 16.0;
-       case PIPE_CAP_BITMAP_TEXCOORD_BIAS:
-               return 0.0;
        default:
                NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param);
                return 0.0;
@@ -92,10 +95,11 @@ nv40_screen_get_paramf(struct pipe_screen *pscreen, int param)
 
 static boolean
 nv40_screen_surface_format_supported(struct pipe_screen *pscreen,
-                                    enum pipe_format format, uint type)
+                                    enum pipe_format format,
+                                    enum pipe_texture_target target,
+                                    unsigned tex_usage, unsigned geom_flags)
 {
-       switch (type) {
-       case PIPE_SURFACE:
+       if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) {
                switch (format) {
                case PIPE_FORMAT_A8R8G8B8_UNORM:
                case PIPE_FORMAT_R5G6B5_UNORM: 
@@ -105,17 +109,17 @@ nv40_screen_surface_format_supported(struct pipe_screen *pscreen,
                default:
                        break;
                }
-               break;
-       case PIPE_TEXTURE:
+       } else {
                switch (format) {
                case PIPE_FORMAT_A8R8G8B8_UNORM:
                case PIPE_FORMAT_A1R5G5B5_UNORM:
                case PIPE_FORMAT_A4R4G4B4_UNORM:
-               case PIPE_FORMAT_R5G6B5_UNORM: 
-               case PIPE_FORMAT_U_L8:
-               case PIPE_FORMAT_U_A8:
-               case PIPE_FORMAT_U_I8:
-               case PIPE_FORMAT_U_A8_L8:
+               case PIPE_FORMAT_R5G6B5_UNORM:
+               case PIPE_FORMAT_R16_SNORM:
+               case PIPE_FORMAT_L8_UNORM:
+               case PIPE_FORMAT_A8_UNORM:
+               case PIPE_FORMAT_I8_UNORM:
+               case PIPE_FORMAT_A8L8_UNORM:
                case PIPE_FORMAT_Z16_UNORM:
                case PIPE_FORMAT_Z24S8_UNORM:
                case PIPE_FORMAT_DXT1_RGB:
@@ -126,14 +130,86 @@ nv40_screen_surface_format_supported(struct pipe_screen *pscreen,
                default:
                        break;
                }
-               break;
-       default:
-               assert(0);
-       };
+       }
 
        return FALSE;
 }
 
+static void *
+nv40_surface_map(struct pipe_screen *screen, struct pipe_surface *surface,
+                unsigned flags )
+{
+       struct pipe_winsys      *ws = screen->winsys;
+       struct pipe_surface     *surface_to_map;
+       void                    *map;
+
+       if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) {
+               struct nv40_miptree *mt = (struct nv40_miptree *)surface->texture;
+
+               if (!mt->shadow_tex) {
+                       unsigned old_tex_usage = surface->texture->tex_usage;
+                       surface->texture->tex_usage = NOUVEAU_TEXTURE_USAGE_LINEAR |
+                                                     PIPE_TEXTURE_USAGE_DYNAMIC;
+                       mt->shadow_tex = screen->texture_create(screen, surface->texture);
+                       surface->texture->tex_usage = old_tex_usage;
+
+                       assert(mt->shadow_tex->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR);
+               }
+
+               mt->shadow_surface = screen->get_tex_surface
+               (
+                       screen, mt->shadow_tex,
+                       surface->face, surface->level, surface->zslice,
+                       surface->usage
+               );
+
+               surface_to_map = mt->shadow_surface;
+       }
+       else
+               surface_to_map = surface;
+
+       assert(surface_to_map);
+
+       map = ws->buffer_map(ws, surface_to_map->buffer, flags);
+       if (!map)
+               return NULL;
+
+       return map + surface_to_map->offset;
+}
+
+static void
+nv40_surface_unmap(struct pipe_screen *screen, struct pipe_surface *surface)
+{
+       struct pipe_winsys      *ws = screen->winsys;
+       struct pipe_surface     *surface_to_unmap;
+
+       /* TODO: Copy from shadow just before push buffer is flushed instead.
+                There are probably some programs that map/unmap excessively
+                before rendering. */
+       if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) {
+               struct nv40_miptree *mt = (struct nv40_miptree *)surface->texture;
+
+               assert(mt->shadow_tex);
+
+               surface_to_unmap = mt->shadow_surface;
+       }
+       else
+               surface_to_unmap = surface;
+
+       assert(surface_to_unmap);
+
+       ws->buffer_unmap(ws, surface_to_unmap->buffer);
+
+       if (surface_to_unmap != surface) {
+               struct nv40_screen *nvscreen = nv40_screen(screen);
+
+               nvscreen->nvws->surface_copy(nvscreen->nvws,
+                                            surface, 0, 0,
+                                            surface_to_unmap, 0, 0,
+                                            surface->width, surface->height);
+       }
+}
+
 static void
 nv40_screen_destroy(struct pipe_screen *pscreen)
 {
@@ -151,17 +227,16 @@ nv40_screen_destroy(struct pipe_screen *pscreen)
 }
 
 struct pipe_screen *
-nv40_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws,
-                  unsigned chipset)
+nv40_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws)
 {
        struct nv40_screen *screen = CALLOC_STRUCT(nv40_screen);
        struct nouveau_stateobj *so;
        unsigned curie_class;
+       unsigned chipset = nvws->channel->device->chipset;
        int ret;
 
        if (!screen)
                return NULL;
-       screen->chipset = chipset;
        screen->nvws = nvws;
 
        /* 3D object */
@@ -284,6 +359,9 @@ nv40_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws,
 
        screen->pipe.is_format_supported = nv40_screen_surface_format_supported;
 
+       screen->pipe.surface_map = nv40_surface_map;
+       screen->pipe.surface_unmap = nv40_surface_unmap;
+
        nv40_screen_init_miptree_functions(&screen->pipe);
 
        return &screen->pipe;