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