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"
16 nvfx_miptree_choose_format(struct nvfx_miptree
*mt
)
18 struct pipe_resource
*pt
= &mt
->base
.base
;
19 unsigned uniform_pitch
= 0;
20 static int no_swizzle
= -1;
22 no_swizzle
= debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE
);
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)
31 /* All texture formats except compressed ones can be swizzled
32 * Unsure about depth, let's prevent swizzling for now
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
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
)
49 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
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
))
55 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
61 mt
->linear_pitch
= util_format_get_stride(pt
->format
, pt
->width0
);
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
|
70 mt
->linear_pitch
= align(mt
->linear_pitch
, 64);
77 nvfx_miptree_layout(struct nvfx_miptree
*mt
)
79 struct pipe_resource
* pt
= &mt
->base
.base
;
82 if(!nvfx_screen(pt
->screen
)->is_nv4x
)
84 assert(pt
->target
== PIPE_TEXTURE_RECT
85 || (util_is_pot(pt
->width0
) && util_is_pot(pt
->height0
)));
88 for (unsigned l
= 0; l
<= pt
->last_level
; l
++)
91 mt
->level_offset
[l
] = offset
;
94 size
= mt
->linear_pitch
;
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
));
99 if(pt
->target
== PIPE_TEXTURE_3D
)
100 size
*= u_minify(pt
->depth0
, l
);
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
;
113 nvfx_miptree_get_handle(struct pipe_screen
*pscreen
,
114 struct pipe_resource
*ptexture
,
115 struct winsys_handle
*whandle
)
117 struct nvfx_miptree
* mt
= (struct nvfx_miptree
*)ptexture
;
119 if (!mt
|| !mt
->base
.bo
)
122 return nouveau_screen_bo_get_handle(pscreen
,
130 nvfx_miptree_destroy(struct pipe_screen
*screen
, struct pipe_resource
*pt
)
132 struct nvfx_miptree
*mt
= (struct nvfx_miptree
*)pt
;
133 nouveau_screen_bo_release(screen
, mt
->base
.bo
);
140 struct u_resource_vtbl nvfx_miptree_vtbl
=
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 */
153 static struct nvfx_miptree
*
154 nvfx_miptree_create_skeleton(struct pipe_screen
*pscreen
, const struct pipe_resource
*pt
)
156 struct nvfx_miptree
*mt
;
158 if(pt
->width0
> 4096 || pt
->height0
> 4096)
161 mt
= CALLOC_STRUCT(nvfx_miptree
);
166 mt
->base
.vtbl
= &nvfx_miptree_vtbl
;
167 pipe_reference_init(&mt
->base
.base
.reference
, 1);
168 mt
->base
.base
.screen
= pscreen
;
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
;
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
;
187 struct pipe_resource
*
188 nvfx_miptree_create(struct pipe_screen
*pscreen
, const struct pipe_resource
*pt
)
190 struct nvfx_miptree
* mt
= nvfx_miptree_create_skeleton(pscreen
, pt
);
191 nvfx_miptree_choose_format(mt
);
193 unsigned size
= nvfx_miptree_layout(mt
);
195 mt
->base
.bo
= nouveau_screen_bo_new(pscreen
, 256, pt
->usage
, pt
->bind
, size
);
201 return &mt
->base
.base
;
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
)
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
;
213 nvfx_miptree_choose_format(mt
);
215 nvfx_miptree_layout(mt
);
218 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, whandle
, &stride
);
219 if (mt
->base
.bo
== NULL
) {
223 return &mt
->base
.base
;
226 /* Surface helpers, not strictly required to implement the resource vtbl:
228 struct pipe_surface
*
229 nvfx_miptree_surface_new(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
,
230 unsigned face
, unsigned level
, unsigned zslice
,
233 struct nvfx_surface
*ns
;
235 ns
= CALLOC_STRUCT(nvfx_surface
);
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
);
254 nvfx_miptree_surface_del(struct pipe_surface
*ps
)
256 pipe_resource_reference(&ps
->texture
, NULL
);