Merge commit 'origin/7.8'
[mesa.git] / src / gallium / drivers / nvfx / nvfx_transfer.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 "nouveau/nouveau_winsys.h"
8 #include "nvfx_context.h"
9 #include "nvfx_screen.h"
10 #include "nvfx_state.h"
11 #include "nvfx_resource.h"
12 #include "nvfx_transfer.h"
13
14 struct nvfx_transfer {
15 struct pipe_transfer base;
16 struct pipe_surface *surface;
17 boolean direct;
18 };
19
20 static void
21 nvfx_compatible_transfer_tex(struct pipe_resource *pt, unsigned width, unsigned height,
22 unsigned bind,
23 struct pipe_resource *template)
24 {
25 memset(template, 0, sizeof(struct pipe_resource));
26 template->target = pt->target;
27 template->format = pt->format;
28 template->width0 = width;
29 template->height0 = height;
30 template->depth0 = 1;
31 template->last_level = 0;
32 template->nr_samples = pt->nr_samples;
33 template->bind = bind;
34 template->_usage = PIPE_USAGE_DYNAMIC;
35 template->flags = NVFX_RESOURCE_FLAG_LINEAR;
36 }
37
38
39 static unsigned nvfx_transfer_bind_flags( unsigned transfer_usage )
40 {
41 unsigned bind = 0;
42
43 if (transfer_usage & PIPE_TRANSFER_WRITE)
44 bind |= PIPE_BIND_BLIT_DESTINATION;
45
46 if (transfer_usage & PIPE_TRANSFER_READ)
47 bind |= PIPE_BIND_BLIT_SOURCE;
48
49 return bind;
50 }
51
52 struct pipe_transfer *
53 nvfx_miptree_transfer_new(struct pipe_context *pipe,
54 struct pipe_resource *pt,
55 struct pipe_subresource sr,
56 unsigned usage,
57 const struct pipe_box *box)
58 {
59 struct pipe_screen *pscreen = pipe->screen;
60 struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
61 struct nvfx_transfer *tx;
62 struct pipe_resource tx_tex_template, *tx_tex;
63 static int no_transfer = -1;
64 unsigned bind = nvfx_transfer_bind_flags(usage);
65 if(no_transfer < 0)
66 no_transfer = debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/);
67
68
69 tx = CALLOC_STRUCT(nvfx_transfer);
70 if (!tx)
71 return NULL;
72
73 /* Don't handle 3D transfers yet.
74 */
75 assert(box->depth == 1);
76
77 pipe_resource_reference(&tx->base.resource, pt);
78 tx->base.sr = sr;
79 tx->base.usage = usage;
80 tx->base.box = *box;
81 tx->base.stride = mt->level[sr.level].pitch;
82
83 /* Direct access to texture */
84 if ((pt->_usage == PIPE_USAGE_DYNAMIC ||
85 no_transfer) &&
86 pt->flags & NVFX_RESOURCE_FLAG_LINEAR)
87 {
88 tx->direct = true;
89
90 /* XXX: just call the internal nvfx function.
91 */
92 tx->surface = pscreen->get_tex_surface(pscreen, pt,
93 sr.face, sr.level,
94 box->z,
95 bind);
96 return &tx->base;
97 }
98
99 tx->direct = false;
100
101 nvfx_compatible_transfer_tex(pt, box->width, box->height, bind, &tx_tex_template);
102
103 tx_tex = pscreen->resource_create(pscreen, &tx_tex_template);
104 if (!tx_tex)
105 {
106 FREE(tx);
107 return NULL;
108 }
109
110 tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch;
111
112 tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
113 0, 0, 0,
114 bind);
115
116 pipe_resource_reference(&tx_tex, NULL);
117
118 if (!tx->surface)
119 {
120 pipe_surface_reference(&tx->surface, NULL);
121 FREE(tx);
122 return NULL;
123 }
124
125 if (usage & PIPE_TRANSFER_READ) {
126 struct nvfx_screen *nvscreen = nvfx_screen(pscreen);
127 struct pipe_surface *src;
128
129 src = pscreen->get_tex_surface(pscreen, pt,
130 sr.face, sr.level, box->z,
131 PIPE_BIND_BLIT_SOURCE);
132
133 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
134 /* TODO: Check if SIFM can un-swizzle */
135 nvscreen->eng2d->copy(nvscreen->eng2d,
136 tx->surface, 0, 0,
137 src,
138 box->x, box->y,
139 box->width, box->height);
140
141 pipe_surface_reference(&src, NULL);
142 }
143
144 return &tx->base;
145 }
146
147 void
148 nvfx_miptree_transfer_del(struct pipe_context *pipe,
149 struct pipe_transfer *ptx)
150 {
151 struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
152
153 if (!tx->direct && (ptx->usage & PIPE_TRANSFER_WRITE)) {
154 struct pipe_screen *pscreen = pipe->screen;
155 struct nvfx_screen *nvscreen = nvfx_screen(pscreen);
156 struct pipe_surface *dst;
157
158 dst = pscreen->get_tex_surface(pscreen,
159 ptx->resource,
160 ptx->sr.face,
161 ptx->sr.level,
162 ptx->box.z,
163 PIPE_BIND_BLIT_DESTINATION);
164
165 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
166 nvscreen->eng2d->copy(nvscreen->eng2d,
167 dst, ptx->box.x, ptx->box.y,
168 tx->surface, 0, 0,
169 ptx->box.width, ptx->box.height);
170
171 pipe_surface_reference(&dst, NULL);
172 }
173
174 pipe_surface_reference(&tx->surface, NULL);
175 pipe_resource_reference(&ptx->resource, NULL);
176 FREE(ptx);
177 }
178
179 void *
180 nvfx_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
181 {
182 struct pipe_screen *pscreen = pipe->screen;
183 struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
184 struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
185 struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
186 uint8_t *map = nouveau_screen_bo_map(pscreen, mt->base.bo,
187 nouveau_screen_transfer_flags(ptx->usage));
188
189 if(!tx->direct)
190 return map + ns->base.offset;
191 else
192 return (map + ns->base.offset +
193 ptx->box.y * ns->pitch +
194 ptx->box.x * util_format_get_blocksize(ptx->resource->format));
195 }
196
197 void
198 nvfx_miptree_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx)
199 {
200 struct pipe_screen *pscreen = pipe->screen;
201 struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
202 struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
203
204 nouveau_screen_bo_unmap(pscreen, mt->base.bo);
205 }