OSDN Git Service

Merge branch 'radeon-rewrite' of git+ssh://agd5f@git.freedesktop.org/git/mesa/mesa...
[android-x86/external-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
5 #include "nv40_context.h"
6
7 static void
8 nv40_miptree_layout(struct nv40_miptree *mt)
9 {
10         struct pipe_texture *pt = &mt->base;
11         uint width = pt->width[0], height = pt->height[0], depth = pt->depth[0];
12         uint offset = 0;
13         int nr_faces, l, f;
14         uint wide_pitch = pt->tex_usage & (PIPE_TEXTURE_USAGE_SAMPLER |
15                                            PIPE_TEXTURE_USAGE_DEPTH_STENCIL |
16                                            PIPE_TEXTURE_USAGE_RENDER_TARGET |
17                                            PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
18                                            PIPE_TEXTURE_USAGE_PRIMARY);
19
20         if (pt->target == PIPE_TEXTURE_CUBE) {
21                 nr_faces = 6;
22         } else
23         if (pt->target == PIPE_TEXTURE_3D) {
24                 nr_faces = pt->depth[0];
25         } else {
26                 nr_faces = 1;
27         }
28
29         for (l = 0; l <= pt->last_level; l++) {
30                 pt->width[l] = width;
31                 pt->height[l] = height;
32                 pt->depth[l] = depth;
33                 pt->nblocksx[l] = pf_get_nblocksx(&pt->block, width);
34                 pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height);
35
36                 if (wide_pitch && (pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR))
37                         mt->level[l].pitch = align(pt->width[0] * pt->block.size, 64);
38                 else
39                         mt->level[l].pitch = pt->width[l] * pt->block.size;
40
41                 mt->level[l].image_offset =
42                         CALLOC(nr_faces, sizeof(unsigned));
43
44                 width  = MAX2(1, width  >> 1);
45                 height = MAX2(1, height >> 1);
46                 depth  = MAX2(1, depth  >> 1);
47         }
48
49         for (f = 0; f < nr_faces; f++) {
50                 for (l = 0; l < pt->last_level; l++) {
51                         mt->level[l].image_offset[f] = offset;
52
53                         if (!(pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR) &&
54                             pt->width[l + 1] > 1 && pt->height[l + 1] > 1)
55                                 offset += align(mt->level[l].pitch * pt->height[l], 64);
56                         else
57                                 offset += mt->level[l].pitch * pt->height[l];
58                 }
59
60                 mt->level[l].image_offset[f] = offset;
61                 offset += mt->level[l].pitch * pt->height[l];
62         }
63
64         mt->total_size = offset;
65 }
66
67 static struct pipe_texture *
68 nv40_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt)
69 {
70         struct nv40_miptree *mt;
71         unsigned buf_usage = PIPE_BUFFER_USAGE_PIXEL |
72                              NOUVEAU_BUFFER_USAGE_TEXTURE;
73
74         mt = MALLOC(sizeof(struct nv40_miptree));
75         if (!mt)
76                 return NULL;
77         mt->base = *pt;
78         pipe_reference_init(&mt->base.reference, 1);
79         mt->base.screen = pscreen;
80
81         /* Swizzled textures must be POT */
82         if (pt->width[0] & (pt->width[0] - 1) ||
83             pt->height[0] & (pt->height[0] - 1))
84                 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
85         else
86         if (pt->tex_usage & (PIPE_TEXTURE_USAGE_PRIMARY |
87                              PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
88                              PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
89                 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
90         else
91         if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
92                 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
93         else {
94                 switch (pt->format) {
95                 /* TODO: Figure out which formats can be swizzled */
96                 case PIPE_FORMAT_A8R8G8B8_UNORM:
97                 case PIPE_FORMAT_X8R8G8B8_UNORM:
98                 case PIPE_FORMAT_R16_SNORM:
99                 {
100                         if (debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE))
101                                 mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
102                         break;
103                 }
104                 default:
105                         mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
106                 }
107         }
108
109         if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
110                 buf_usage |= PIPE_BUFFER_USAGE_CPU_READ_WRITE;
111
112         nv40_miptree_layout(mt);
113
114         mt->buffer = pscreen->buffer_create(pscreen, 256, buf_usage, mt->total_size);
115         if (!mt->buffer) {
116                 FREE(mt);
117                 return NULL;
118         }
119
120         return &mt->base;
121 }
122
123 static struct pipe_texture *
124 nv40_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt,
125                      const unsigned *stride, struct pipe_buffer *pb)
126 {
127         struct nv40_miptree *mt;
128
129         /* Only supports 2D, non-mipmapped textures for the moment */
130         if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 ||
131             pt->depth[0] != 1)
132                 return NULL;
133
134         mt = CALLOC_STRUCT(nv40_miptree);
135         if (!mt)
136                 return NULL;
137
138         mt->base = *pt;
139         pipe_reference_init(&mt->base.reference, 1);
140         mt->base.screen = pscreen;
141         mt->level[0].pitch = stride[0];
142         mt->level[0].image_offset = CALLOC(1, sizeof(unsigned));
143
144         pipe_buffer_reference(&mt->buffer, pb);
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 = pt->width[level];
177         ns->base.height = pt->height[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