nv50_miptree.c revision 93ce4c99d4c4515b8f8c4e999af53c8196b5f9eb
1/* 2 * Copyright 2008 Ben Skeggs 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "pipe/p_state.h" 24#include "pipe/p_defines.h" 25#include "pipe/p_inlines.h" 26 27#include "nv50_context.h" 28 29static struct pipe_texture * 30nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp) 31{ 32 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 33 struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); 34 struct pipe_texture *pt = &mt->base; 35 unsigned width = tmp->width[0], height = tmp->height[0]; 36 unsigned depth = tmp->depth[0]; 37 uint32_t tile_mode, tile_flags, tile_h; 38 int ret, i, l; 39 40 mt->base = *tmp; 41 pipe_reference_init(&mt->base.reference, 1); 42 mt->base.screen = pscreen; 43 44 switch (pt->format) { 45 case PIPE_FORMAT_Z32_FLOAT: 46 tile_flags = 0x4800; 47 break; 48 case PIPE_FORMAT_Z24S8_UNORM: 49 tile_flags = 0x1800; 50 break; 51 case PIPE_FORMAT_X8Z24_UNORM: 52 case PIPE_FORMAT_S8Z24_UNORM: 53 tile_flags = 0x2800; 54 break; 55 default: 56 tile_flags = 0x7000; 57 break; 58 } 59 60 if (pt->height[0] > 32) tile_mode = 4; 61 else if (pt->height[0] > 16) tile_mode = 3; 62 else if (pt->height[0] > 8) tile_mode = 2; 63 else if (pt->height[0] > 4) tile_mode = 1; 64 else tile_mode = 0; 65 tile_h = 1 << (tile_mode + 2); 66 67 switch (pt->target) { 68 case PIPE_TEXTURE_3D: 69 mt->image_nr = pt->depth[0]; 70 break; 71 case PIPE_TEXTURE_CUBE: 72 mt->image_nr = 6; 73 break; 74 default: 75 mt->image_nr = 1; 76 break; 77 } 78 79 for (l = 0; l <= pt->last_level; l++) { 80 struct nv50_miptree_level *lvl = &mt->level[l]; 81 82 pt->width[l] = width; 83 pt->height[l] = height; 84 pt->depth[l] = depth; 85 pt->nblocksx[l] = pf_get_nblocksx(&pt->block, width); 86 pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height); 87 88 lvl->image_offset = CALLOC(mt->image_nr, sizeof(int)); 89 lvl->pitch = align(pt->width[l] * pt->block.size, 64); 90 lvl->tile_mode = tile_mode; 91 92 width = MAX2(1, width >> 1); 93 height = MAX2(1, height >> 1); 94 depth = MAX2(1, depth >> 1); 95 96 if (tile_mode && height <= (tile_h >> 1)) { 97 tile_mode--; 98 tile_h >>= 1; 99 } 100 } 101 102 for (i = 0; i < mt->image_nr; i++) { 103 for (l = 0; l <= pt->last_level; l++) { 104 struct nv50_miptree_level *lvl = &mt->level[l]; 105 int size; 106 tile_h = 1 << (lvl->tile_mode + 2); 107 108 size = align(pt->width[l], 8) * pt->block.size; 109 size = align(size, 64); 110 size *= align(pt->height[l], tile_h); 111 112 lvl->image_offset[i] = mt->total_size; 113 114 mt->total_size += size; 115 } 116 } 117 118 ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 256, mt->total_size, 119 mt->level[0].tile_mode, tile_flags, &mt->bo); 120 if (ret) { 121 FREE(mt); 122 return NULL; 123 } 124 125 return &mt->base; 126} 127 128static struct pipe_texture * 129nv50_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt, 130 const unsigned *stride, struct pipe_buffer *pb) 131{ 132 struct nouveau_bo *bo = nouveau_bo(pb); 133 struct nv50_miptree *mt; 134 135 /* Only supports 2D, non-mipmapped textures for the moment */ 136 if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 || 137 pt->depth[0] != 1) 138 return NULL; 139 140 mt = CALLOC_STRUCT(nv50_miptree); 141 if (!mt) 142 return NULL; 143 144 mt->base = *pt; 145 pipe_reference_init(&mt->base.reference, 1); 146 mt->base.screen = pscreen; 147 mt->image_nr = 1; 148 mt->level[0].pitch = *stride; 149 mt->level[0].image_offset = CALLOC(1, sizeof(unsigned)); 150 151 nouveau_bo_ref(bo, &mt->bo); 152 return &mt->base; 153} 154 155static void 156nv50_miptree_destroy(struct pipe_texture *pt) 157{ 158 struct nv50_miptree *mt = nv50_miptree(pt); 159 160 nouveau_bo_ref(NULL, &mt->bo); 161 FREE(mt); 162} 163 164static struct pipe_surface * 165nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt, 166 unsigned face, unsigned level, unsigned zslice, 167 unsigned flags) 168{ 169 struct nv50_miptree *mt = nv50_miptree(pt); 170 struct nv50_miptree_level *lvl = &mt->level[level]; 171 struct pipe_surface *ps; 172 int img; 173 174 if (pt->target == PIPE_TEXTURE_CUBE) 175 img = face; 176 else 177 if (pt->target == PIPE_TEXTURE_3D) 178 img = zslice; 179 else 180 img = 0; 181 182 ps = CALLOC_STRUCT(pipe_surface); 183 if (!ps) 184 return NULL; 185 pipe_texture_reference(&ps->texture, pt); 186 ps->format = pt->format; 187 ps->width = pt->width[level]; 188 ps->height = pt->height[level]; 189 ps->usage = flags; 190 pipe_reference_init(&ps->reference, 1); 191 ps->face = face; 192 ps->level = level; 193 ps->zslice = zslice; 194 ps->offset = lvl->image_offset[img]; 195 196 return ps; 197} 198 199static void 200nv50_miptree_surface_del(struct pipe_surface *ps) 201{ 202 struct nv50_surface *s = nv50_surface(ps); 203 204 pipe_texture_reference(&ps->texture, NULL); 205 FREE(s); 206} 207 208void 209nv50_screen_init_miptree_functions(struct pipe_screen *pscreen) 210{ 211 pscreen->texture_create = nv50_miptree_create; 212 pscreen->texture_blanket = nv50_miptree_blanket; 213 pscreen->texture_destroy = nv50_miptree_destroy; 214 pscreen->get_tex_surface = nv50_miptree_surface_new; 215 pscreen->tex_surface_destroy = nv50_miptree_surface_del; 216} 217 218