r600g: atomize stencil ref state
[mesa.git] / src / gallium / drivers / r600 / r600_texture.c
index acb77d5c4dd48d34e0832f3ca0589c3ccb041c33..6de3d6a8645aae6a2678dc295864a73e25bcb427 100644 (file)
@@ -252,13 +252,15 @@ static const struct u_resource_vtbl r600_texture_vtbl =
        NULL                            /* transfer_inline_write */
 };
 
-static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
-                                       struct r600_texture *rtex)
+/* The number of samples can be specified independently of the texture. */
+void r600_texture_get_fmask_info(struct r600_screen *rscreen,
+                                struct r600_texture *rtex,
+                                unsigned nr_samples,
+                                struct r600_fmask_info *out)
 {
        /* FMASK is allocated pretty much like an ordinary texture.
         * Here we use bpe in the units of bits, not bytes. */
        struct radeon_surface fmask = rtex->surface;
-       unsigned nr_samples = rtex->resource.b.b.nr_samples;
 
        switch (nr_samples) {
        case 2:
@@ -282,6 +284,11 @@ static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
                return;
        }
 
+       /* R600-R700 errata? Anyway, this fixes colorbuffer corruption. */
+       if (rscreen->chip_class <= R700) {
+               fmask.bpe *= 2;
+       }
+
        if (rscreen->chip_class >= EVERGREEN) {
                fmask.bankh = nr_samples <= 4 ? 4 : 1;
        }
@@ -292,10 +299,23 @@ static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
        }
        assert(fmask.level[0].mode == RADEON_SURF_MODE_2D);
 
+       out->bank_height = fmask.bankh;
+       out->alignment = MAX2(256, fmask.bo_alignment);
+       out->size = (fmask.bo_size + 7) / 8;
+}
+
+static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
+                                       struct r600_texture *rtex)
+{
+       struct r600_fmask_info fmask;
+
+       r600_texture_get_fmask_info(rscreen, rtex,
+                                   rtex->resource.b.b.nr_samples, &fmask);
+
        /* Reserve space for FMASK while converting bits back to bytes. */
-       rtex->fmask_bank_height = fmask.bankh;
-       rtex->fmask_offset = align(rtex->size, MAX2(256, fmask.bo_alignment));
-       rtex->fmask_size = (fmask.bo_size + 7) / 8;
+       rtex->fmask_bank_height = fmask.bank_height;
+       rtex->fmask_offset = align(rtex->size, fmask.alignment);
+       rtex->fmask_size = fmask.size;
        rtex->size = rtex->fmask_offset + rtex->fmask_size;
 #if 0
        printf("FMASK width=%u, height=%i, bits=%u, size=%u\n",
@@ -303,8 +323,9 @@ static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
 #endif
 }
 
-static void r600_texture_allocate_cmask(struct r600_screen *rscreen,
-                                       struct r600_texture *rtex)
+void r600_texture_get_cmask_info(struct r600_screen *rscreen,
+                                struct r600_texture *rtex,
+                                struct r600_cmask_info *out)
 {
        unsigned cmask_tile_width = 8;
        unsigned cmask_tile_height = 8;
@@ -326,14 +347,25 @@ static void r600_texture_allocate_cmask(struct r600_screen *rscreen,
        unsigned base_align = num_pipes * pipe_interleave_bytes;
        unsigned slice_bytes =
                ((pitch_elements * height * element_bits + 7) / 8) / cmask_tile_elements;
-       unsigned size = rtex->surface.array_size * align(slice_bytes, base_align);
 
        assert(macro_tile_width % 128 == 0);
        assert(macro_tile_height % 128 == 0);
 
-       rtex->cmask_slice_tile_max = ((pitch_elements * height) / (128*128)) - 1;
-       rtex->cmask_offset = align(rtex->size, MAX2(256, base_align));
-       rtex->cmask_size = size;
+       out->slice_tile_max = ((pitch_elements * height) / (128*128)) - 1;
+       out->alignment = MAX2(256, base_align);
+       out->size = rtex->surface.array_size * align(slice_bytes, base_align);
+}
+
+static void r600_texture_allocate_cmask(struct r600_screen *rscreen,
+                                       struct r600_texture *rtex)
+{
+       struct r600_cmask_info cmask;
+
+       r600_texture_get_cmask_info(rscreen, rtex, &cmask);
+
+       rtex->cmask_slice_tile_max = cmask.slice_tile_max;
+       rtex->cmask_offset = align(rtex->size, cmask.alignment);
+       rtex->cmask_size = cmask.size;
        rtex->size = rtex->cmask_offset + rtex->cmask_size;
 #if 0
        printf("CMASK: macro tile width = %u, macro tile height = %u, "
@@ -379,8 +411,8 @@ r600_texture_create_object(struct pipe_screen *screen,
        }
 
        if (base->nr_samples > 1 && !rtex->is_depth && alloc_bo) {
-               r600_texture_allocate_fmask(rscreen, rtex);
                r600_texture_allocate_cmask(rscreen, rtex);
+               r600_texture_allocate_fmask(rscreen, rtex);
        }
 
        if (!rtex->is_depth && base->nr_samples > 1 &&
@@ -474,6 +506,9 @@ static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
 static void r600_surface_destroy(struct pipe_context *pipe,
                                 struct pipe_surface *surface)
 {
+       struct r600_surface *surf = (struct r600_surface*)surface;
+       pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_fmask, NULL);
+       pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_cmask, NULL);
        pipe_resource_reference(&surface->texture, NULL);
        FREE(surface);
 }