nvfx: new 2D: unify textures and buffers
[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 #include "nv04_2d.h"
15
16 static void
17 nvfx_miptree_choose_format(struct nvfx_miptree *mt)
18 {
19 struct pipe_resource *pt = &mt->base.base;
20 unsigned uniform_pitch = 0;
21 static int no_swizzle = -1;
22 if(no_swizzle < 0)
23 no_swizzle = debug_get_bool_option("NV40_NO_SWIZZLE", FALSE); /* this will break things on nv30 */
24
25 if (!util_is_pot(pt->width0) ||
26 !util_is_pot(pt->height0) ||
27 !util_is_pot(pt->depth0) ||
28 (!nvfx_screen(pt->screen)->is_nv4x && pt->target == PIPE_TEXTURE_RECT)
29 )
30 uniform_pitch = 1;
31
32 if (
33 (pt->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET))
34 || (pt->usage & PIPE_USAGE_DYNAMIC) || (pt->usage & PIPE_USAGE_STAGING)
35 || util_format_is_compressed(pt->format)
36 || no_swizzle
37 )
38 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
39
40 /* non compressed formats with uniform pitch must be linear, and vice versa */
41 if(!util_format_is_s3tc(pt->format)
42 && (uniform_pitch || mt->base.base.flags & NVFX_RESOURCE_FLAG_LINEAR))
43 {
44 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
45 uniform_pitch = 1;
46 }
47
48 if(uniform_pitch)
49 {
50 mt->linear_pitch = util_format_get_stride(pt->format, pt->width0);
51
52 // TODO: this is only a constraint for rendering and not sampling, apparently
53 // we may also want this unconditionally
54 if(pt->bind & (PIPE_BIND_SAMPLER_VIEW |
55 PIPE_BIND_DEPTH_STENCIL |
56 PIPE_BIND_RENDER_TARGET |
57 PIPE_BIND_DISPLAY_TARGET |
58 PIPE_BIND_SCANOUT))
59 mt->linear_pitch = align(mt->linear_pitch, 64);
60 }
61 else
62 mt->linear_pitch = 0;
63 }
64
65 static unsigned
66 nvfx_miptree_layout(struct nvfx_miptree *mt)
67 {
68 struct pipe_resource* pt = &mt->base.base;
69 uint offset = 0;
70
71 if(!nvfx_screen(pt->screen)->is_nv4x)
72 {
73 assert(pt->target == PIPE_TEXTURE_RECT
74 || (util_is_pot(pt->width0) && util_is_pot(pt->height0)));
75 }
76
77 for (unsigned l = 0; l <= pt->last_level; l++)
78 {
79 unsigned size;
80 mt->level_offset[l] = offset;
81
82 if(mt->linear_pitch)
83 size = mt->linear_pitch;
84 else
85 size = util_format_get_stride(pt->format, u_minify(pt->width0, l));
86 size = util_format_get_2d_size(pt->format, size, u_minify(pt->height0, l));
87
88 if(pt->target == PIPE_TEXTURE_3D)
89 size *= u_minify(pt->depth0, l);
90
91 offset += size;
92 }
93
94 offset = align(offset, 128);
95 mt->face_size = offset;
96 if(mt->base.base.target == PIPE_TEXTURE_CUBE)
97 offset += 5 * mt->face_size;
98 return offset;
99 }
100
101 static void
102 nvfx_miptree_surface_final_destroy(struct pipe_surface* ps)
103 {
104 struct nvfx_surface* ns = (struct nvfx_surface*)ps;
105 pipe_resource_reference(&ps->texture, 0);
106 pipe_resource_reference((struct pipe_resource**)&ns->temp, 0);
107 FREE(ps);
108 }
109
110 void
111 nvfx_miptree_destroy(struct pipe_screen *screen, struct pipe_resource *pt)
112 {
113 struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
114 util_surfaces_destroy(&mt->surfaces, pt, nvfx_miptree_surface_final_destroy);
115 nouveau_screen_bo_release(screen, mt->base.bo);
116 FREE(mt);
117 }
118
119 static struct nvfx_miptree*
120 nvfx_miptree_create_skeleton(struct pipe_screen *pscreen, const struct pipe_resource *pt)
121 {
122 struct nvfx_miptree *mt;
123
124 if(pt->width0 > 4096 || pt->height0 > 4096)
125 return NULL;
126
127 mt = CALLOC_STRUCT(nvfx_miptree);
128 if (!mt)
129 return NULL;
130
131 mt->base.base = *pt;
132 util_dirty_surfaces_init(&mt->dirty_surfaces);
133
134 pipe_reference_init(&mt->base.base.reference, 1);
135 mt->base.base.screen = pscreen;
136
137 // set this to the actual capabilities, we use it to decide whether to use the 3D engine for copies
138 // TODO: is this the correct way to use Gallium?
139 mt->base.base.bind = pt->bind | PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
140
141 // on our current driver (and the driver too), format support does not depend on geometry, so don't bother computing it
142 // TODO: may want to revisit this
143 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_RENDER_TARGET, 0))
144 mt->base.base.bind &=~ PIPE_BIND_RENDER_TARGET;
145 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_SAMPLER_VIEW, 0))
146 mt->base.base.bind &=~ PIPE_BIND_SAMPLER_VIEW;
147 if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_DEPTH_STENCIL, 0))
148 mt->base.base.bind &=~ PIPE_BIND_DEPTH_STENCIL;
149
150 return mt;
151 }
152
153
154 struct pipe_resource *
155 nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt)
156 {
157 struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, pt);
158 nvfx_miptree_choose_format(mt);
159
160 unsigned size = nvfx_miptree_layout(mt);
161
162 mt->base.bo = nouveau_screen_bo_new(pscreen, 256, pt->usage, pt->bind, size);
163
164 if (!mt->base.bo) {
165 FREE(mt);
166 return NULL;
167 }
168 return &mt->base.base;
169 }
170
171 // TODO: redo this, just calling miptree_layout
172 struct pipe_resource *
173 nvfx_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle)
174 {
175 struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, template);
176 if(whandle->stride) {
177 mt->linear_pitch = whandle->stride;
178 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
179 } else
180 nvfx_miptree_choose_format(mt);
181
182 nvfx_miptree_layout(mt);
183
184 unsigned stride;
185 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
186 if (mt->base.bo == NULL) {
187 FREE(mt);
188 return NULL;
189 }
190 return &mt->base.base;
191 }
192
193 struct pipe_surface *
194 nvfx_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_resource *pt,
195 unsigned face, unsigned level, unsigned zslice,
196 unsigned flags)
197 {
198 struct nvfx_miptree* mt = (struct nvfx_miptree*)pt;
199 struct nvfx_surface *ns;
200
201 ns = (struct nvfx_surface*)util_surfaces_get(&mt->surfaces, sizeof(struct nvfx_surface), pscreen, pt, face, level, zslice, flags);
202 if(ns->base.base.offset == ~0) {
203 util_dirty_surface_init(&ns->base);
204 ns->pitch = nvfx_subresource_pitch(pt, level);
205 ns->base.base.offset = nvfx_subresource_offset(pt, face, level, zslice);
206 }
207
208 return &ns->base.base;
209 }
210
211 void
212 nvfx_miptree_surface_del(struct pipe_surface *ps)
213 {
214 struct nvfx_surface* ns = (struct nvfx_surface*)ps;
215
216 if(!ns->temp)
217 {
218 util_surfaces_detach(&((struct nvfx_miptree*)ps->texture)->surfaces, ps);
219 pipe_resource_reference(&ps->texture, 0);
220 FREE(ps);
221 }
222 }