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_math.h"
7 #include "nvfx_context.h"
8 #include "nvfx_resource.h"
9 #include "nvfx_transfer.h"
10 #include "nv04_surface_2d.h"
12 /* Currently using separate implementations for buffers and textures,
13 * even though gallium has a unified abstraction of these objects.
14 * Eventually these should be combined, and mechanisms like transfers
15 * be adapted to work for both buffer and texture uploads.
19 nvfx_miptree_layout(struct nvfx_miptree
*mt
)
21 struct pipe_resource
*pt
= &mt
->base
.base
;
22 uint width
= pt
->width0
;
25 uint wide_pitch
= pt
->bind
& (PIPE_BIND_SAMPLER_VIEW
|
26 PIPE_BIND_DEPTH_STENCIL
|
27 PIPE_BIND_RENDER_TARGET
|
28 PIPE_BIND_DISPLAY_TARGET
|
31 if (pt
->target
== PIPE_TEXTURE_CUBE
) {
34 if (pt
->target
== PIPE_TEXTURE_3D
) {
35 nr_faces
= pt
->depth0
;
40 for (l
= 0; l
<= pt
->last_level
; l
++) {
41 if (wide_pitch
&& (pt
->flags
& NVFX_RESOURCE_FLAG_LINEAR
))
42 mt
->level
[l
].pitch
= align(util_format_get_stride(pt
->format
, pt
->width0
), 64);
44 mt
->level
[l
].pitch
= util_format_get_stride(pt
->format
, width
);
46 mt
->level
[l
].image_offset
=
47 CALLOC(nr_faces
, sizeof(unsigned));
49 width
= u_minify(width
, 1);
52 for (f
= 0; f
< nr_faces
; f
++) {
53 for (l
= 0; l
< pt
->last_level
; l
++) {
54 mt
->level
[l
].image_offset
[f
] = offset
;
56 if (!(pt
->flags
& NVFX_RESOURCE_FLAG_LINEAR
) &&
57 u_minify(pt
->width0
, l
+ 1) > 1 && u_minify(pt
->height0
, l
+ 1) > 1)
58 offset
+= align(mt
->level
[l
].pitch
* u_minify(pt
->height0
, l
), 64);
60 offset
+= mt
->level
[l
].pitch
* u_minify(pt
->height0
, l
);
63 mt
->level
[l
].image_offset
[f
] = offset
;
64 offset
+= mt
->level
[l
].pitch
* u_minify(pt
->height0
, l
);
67 mt
->total_size
= offset
;
71 nvfx_miptree_get_handle(struct pipe_screen
*pscreen
,
72 struct pipe_resource
*ptexture
,
73 struct winsys_handle
*whandle
)
75 struct nvfx_miptree
* mt
= (struct nvfx_miptree
*)ptexture
;
77 if (!mt
|| !mt
->base
.bo
)
80 return nouveau_screen_bo_get_handle(pscreen
,
88 nvfx_miptree_destroy(struct pipe_screen
*screen
, struct pipe_resource
*pt
)
90 struct nvfx_miptree
*mt
= (struct nvfx_miptree
*)pt
;
93 nouveau_screen_bo_release(screen
, mt
->base
.bo
);
95 for (l
= 0; l
<= pt
->last_level
; l
++) {
96 if (mt
->level
[l
].image_offset
)
97 FREE(mt
->level
[l
].image_offset
);
106 struct u_resource_vtbl nvfx_miptree_vtbl
=
108 nvfx_miptree_get_handle
, /* get_handle */
109 nvfx_miptree_destroy
, /* resource_destroy */
110 NULL
, /* is_resource_referenced */
111 nvfx_miptree_transfer_new
, /* get_transfer */
112 nvfx_miptree_transfer_del
, /* transfer_destroy */
113 nvfx_miptree_transfer_map
, /* transfer_map */
114 u_default_transfer_flush_region
, /* transfer_flush_region */
115 nvfx_miptree_transfer_unmap
, /* transfer_unmap */
116 u_default_transfer_inline_write
/* transfer_inline_write */
121 struct pipe_resource
*
122 nvfx_miptree_create(struct pipe_screen
*pscreen
, const struct pipe_resource
*pt
)
124 struct nvfx_miptree
*mt
;
125 static int no_swizzle
= -1;
127 no_swizzle
= debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE
);
129 mt
= CALLOC_STRUCT(nvfx_miptree
);
134 mt
->base
.vtbl
= &nvfx_miptree_vtbl
;
135 pipe_reference_init(&mt
->base
.base
.reference
, 1);
136 mt
->base
.base
.screen
= pscreen
;
138 /* Swizzled textures must be POT */
139 if (pt
->width0
& (pt
->width0
- 1) ||
140 pt
->height0
& (pt
->height0
- 1))
141 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
143 if (pt
->bind
& (PIPE_BIND_SCANOUT
|
144 PIPE_BIND_DISPLAY_TARGET
|
145 PIPE_BIND_DEPTH_STENCIL
))
146 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
148 if (pt
->_usage
== PIPE_USAGE_DYNAMIC
)
149 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
151 switch (pt
->format
) {
152 case PIPE_FORMAT_B5G6R5_UNORM
:
153 case PIPE_FORMAT_L8A8_UNORM
:
154 case PIPE_FORMAT_A8_UNORM
:
155 case PIPE_FORMAT_L8_UNORM
:
156 case PIPE_FORMAT_I8_UNORM
:
157 /* TODO: we can actually swizzle these formats on nv40, we
158 are just preserving the pre-unification behavior.
159 The whole 2D code is going to be rewritten anyway. */
160 if(nvfx_screen(pscreen
)->is_nv4x
) {
161 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
164 /* TODO: Figure out which formats can be swizzled */
165 case PIPE_FORMAT_B8G8R8A8_UNORM
:
166 case PIPE_FORMAT_B8G8R8X8_UNORM
:
167 case PIPE_FORMAT_R16_SNORM
:
170 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
174 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
178 /* apparently we can't render to swizzled surfaces smaller than 64 bytes, so make them linear.
179 * If the user did not ask for a render target, they can still render to it, but it will cost them an extra copy.
180 * This also happens for small mipmaps of large textures. */
181 if (pt
->bind
& PIPE_BIND_RENDER_TARGET
&&
182 util_format_get_stride(pt
->format
, pt
->width0
) < 64)
183 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
185 nvfx_miptree_layout(mt
);
187 mt
->base
.bo
= nouveau_screen_bo_new(pscreen
, 256,
188 pt
->_usage
, pt
->bind
, mt
->total_size
);
193 return &mt
->base
.base
;
199 struct pipe_resource
*
200 nvfx_miptree_from_handle(struct pipe_screen
*pscreen
,
201 const struct pipe_resource
*template,
202 struct winsys_handle
*whandle
)
204 struct nvfx_miptree
*mt
;
207 /* Only supports 2D, non-mipmapped textures for the moment */
208 if (template->target
!= PIPE_TEXTURE_2D
||
209 template->last_level
!= 0 ||
210 template->depth0
!= 1)
213 mt
= CALLOC_STRUCT(nvfx_miptree
);
217 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, whandle
, &stride
);
218 if (mt
->base
.bo
== NULL
) {
223 mt
->base
.base
= *template;
224 mt
->base
.vtbl
= &nvfx_miptree_vtbl
;
225 pipe_reference_init(&mt
->base
.base
.reference
, 1);
226 mt
->base
.base
.screen
= pscreen
;
227 mt
->level
[0].pitch
= stride
;
228 mt
->level
[0].image_offset
= CALLOC(1, sizeof(unsigned));
230 /* Assume whoever created this buffer expects it to be linear for now */
231 mt
->base
.base
.flags
|= NVFX_RESOURCE_FLAG_LINEAR
;
233 /* XXX: Need to adjust bo refcount??
235 /* nouveau_bo_ref(bo, &mt->base.bo); */
236 return &mt
->base
.base
;
243 /* Surface helpers, not strictly required to implement the resource vtbl:
245 struct pipe_surface
*
246 nvfx_miptree_surface_new(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
,
247 unsigned face
, unsigned level
, unsigned zslice
,
250 struct nvfx_miptree
*mt
= (struct nvfx_miptree
*)pt
;
251 struct nv04_surface
*ns
;
253 ns
= CALLOC_STRUCT(nv04_surface
);
256 pipe_resource_reference(&ns
->base
.texture
, pt
);
257 ns
->base
.format
= pt
->format
;
258 ns
->base
.width
= u_minify(pt
->width0
, level
);
259 ns
->base
.height
= u_minify(pt
->height0
, level
);
260 ns
->base
.usage
= flags
;
261 pipe_reference_init(&ns
->base
.reference
, 1);
262 ns
->base
.face
= face
;
263 ns
->base
.level
= level
;
264 ns
->base
.zslice
= zslice
;
265 ns
->pitch
= mt
->level
[level
].pitch
;
267 if (pt
->target
== PIPE_TEXTURE_CUBE
) {
268 ns
->base
.offset
= mt
->level
[level
].image_offset
[face
];
270 if (pt
->target
== PIPE_TEXTURE_3D
) {
271 ns
->base
.offset
= mt
->level
[level
].image_offset
[zslice
];
273 ns
->base
.offset
= mt
->level
[level
].image_offset
[0];
276 /* create a linear temporary that we can render into if
279 * Note that ns->pitch is always a multiple of 64 for linear
280 * surfaces and swizzled surfaces are POT, so ns->pitch & 63
281 * is equivalent to (ns->pitch < 64 && swizzled)
284 if ((ns
->pitch
& 63) &&
285 (ns
->base
.usage
& PIPE_BIND_RENDER_TARGET
))
287 struct nv04_surface_2d
* eng2d
=
288 ((struct nvfx_screen
*)pscreen
)->eng2d
;
290 ns
= nv04_surface_wrap_for_render(pscreen
, eng2d
, ns
);
297 nvfx_miptree_surface_del(struct pipe_surface
*ps
)
299 struct nv04_surface
* ns
= (struct nv04_surface
*)ps
;
302 struct nvfx_screen
* screen
= (struct nvfx_screen
*)ps
->texture
->screen
;
303 if(ns
->backing
->base
.usage
& PIPE_BIND_BLIT_DESTINATION
)
304 screen
->eng2d
->copy(screen
->eng2d
, &ns
->backing
->base
, 0, 0, ps
, 0, 0, ns
->base
.width
, ns
->base
.height
);
305 nvfx_miptree_surface_del(&ns
->backing
->base
);
308 pipe_resource_reference(&ps
->texture
, NULL
);