Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / drivers / nv40 / nv40_miptree.c
1 #include "pipe/p_state.h"
2 #include "pipe/p_defines.h"
3 #include "pipe/p_inlines.h"
4 #include "util/u_format.h"
5 #include "util/u_math.h"
6
7 #include "nv40_context.h"
8
9
10
11 static void
12 nv40_miptree_layout(struct nv40_miptree *mt)
13 {
14 struct pipe_texture *pt = &mt->base;
15 uint width = pt->width0;
16 uint offset = 0;
17 int nr_faces, l, f;
18 uint wide_pitch = pt->tex_usage & (PIPE_TEXTURE_USAGE_SAMPLER |
19 PIPE_TEXTURE_USAGE_DEPTH_STENCIL |
20 PIPE_TEXTURE_USAGE_RENDER_TARGET |
21 PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
22 PIPE_TEXTURE_USAGE_PRIMARY);
23
24 if (pt->target == PIPE_TEXTURE_CUBE) {
25 nr_faces = 6;
26 } else
27 if (pt->target == PIPE_TEXTURE_3D) {
28 nr_faces = pt->depth0;
29 } else {
30 nr_faces = 1;
31 }
32
33 for (l = 0; l <= pt->last_level; l++) {
34 if (wide_pitch && (pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR))
35 mt->level[l].pitch = align(util_format_get_stride(pt->format, pt->width0), 64);
36 else
37 mt->level[l].pitch = util_format_get_stride(pt->format, width);
38
39 mt->level[l].image_offset =
40 CALLOC(nr_faces, sizeof(unsigned));
41
42 width = u_minify(width, 1);
43 }
44
45 for (f = 0; f < nr_faces; f++) {
46 for (l = 0; l < pt->last_level; l++) {
47 mt->level[l].image_offset[f] = offset;
48
49 if (!(pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR) &&
50 u_minify(pt->width0, l + 1) > 1 && u_minify(pt->height0, l + 1) > 1)
51 offset += align(mt->level[l].pitch * u_minify(pt->height0, l), 64);
52 else
53 offset += mt->level[l].pitch * u_minify(pt->height0, l);
54 }
55
56 mt->level[l].image_offset[f] = offset;
57 offset += mt->level[l].pitch * u_minify(pt->height0, l);
58 }
59
60 mt->total_size = offset;
61 }
62
63 static struct pipe_texture *
64 nv40_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt)
65 {
66 struct nv40_miptree *mt;
67 unsigned buf_usage = PIPE_BUFFER_USAGE_PIXEL |
68 NOUVEAU_BUFFER_USAGE_TEXTURE;
69
70 mt = MALLOC(sizeof(struct nv40_miptree));
71 if (!mt)
72 return NULL;
73 mt->base = *pt;
74 pipe_reference_init(&mt->base.reference, 1);
75 mt->base.screen = pscreen;
76
77 /* Swizzled textures must be POT */
78 if (pt->width0 & (pt->width0 - 1) ||
79 pt->height0 & (pt->height0 - 1))
80 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
81 else
82 if (pt->tex_usage & (PIPE_TEXTURE_USAGE_PRIMARY |
83 PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
84 PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
85 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
86 else
87 if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
88 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
89 else {
90 switch (pt->format) {
91 /* TODO: Figure out which formats can be swizzled */
92 case PIPE_FORMAT_A8R8G8B8_UNORM:
93 case PIPE_FORMAT_X8R8G8B8_UNORM:
94 case PIPE_FORMAT_R16_SNORM:
95 {
96 if (debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE))
97 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
98 break;
99 }
100 default:
101 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
102 }
103 }
104
105 if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
106 buf_usage |= PIPE_BUFFER_USAGE_CPU_READ_WRITE;
107
108 nv40_miptree_layout(mt);
109
110 mt->buffer = pscreen->buffer_create(pscreen, 256, buf_usage, mt->total_size);
111 if (!mt->buffer) {
112 FREE(mt);
113 return NULL;
114 }
115 mt->bo = nouveau_bo(mt->buffer);
116 return &mt->base;
117 }
118
119 static struct pipe_texture *
120 nv40_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt,
121 const unsigned *stride, struct pipe_buffer *pb)
122 {
123 struct nv40_miptree *mt;
124
125 /* Only supports 2D, non-mipmapped textures for the moment */
126 if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 ||
127 pt->depth0 != 1)
128 return NULL;
129
130 mt = CALLOC_STRUCT(nv40_miptree);
131 if (!mt)
132 return NULL;
133
134 mt->base = *pt;
135 pipe_reference_init(&mt->base.reference, 1);
136 mt->base.screen = pscreen;
137 mt->level[0].pitch = stride[0];
138 mt->level[0].image_offset = CALLOC(1, sizeof(unsigned));
139
140 /* Assume whoever created this buffer expects it to be linear for now */
141 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
142
143 pipe_buffer_reference(&mt->buffer, pb);
144 mt->bo = nouveau_bo(mt->buffer);
145 return &mt->base;
146 }
147
148 static void
149 nv40_miptree_destroy(struct pipe_texture *pt)
150 {
151 struct nv40_miptree *mt = (struct nv40_miptree *)pt;
152 int l;
153
154 pipe_buffer_reference(&mt->buffer, NULL);
155 for (l = 0; l <= pt->last_level; l++) {
156 if (mt->level[l].image_offset)
157 FREE(mt->level[l].image_offset);
158 }
159
160 FREE(mt);
161 }
162
163 static struct pipe_surface *
164 nv40_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
165 unsigned face, unsigned level, unsigned zslice,
166 unsigned flags)
167 {
168 struct nv40_miptree *mt = (struct nv40_miptree *)pt;
169 struct nv04_surface *ns;
170
171 ns = CALLOC_STRUCT(nv04_surface);
172 if (!ns)
173 return NULL;
174 pipe_texture_reference(&ns->base.texture, pt);
175 ns->base.format = pt->format;
176 ns->base.width = u_minify(pt->width0, level);
177 ns->base.height = u_minify(pt->height0, level);
178 ns->base.usage = flags;
179 pipe_reference_init(&ns->base.reference, 1);
180 ns->base.face = face;
181 ns->base.level = level;
182 ns->base.zslice = zslice;
183 ns->pitch = mt->level[level].pitch;
184
185 if (pt->target == PIPE_TEXTURE_CUBE) {
186 ns->base.offset = mt->level[level].image_offset[face];
187 } else
188 if (pt->target == PIPE_TEXTURE_3D) {
189 ns->base.offset = mt->level[level].image_offset[zslice];
190 } else {
191 ns->base.offset = mt->level[level].image_offset[0];
192 }
193
194 return &ns->base;
195 }
196
197 static void
198 nv40_miptree_surface_del(struct pipe_surface *ps)
199 {
200 pipe_texture_reference(&ps->texture, NULL);
201 FREE(ps);
202 }
203
204 void
205 nv40_screen_init_miptree_functions(struct pipe_screen *pscreen)
206 {
207 pscreen->texture_create = nv40_miptree_create;
208 pscreen->texture_blanket = nv40_miptree_blanket;
209 pscreen->texture_destroy = nv40_miptree_destroy;
210 pscreen->get_tex_surface = nv40_miptree_surface_new;
211 pscreen->tex_surface_destroy = nv40_miptree_surface_del;
212 }
213