Merge remote branch 'main/master' into radeon-rewrite
[mesa.git] / src / gallium / drivers / nv10 / nv10_transfer.c
1 #include <pipe/p_state.h>
2 #include <pipe/p_defines.h>
3 #include <pipe/p_inlines.h>
4 #include <util/u_memory.h>
5 #include <nouveau/nouveau_winsys.h>
6 #include "nv10_context.h"
7 #include "nv10_screen.h"
8 #include "nv10_state.h"
9
10 struct nv10_transfer {
11 struct pipe_transfer base;
12 struct pipe_surface *surface;
13 bool direct;
14 };
15
16 static unsigned nv10_usage_tx_to_buf(unsigned tx_usage)
17 {
18 switch (tx_usage) {
19 case PIPE_TRANSFER_READ:
20 return PIPE_BUFFER_USAGE_CPU_READ;
21 case PIPE_TRANSFER_WRITE:
22 return PIPE_BUFFER_USAGE_CPU_WRITE;
23 case PIPE_TRANSFER_READ_WRITE:
24 return PIPE_BUFFER_USAGE_CPU_READ_WRITE;
25 default:
26 assert(0);
27 }
28
29 return -1;
30 }
31
32 static void
33 nv10_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
34 struct pipe_texture *template)
35 {
36 memset(template, 0, sizeof(struct pipe_texture));
37 template->target = pt->target;
38 template->format = pt->format;
39 template->width[0] = pt->width[level];
40 template->height[0] = pt->height[level];
41 template->depth[0] = 1;
42 template->block = pt->block;
43 template->nblocksx[0] = pt->nblocksx[level];
44 template->nblocksy[0] = pt->nblocksx[level];
45 template->last_level = 0;
46 template->compressed = pt->compressed;
47 template->nr_samples = pt->nr_samples;
48
49 template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC |
50 NOUVEAU_TEXTURE_USAGE_LINEAR;
51 }
52
53 static struct pipe_transfer *
54 nv10_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
55 unsigned face, unsigned level, unsigned zslice,
56 enum pipe_transfer_usage usage,
57 unsigned x, unsigned y, unsigned w, unsigned h)
58 {
59 struct nv10_miptree *mt = (struct nv10_miptree *)pt;
60 struct nv10_transfer *tx;
61 struct pipe_texture tx_tex_template, *tx_tex;
62
63 tx = CALLOC_STRUCT(nv10_transfer);
64 if (!tx)
65 return NULL;
66
67 pipe_texture_reference(&tx->base.texture, pt);
68 tx->base.format = pt->format;
69 tx->base.x = x;
70 tx->base.y = y;
71 tx->base.width = w;
72 tx->base.height = h;
73 tx->base.block = pt->block;
74 tx->base.nblocksx = pt->nblocksx[level];
75 tx->base.nblocksy = pt->nblocksy[level];
76 tx->base.stride = mt->level[level].pitch;
77 tx->base.usage = usage;
78 tx->base.face = face;
79 tx->base.level = level;
80 tx->base.zslice = zslice;
81
82 /* Direct access to texture */
83 if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC ||
84 debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) &&
85 pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
86 {
87 tx->direct = true;
88 tx->surface = pscreen->get_tex_surface(pscreen, pt,
89 0, 0, 0,
90 nv10_usage_tx_to_buf(usage));
91 return &tx->base;
92 }
93
94 tx->direct = false;
95
96 nv10_compatible_transfer_tex(pt, level, &tx_tex_template);
97
98 tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
99 if (!tx_tex)
100 {
101 FREE(tx);
102 return NULL;
103 }
104
105 tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
106 face, level, zslice,
107 nv10_usage_tx_to_buf(usage));
108
109 pipe_texture_reference(&tx_tex, NULL);
110
111 if (!tx->surface)
112 {
113 pipe_surface_reference(&tx->surface, NULL);
114 FREE(tx);
115 return NULL;
116 }
117
118 if (usage != PIPE_TRANSFER_WRITE) {
119 struct nv10_screen *nvscreen = nv10_screen(pscreen);
120 struct pipe_surface *src;
121
122 src = pscreen->get_tex_surface(pscreen, pt,
123 face, level, zslice,
124 PIPE_BUFFER_USAGE_GPU_READ);
125
126 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
127 /* TODO: Check if SIFM can un-swizzle */
128 nvscreen->eng2d->copy(nvscreen->eng2d,
129 tx->surface, 0, 0,
130 src, 0, 0,
131 src->width, src->height);
132
133 pipe_surface_reference(&src, NULL);
134 }
135
136 return &tx->base;
137 }
138
139 static void
140 nv10_transfer_del(struct pipe_transfer *ptx)
141 {
142 struct nv10_transfer *tx = (struct nv10_transfer *)ptx;
143
144 if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) {
145 struct pipe_screen *pscreen = ptx->texture->screen;
146 struct nv10_screen *nvscreen = nv10_screen(pscreen);
147 struct pipe_surface *dst;
148
149 dst = pscreen->get_tex_surface(pscreen, ptx->texture,
150 ptx->face, ptx->level, ptx->zslice,
151 PIPE_BUFFER_USAGE_GPU_WRITE);
152
153 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
154 nvscreen->eng2d->copy(nvscreen->eng2d,
155 dst, 0, 0,
156 tx->surface, 0, 0,
157 dst->width, dst->height);
158
159 pipe_surface_reference(&dst, NULL);
160 }
161
162 pipe_surface_reference(&tx->surface, NULL);
163 pipe_texture_reference(&ptx->texture, NULL);
164 FREE(ptx);
165 }
166
167 static void *
168 nv10_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
169 {
170 struct nv10_transfer *tx = (struct nv10_transfer *)ptx;
171 struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
172 struct nv10_miptree *mt = (struct nv10_miptree *)tx->surface->texture;
173 void *map = pipe_buffer_map(pscreen, mt->buffer,
174 nv10_usage_tx_to_buf(ptx->usage));
175
176 return map + ns->base.offset +
177 ptx->y * ns->pitch + ptx->x * ptx->block.size;
178 }
179
180 static void
181 nv10_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
182 {
183 struct nv10_transfer *tx = (struct nv10_transfer *)ptx;
184 struct nv10_miptree *mt = (struct nv10_miptree *)tx->surface->texture;
185
186 pipe_buffer_unmap(pscreen, mt->buffer);
187 }
188
189 void
190 nv10_screen_init_transfer_functions(struct pipe_screen *pscreen)
191 {
192 pscreen->get_tex_transfer = nv10_transfer_new;
193 pscreen->tex_transfer_destroy = nv10_transfer_del;
194 pscreen->transfer_map = nv10_transfer_map;
195 pscreen->transfer_unmap = nv10_transfer_unmap;
196 }