nv30: new 2D: support ARB_texture_rectangle
[mesa.git] / src / gallium / drivers / nvfx / nvfx_miptree.c
1 #include "pipe/p_state.h"
2 #include "pipe/p_defines.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5 #include "util/u_memory.h"
6 #include "util/u_math.h"
7 #include "util/u_staging.h"
8 #include "state_tracker/drm_driver.h"
9 #include "nouveau/nouveau_winsys.h"
10 #include "nouveau/nouveau_screen.h"
11 #include "nvfx_screen.h"
12 #include "nvfx_resource.h"
13 #include "nvfx_transfer.h"
14
15 static void
16 nvfx_miptree_choose_format(struct nvfx_miptree *mt)
17 {
18 struct pipe_resource *pt = &mt->base.base;
19 unsigned uniform_pitch = 0;
20 static int no_swizzle = -1;
21 if(no_swizzle < 0)
22 no_swizzle = debug_get_bool_option("NV40_NO_SWIZZLE", FALSE); /* this will break things on nv30 */
23
24 if (!util_is_pot(pt->width0) ||
25 !util_is_pot(pt->height0) ||
26 !util_is_pot(pt->depth0) ||
27 (!nvfx_screen(pt->screen)->is_nv4x && pt->target == PIPE_TEXTURE_RECT)
28 )
29 uniform_pitch = 1;
30
31 if (
32 (pt->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET))
33 || (pt->usage & PIPE_USAGE_DYNAMIC) || (pt->usage & PIPE_USAGE_STAGING)
34 || util_format_is_compressed(pt->format)
35 || no_swizzle
36 )
37 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
38
39 /* non compressed formats with uniform pitch must be linear, and vice versa */
40 if(!util_format_is_s3tc(pt->format)
41 && (uniform_pitch || mt->base.base.flags & NVFX_RESOURCE_FLAG_LINEAR))
42 {
43 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
44 uniform_pitch = 1;
45 }
46
47 if(uniform_pitch)
48 {
49 mt->linear_pitch = util_format_get_stride(pt->format, pt->width0);
50
51 // TODO: this is only a constraint for rendering and not sampling, apparently
52 // we may also want this unconditionally
53 if(pt->bind & (PIPE_BIND_SAMPLER_VIEW |
54 PIPE_BIND_DEPTH_STENCIL |
55 PIPE_BIND_RENDER_TARGET |
56 PIPE_BIND_DISPLAY_TARGET |
57 PIPE_BIND_SCANOUT))
58 mt->linear_pitch = align(mt->linear_pitch, 64);
59 }
60 else
61 mt->linear_pitch = 0;
62 }
63
64 static unsigned
65 nvfx_miptree_layout(struct nvfx_miptree *mt)
66 {
67 struct pipe_resource* pt = &mt->base.base;
68 uint offset = 0;
69
70 if(!nvfx_screen(pt->screen)->is_nv4x)
71 {
72 assert(pt->target == PIPE_TEXTURE_RECT
73 || (util_is_pot(pt->width0) && util_is_pot(pt->height0)));
74 }
75
76 for (unsigned l = 0; l <= pt->last_level; l++)
77 {
78 unsigned size;
79 mt->level_offset[l] = offset;
80
81 if(mt->linear_pitch)
82 size = mt->linear_pitch;
83 else
84 size = util_format_get_stride(pt->format, u_minify(pt->width0, l));
85 size = util_format_get_2d_size(pt->format, size, u_minify(pt->height0, l));
86
87 if(pt->target == PIPE_TEXTURE_3D)
88 size *= u_minify(pt->depth0, l);
89
90 offset += size;
91 }
92
93 offset = align(offset, 128);
94 mt->face_size = offset;
95 if(mt->base.base.target == PIPE_TEXTURE_CUBE)
96 offset += 5 * mt->face_size;
97 return offset;
98 }
99
100 static boolean
101 nvfx_miptree_get_handle(struct pipe_screen *pscreen,
102 struct pipe_resource *ptexture,
103 struct winsys_handle *whandle)
104 {
105 struct nvfx_miptree* mt = (struct nvfx_miptree*)ptexture;
106
107 if (!mt || !mt->base.bo)
108 return FALSE;
109
110 return nouveau_screen_bo_get_handle(pscreen,
111 mt->base.bo,
112 mt->linear_pitch,
113 whandle);
114 }
115
116
117 static void
118 nvfx_miptree_destroy(struct pipe_screen *screen, struct pipe_resource *pt)
119 {
120 struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
121 nouveau_screen_bo_release(screen, mt->base.bo);
122 FREE(mt);
123 }
124
125
126
127
128 struct u_resource_vtbl nvfx_miptree_vtbl =
129 {
130 nvfx_miptree_get_handle, /* get_handle */
131 nvfx_miptree_destroy, /* resource_destroy */
132 NULL, /* is_resource_referenced */
133 nvfx_transfer_new, /* get_transfer */
134 util_staging_transfer_destroy, /* transfer_destroy */
135 nvfx_transfer_map, /* transfer_map */
136 u_default_transfer_flush_region, /* transfer_flush_region */
137 nvfx_transfer_unmap, /* transfer_unmap */
138 u_default_transfer_inline_write /* transfer_inline_write */
139 };
140
141 static struct nvfx_miptree*
142 nvfx_miptree_create_skeleton(struct pipe_screen *pscreen, const struct pipe_resource *pt)
143 {
144 struct nvfx_miptree *mt;
145
146 if(pt->width0 > 4096 || pt->height0 > 4096)
147 return NULL;
148
149 mt = CALLOC_STRUCT(nvfx_miptree);
150 if (!mt)
151 return NULL;
152
153 mt->base.base = *pt;
154 mt->base.vtbl = &nvfx_miptree_vtbl;
155 pipe_reference_init(&mt->base.base.reference, 1);
156 mt->base.base.screen = pscreen;
157
158 // set this to the actual capabilities, we use it to decide whether to use the 3D engine for copies
159 // TODO: is this the correct way to use Gallium?
160 mt->base.base.bind = pt->bind | PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
161
162 // on our current driver (and the driver too), format support does not depend on geometry, so don't bother computing it
163 // TODO: may want to revisit this
164 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_RENDER_TARGET, 0))
165 mt->base.base.bind &=~ PIPE_BIND_RENDER_TARGET;
166 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_SAMPLER_VIEW, 0))
167 mt->base.base.bind &=~ PIPE_BIND_SAMPLER_VIEW;
168 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_DEPTH_STENCIL, 0))
169 mt->base.base.bind &=~ PIPE_BIND_DEPTH_STENCIL;
170
171 return mt;
172 }
173
174
175 struct pipe_resource *
176 nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt)
177 {
178 struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, pt);
179 nvfx_miptree_choose_format(mt);
180
181 unsigned size = nvfx_miptree_layout(mt);
182
183 mt->base.bo = nouveau_screen_bo_new(pscreen, 256, pt->usage, pt->bind, size);
184
185 if (!mt->base.bo) {
186 FREE(mt);
187 return NULL;
188 }
189 return &mt->base.base;
190 }
191
192 // TODO: redo this, just calling miptree_layout
193 struct pipe_resource *
194 nvfx_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle)
195 {
196 struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, template);
197 if(whandle->stride) {
198 mt->linear_pitch = whandle->stride;
199 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
200 } else
201 nvfx_miptree_choose_format(mt);
202
203 nvfx_miptree_layout(mt);
204
205 unsigned stride;
206 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
207 if (mt->base.bo == NULL) {
208 FREE(mt);
209 return NULL;
210 }
211 return &mt->base.base;
212 }
213
214 /* Surface helpers, not strictly required to implement the resource vtbl:
215 */
216 struct pipe_surface *
217 nvfx_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_resource *pt,
218 unsigned face, unsigned level, unsigned zslice,
219 unsigned flags)
220 {
221 struct nvfx_surface *ns;
222
223 ns = CALLOC_STRUCT(nvfx_surface);
224 if (!ns)
225 return NULL;
226 pipe_resource_reference(&ns->base.texture, pt);
227 ns->base.format = pt->format;
228 ns->base.width = u_minify(pt->width0, level);
229 ns->base.height = u_minify(pt->height0, level);
230 ns->base.usage = flags;
231 pipe_reference_init(&ns->base.reference, 1);
232 ns->base.face = face;
233 ns->base.level = level;
234 ns->base.zslice = zslice;
235 ns->pitch = nvfx_subresource_pitch(pt, level);
236 ns->base.offset = nvfx_subresource_offset(pt, face, level, zslice);
237
238 return &ns->base;
239 }
240
241 void
242 nvfx_miptree_surface_del(struct pipe_surface *ps)
243 {
244 pipe_resource_reference(&ps->texture, NULL);
245 FREE(ps);
246 }