nouveau: Expect right params to tex_transfer_destroy().
[mesa.git] / src / gallium / drivers / nv40 / nv40_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 "nv40_context.h"
7 #include "nv40_screen.h"
8 #include "nv40_state.h"
9
10 struct nv40_transfer {
11 struct pipe_transfer base;
12 struct pipe_surface *surface;
13 bool direct;
14 };
15
16 static unsigned nv40_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 nv40_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->nr_samples = pt->nr_samples;
47
48 template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC |
49 NOUVEAU_TEXTURE_USAGE_LINEAR;
50 }
51
52 static struct pipe_transfer *
53 nv40_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
54 unsigned face, unsigned level, unsigned zslice,
55 enum pipe_transfer_usage usage,
56 unsigned x, unsigned y, unsigned w, unsigned h)
57 {
58 struct nv40_miptree *mt = (struct nv40_miptree *)pt;
59 struct nv40_transfer *tx;
60 struct pipe_texture tx_tex_template, *tx_tex;
61
62 tx = CALLOC_STRUCT(nv40_transfer);
63 if (!tx)
64 return NULL;
65
66 pipe_texture_reference(&tx->base.texture, pt);
67 tx->base.format = pt->format;
68 tx->base.x = x;
69 tx->base.y = y;
70 tx->base.width = w;
71 tx->base.height = h;
72 tx->base.block = pt->block;
73 tx->base.nblocksx = pt->nblocksx[level];
74 tx->base.nblocksy = pt->nblocksy[level];
75 tx->base.stride = mt->level[level].pitch;
76 tx->base.usage = usage;
77 tx->base.face = face;
78 tx->base.level = level;
79 tx->base.zslice = zslice;
80
81 /* Direct access to texture */
82 if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC ||
83 debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) &&
84 pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
85 {
86 tx->direct = true;
87 tx->surface = pscreen->get_tex_surface(pscreen, pt,
88 face, level, zslice,
89 nv40_usage_tx_to_buf(usage));
90 return &tx->base;
91 }
92
93 tx->direct = false;
94
95 nv40_compatible_transfer_tex(pt, level, &tx_tex_template);
96
97 tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
98 if (!tx_tex)
99 {
100 FREE(tx);
101 return NULL;
102 }
103
104 tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
105 0, 0, 0,
106 nv40_usage_tx_to_buf(usage));
107
108 pipe_texture_reference(&tx_tex, NULL);
109
110 if (!tx->surface)
111 {
112 pipe_surface_reference(&tx->surface, NULL);
113 FREE(tx);
114 return NULL;
115 }
116
117 if (usage != PIPE_TRANSFER_WRITE) {
118 struct nv40_screen *nvscreen = nv40_screen(pscreen);
119 struct pipe_surface *src;
120
121 src = pscreen->get_tex_surface(pscreen, pt,
122 face, level, zslice,
123 PIPE_BUFFER_USAGE_GPU_READ);
124
125 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
126 /* TODO: Check if SIFM can un-swizzle */
127 nvscreen->eng2d->copy(nvscreen->eng2d,
128 tx->surface, 0, 0,
129 src, 0, 0,
130 src->width, src->height);
131
132 pipe_surface_reference(&src, NULL);
133 }
134
135 return &tx->base;
136 }
137
138 static void
139 nv40_transfer_del(struct pipe_transfer *ptx)
140 {
141 struct nv40_transfer *tx = (struct nv40_transfer *)ptx;
142
143 if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) {
144 struct pipe_screen *pscreen = ptx->texture->screen;
145 struct nv40_screen *nvscreen = nv40_screen(pscreen);
146 struct pipe_surface *dst;
147
148 dst = pscreen->get_tex_surface(pscreen, ptx->texture,
149 ptx->face, ptx->level, ptx->zslice,
150 PIPE_BUFFER_USAGE_GPU_WRITE);
151
152 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
153 nvscreen->eng2d->copy(nvscreen->eng2d,
154 dst, 0, 0,
155 tx->surface, 0, 0,
156 dst->width, dst->height);
157
158 pipe_surface_reference(&dst, NULL);
159 }
160
161 pipe_surface_reference(&tx->surface, NULL);
162 pipe_texture_reference(&ptx->texture, NULL);
163 FREE(ptx);
164 }
165
166 static void *
167 nv40_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
168 {
169 struct nv40_transfer *tx = (struct nv40_transfer *)ptx;
170 struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
171 struct nv40_miptree *mt = (struct nv40_miptree *)tx->surface->texture;
172 void *map = pipe_buffer_map(pscreen, mt->buffer,
173 nv40_usage_tx_to_buf(ptx->usage));
174
175 return map + ns->base.offset +
176 ptx->y * ns->pitch + ptx->x * ptx->block.size;
177 }
178
179 static void
180 nv40_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
181 {
182 struct nv40_transfer *tx = (struct nv40_transfer *)ptx;
183 struct nv40_miptree *mt = (struct nv40_miptree *)tx->surface->texture;
184
185 pipe_buffer_unmap(pscreen, mt->buffer);
186 }
187
188 void
189 nv40_screen_init_transfer_functions(struct pipe_screen *pscreen)
190 {
191 pscreen->get_tex_transfer = nv40_transfer_new;
192 pscreen->tex_transfer_destroy = nv40_transfer_del;
193 pscreen->transfer_map = nv40_transfer_map;
194 pscreen->transfer_unmap = nv40_transfer_unmap;
195 }