r300-gallium: Be more Gallium-ish in some of the math.
[platform/upstream/mesa.git] / src / gallium / drivers / nv20 / nv20_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 "nv20_context.h"
7 #include "nv20_screen.h"
8 #include "nv20_state.h"
9
10 struct nv20_transfer {
11         struct pipe_transfer base;
12         struct pipe_surface *surface;
13         bool direct;
14 };
15
16 static unsigned nv20_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 nv20_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 nv20_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 nv20_miptree *mt = (struct nv20_miptree *)pt;
60         struct nv20_transfer *tx;
61         struct pipe_texture tx_tex_template, *tx_tex;
62
63         tx = CALLOC_STRUCT(nv20_transfer);
64         if (!tx)
65                 return NULL;
66
67         tx->base.refcount = 1;
68         pipe_texture_reference(&tx->base.texture, pt);
69         tx->base.format = pt->format;
70         tx->base.x = x;
71         tx->base.y = y;
72         tx->base.width = w;
73         tx->base.height = h;
74         tx->base.block = pt->block;
75         tx->base.nblocksx = pt->nblocksx[level];
76         tx->base.nblocksy = pt->nblocksy[level];
77         tx->base.stride = mt->level[level].pitch;
78         tx->base.usage = usage;
79         tx->base.face = face;
80         tx->base.level = level;
81         tx->base.zslice = zslice;
82
83         /* Direct access to texture */
84         if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC ||
85              debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) &&
86             pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
87         {
88                 tx->direct = true;
89                 tx->surface = pscreen->get_tex_surface(pscreen, pt,
90                                                        face, level, zslice,
91                                                        nv20_usage_tx_to_buf(usage));
92                 return &tx->base;
93         }
94
95         tx->direct = false;
96
97         nv20_compatible_transfer_tex(pt, level, &tx_tex_template);
98
99         tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
100         if (!tx_tex)
101         {
102                 FREE(tx);
103                 return NULL;
104         }
105
106         tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
107                                                face, level, zslice,
108                                                nv20_usage_tx_to_buf(usage));
109
110         pipe_texture_reference(&tx_tex, NULL);
111
112         if (!tx->surface)
113         {
114                 pipe_surface_reference(&tx->surface, NULL);
115                 FREE(tx);
116                 return NULL;
117         }
118
119         if (usage != PIPE_TRANSFER_WRITE) {
120                 struct nv20_screen *nvscreen = nv20_screen(pscreen);
121                 struct pipe_surface *src;
122
123                 src = pscreen->get_tex_surface(pscreen, pt,
124                                                face, level, zslice,
125                                                PIPE_BUFFER_USAGE_GPU_READ);
126
127                 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
128                 /* TODO: Check if SIFM can un-swizzle */
129                 nvscreen->eng2d->copy(nvscreen->eng2d,
130                                       tx->surface, 0, 0,
131                                       src, 0, 0,
132                                       src->width, src->height);
133
134                 pipe_surface_reference(&src, NULL);
135         }
136
137         return &tx->base;
138 }
139
140 static void
141 nv20_transfer_del(struct pipe_screen *pscreen, struct pipe_transfer **pptx)
142 {
143         struct pipe_transfer *ptx = *pptx;
144         struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
145
146         if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) {
147                 struct nv20_screen *nvscreen = nv20_screen(pscreen);
148                 struct pipe_surface *dst;
149
150                 dst = pscreen->get_tex_surface(pscreen, ptx->texture,
151                                                ptx->face, ptx->level, ptx->zslice,
152                                                PIPE_BUFFER_USAGE_GPU_WRITE);
153
154                 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
155                 nvscreen->eng2d->copy(nvscreen->eng2d,
156                                       dst, 0, 0,
157                                       tx->surface, 0, 0,
158                                       dst->width, dst->height);
159
160                 pipe_surface_reference(&dst, NULL);
161         }
162
163         *pptx = NULL;
164         if (--ptx->refcount)
165                 return;
166
167         pipe_surface_reference(&tx->surface, NULL);
168         pipe_texture_reference(&ptx->texture, NULL);
169         FREE(ptx);
170 }
171
172 static void *
173 nv20_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
174 {
175         struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
176         struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
177         struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
178         void *map = pipe_buffer_map(pscreen, mt->buffer,
179                                     nv20_usage_tx_to_buf(ptx->usage));
180
181         return map + ns->base.offset +
182                ptx->y * ns->pitch + ptx->x * ptx->block.size;
183 }
184
185 static void
186 nv20_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
187 {
188         struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
189         struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
190
191         pipe_buffer_unmap(pscreen, mt->buffer);
192 }
193
194 void
195 nv20_screen_init_transfer_functions(struct pipe_screen *pscreen)
196 {
197         pscreen->get_tex_transfer = nv20_transfer_new;
198         pscreen->tex_transfer_release = nv20_transfer_del;
199         pscreen->transfer_map = nv20_transfer_map;
200         pscreen->transfer_unmap = nv20_transfer_unmap;
201 }