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