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"
15 nvfx_miptree_choose_format(struct nvfx_miptree
*mt
)
17 struct pipe_resource
*pt
= &mt
->base
.base
;
18 unsigned uniform_pitch
= 0;
19 static int no_swizzle
= -1;
21 no_swizzle
= debug_get_bool_option("NV40_NO_SWIZZLE", FALSE
); /* this will break things on nv30 */
23 if (!util_is_power_of_two(pt
->width0
) ||
24 !util_is_power_of_two(pt
->height0
) ||
25 !util_is_power_of_two(pt
->depth0
) ||
26 (!nvfx_screen(pt
->screen
)->is_nv4x
&& pt
->target
== PIPE_TEXTURE_RECT
)
31 (pt
->bind
& (PIPE_BIND_SCANOUT
| PIPE_BIND_DISPLAY_TARGET
))
32 || (pt
->usage
& PIPE_USAGE_DYNAMIC
) || (pt
->usage
& PIPE_USAGE_STAGING
)
33 || util_format_is_compressed(pt
->format
)
36 mt
->base
.base
.flags
|= NOUVEAU_RESOURCE_FLAG_LINEAR
;
38 /* non compressed formats with uniform pitch must be linear, and vice versa */
39 if(!util_format_is_s3tc(pt
->format
)
40 && (uniform_pitch
|| mt
->base
.base
.flags
& NOUVEAU_RESOURCE_FLAG_LINEAR
))
42 mt
->base
.base
.flags
|= NOUVEAU_RESOURCE_FLAG_LINEAR
;
48 mt
->linear_pitch
= util_format_get_stride(pt
->format
, pt
->width0
);
50 // TODO: this is only a constraint for rendering and not sampling, apparently
51 // we may also want this unconditionally
52 if(pt
->bind
& (PIPE_BIND_SAMPLER_VIEW
|
53 PIPE_BIND_DEPTH_STENCIL
|
54 PIPE_BIND_RENDER_TARGET
|
55 PIPE_BIND_DISPLAY_TARGET
|
57 mt
->linear_pitch
= align(mt
->linear_pitch
, 64);
64 nvfx_miptree_layout(struct nvfx_miptree
*mt
)
66 struct pipe_resource
* pt
= &mt
->base
.base
;
69 if(!nvfx_screen(pt
->screen
)->is_nv4x
)
71 assert(pt
->target
== PIPE_TEXTURE_RECT
72 || (util_is_power_of_two(pt
->width0
) && util_is_power_of_two(pt
->height0
)));
75 for (unsigned l
= 0; l
<= pt
->last_level
; l
++)
78 mt
->level_offset
[l
] = offset
;
81 size
= mt
->linear_pitch
;
83 size
= util_format_get_stride(pt
->format
, u_minify(pt
->width0
, l
));
84 size
= util_format_get_2d_size(pt
->format
, size
, u_minify(pt
->height0
, l
));
86 if(pt
->target
== PIPE_TEXTURE_3D
)
87 size
*= u_minify(pt
->depth0
, l
);
92 offset
= align(offset
, 128);
93 mt
->face_size
= offset
;
94 if(mt
->base
.base
.target
== PIPE_TEXTURE_CUBE
)
95 offset
+= 5 * mt
->face_size
;
100 nvfx_miptree_surface_final_destroy(struct pipe_surface
* ps
)
102 pipe_resource_reference(&ps
->texture
, 0);
107 nvfx_miptree_destroy(struct pipe_screen
*screen
, struct pipe_resource
*pt
)
109 struct nvfx_miptree
*mt
= (struct nvfx_miptree
*)pt
;
110 util_surfaces_destroy(&mt
->surfaces
, pt
, nvfx_miptree_surface_final_destroy
);
111 nouveau_screen_bo_release(screen
, mt
->base
.bo
);
115 static struct nvfx_miptree
*
116 nvfx_miptree_create_skeleton(struct pipe_screen
*pscreen
, const struct pipe_resource
*pt
)
118 struct nvfx_miptree
*mt
;
120 if(pt
->width0
> 4096 || pt
->height0
> 4096)
123 mt
= CALLOC_STRUCT(nvfx_miptree
);
129 pipe_reference_init(&mt
->base
.base
.reference
, 1);
130 mt
->base
.base
.screen
= pscreen
;
132 // set this to the actual capabilities, we use it to decide whether to use the 3D engine for copies
133 // TODO: is this the correct way to use Gallium?
134 mt
->base
.base
.bind
= pt
->bind
| PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_DEPTH_STENCIL
;
136 // on our current driver (and the driver too), format support does not depend on geometry, so don't bother computing it
137 // TODO: may want to revisit this
138 if(!pscreen
->is_format_supported(pscreen
, pt
->format
, pt
->target
, 0, PIPE_BIND_RENDER_TARGET
))
139 mt
->base
.base
.bind
&=~ PIPE_BIND_RENDER_TARGET
;
140 if(!pscreen
->is_format_supported(pscreen
, pt
->format
, pt
->target
, 0, PIPE_BIND_SAMPLER_VIEW
))
141 mt
->base
.base
.bind
&=~ PIPE_BIND_SAMPLER_VIEW
;
142 if(!pscreen
->is_format_supported(pscreen
, pt
->format
, pt
->target
, 0, PIPE_BIND_DEPTH_STENCIL
))
143 mt
->base
.base
.bind
&=~ PIPE_BIND_DEPTH_STENCIL
;
149 struct pipe_resource
*
150 nvfx_miptree_create(struct pipe_screen
*pscreen
, const struct pipe_resource
*pt
)
152 struct nvfx_miptree
* mt
= nvfx_miptree_create_skeleton(pscreen
, pt
);
154 nvfx_miptree_choose_format(mt
);
156 size
= nvfx_miptree_layout(mt
);
158 mt
->base
.bo
= nouveau_screen_bo_new(pscreen
, 256, pt
->usage
, pt
->bind
, size
);
164 return &mt
->base
.base
;
167 // TODO: redo this, just calling miptree_layout
168 struct pipe_resource
*
169 nvfx_miptree_from_handle(struct pipe_screen
*pscreen
, const struct pipe_resource
*template, struct winsys_handle
*whandle
)
171 struct nvfx_miptree
* mt
= nvfx_miptree_create_skeleton(pscreen
, template);
173 if(whandle
->stride
) {
174 mt
->linear_pitch
= whandle
->stride
;
175 mt
->base
.base
.flags
|= NOUVEAU_RESOURCE_FLAG_LINEAR
;
177 nvfx_miptree_choose_format(mt
);
179 nvfx_miptree_layout(mt
);
181 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, whandle
, &stride
);
182 if (mt
->base
.bo
== NULL
) {
186 return &mt
->base
.base
;
189 struct pipe_surface
*
190 nvfx_miptree_surface_new(struct pipe_context
*pipe
, struct pipe_resource
*pt
,
191 const struct pipe_surface
*surf_tmpl
)
193 struct nvfx_miptree
*mt
= (struct nvfx_miptree
*)pt
;
194 unsigned level
= surf_tmpl
->u
.tex
.level
;
195 struct nvfx_surface
*ns
= NULL
;
197 assert(surf_tmpl
->u
.tex
.first_layer
== surf_tmpl
->u
.tex
.last_layer
);
198 if(util_surfaces_get(&mt
->surfaces
, sizeof(struct nvfx_surface
), pipe
,
199 pt
, level
, surf_tmpl
->u
.tex
.first_layer
,
200 surf_tmpl
->usage
, (struct pipe_surface
**)&ns
)) {
201 ns
->pitch
= nvfx_subresource_pitch(pt
, level
);
202 ns
->offset
= nvfx_subresource_offset(pt
, surf_tmpl
->u
.tex
.first_layer
, level
, surf_tmpl
->u
.tex
.first_layer
);
209 nvfx_miptree_surface_del(struct pipe_context
*pipe
, struct pipe_surface
*ps
)
211 util_surfaces_detach(&((struct nvfx_miptree
*)ps
->texture
)->surfaces
, ps
);
212 pipe_resource_reference(&ps
->texture
, 0);