Merge commit 'origin/master' into i965g-restart
[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 <util/u_math.h>
6 #include <nouveau/nouveau_winsys.h>
7 #include "nv20_context.h"
8 #include "nv20_screen.h"
9 #include "nv20_state.h"
10
11 struct nv20_transfer {
12 struct pipe_transfer base;
13 struct pipe_surface *surface;
14 bool direct;
15 };
16
17 static void
18 nv20_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
19 struct pipe_texture *template)
20 {
21 memset(template, 0, sizeof(struct pipe_texture));
22 template->target = pt->target;
23 template->format = pt->format;
24 template->width0 = u_minify(pt->width0, level);
25 template->height0 = u_minify(pt->height0, level);
26 template->depth0 = 1;
27 template->block = pt->block;
28 template->nblocksx[0] = pt->nblocksx[level];
29 template->nblocksy[0] = pt->nblocksx[level];
30 template->last_level = 0;
31 template->nr_samples = pt->nr_samples;
32
33 template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC |
34 NOUVEAU_TEXTURE_USAGE_LINEAR;
35 }
36
37 static struct pipe_transfer *
38 nv20_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
39 unsigned face, unsigned level, unsigned zslice,
40 enum pipe_transfer_usage usage,
41 unsigned x, unsigned y, unsigned w, unsigned h)
42 {
43 struct nv20_miptree *mt = (struct nv20_miptree *)pt;
44 struct nv20_transfer *tx;
45 struct pipe_texture tx_tex_template, *tx_tex;
46
47 tx = CALLOC_STRUCT(nv20_transfer);
48 if (!tx)
49 return NULL;
50
51 pipe_texture_reference(&tx->base.texture, pt);
52 tx->base.format = pt->format;
53 tx->base.x = x;
54 tx->base.y = y;
55 tx->base.width = w;
56 tx->base.height = h;
57 tx->base.block = pt->block;
58 tx->base.nblocksx = pt->nblocksx[level];
59 tx->base.nblocksy = pt->nblocksy[level];
60 tx->base.stride = mt->level[level].pitch;
61 tx->base.usage = usage;
62 tx->base.face = face;
63 tx->base.level = level;
64 tx->base.zslice = zslice;
65
66 /* Direct access to texture */
67 if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC ||
68 debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) &&
69 pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
70 {
71 tx->direct = true;
72 tx->surface = pscreen->get_tex_surface(pscreen, pt,
73 0, 0, 0,
74 pipe_transfer_buffer_flags(&tx->base));
75 return &tx->base;
76 }
77
78 tx->direct = false;
79
80 nv20_compatible_transfer_tex(pt, level, &tx_tex_template);
81
82 tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
83 if (!tx_tex)
84 {
85 FREE(tx);
86 return NULL;
87 }
88
89 tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
90 face, level, zslice,
91 pipe_transfer_buffer_flags(&tx->base));
92
93 pipe_texture_reference(&tx_tex, NULL);
94
95 if (!tx->surface)
96 {
97 pipe_surface_reference(&tx->surface, NULL);
98 FREE(tx);
99 return NULL;
100 }
101
102 if (usage & PIPE_TRANSFER_READ) {
103 struct nv20_screen *nvscreen = nv20_screen(pscreen);
104 struct pipe_surface *src;
105
106 src = pscreen->get_tex_surface(pscreen, pt,
107 face, level, zslice,
108 PIPE_BUFFER_USAGE_GPU_READ);
109
110 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
111 /* TODO: Check if SIFM can un-swizzle */
112 nvscreen->eng2d->copy(nvscreen->eng2d,
113 tx->surface, 0, 0,
114 src, 0, 0,
115 src->width, src->height);
116
117 pipe_surface_reference(&src, NULL);
118 }
119
120 return &tx->base;
121 }
122
123 static void
124 nv20_transfer_del(struct pipe_transfer *ptx)
125 {
126 struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
127
128 if (!tx->direct && (ptx->usage = PIPE_TRANSFER_WRITE)) {
129 struct pipe_screen *pscreen = ptx->texture->screen;
130 struct nv20_screen *nvscreen = nv20_screen(pscreen);
131 struct pipe_surface *dst;
132
133 dst = pscreen->get_tex_surface(pscreen, ptx->texture,
134 ptx->face, ptx->level, ptx->zslice,
135 PIPE_BUFFER_USAGE_GPU_WRITE);
136
137 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
138 nvscreen->eng2d->copy(nvscreen->eng2d,
139 dst, 0, 0,
140 tx->surface, 0, 0,
141 dst->width, dst->height);
142
143 pipe_surface_reference(&dst, NULL);
144 }
145
146 pipe_surface_reference(&tx->surface, NULL);
147 pipe_texture_reference(&ptx->texture, NULL);
148 FREE(ptx);
149 }
150
151 static void *
152 nv20_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
153 {
154 struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
155 struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
156 struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
157 void *map = pipe_buffer_map(pscreen, mt->buffer,
158 pipe_transfer_buffer_flags(ptx));
159
160 return map + ns->base.offset +
161 ptx->y * ns->pitch + ptx->x * ptx->block.size;
162 }
163
164 static void
165 nv20_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
166 {
167 struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
168 struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
169
170 pipe_buffer_unmap(pscreen, mt->buffer);
171 }
172
173 void
174 nv20_screen_init_transfer_functions(struct pipe_screen *pscreen)
175 {
176 pscreen->get_tex_transfer = nv20_transfer_new;
177 pscreen->tex_transfer_destroy = nv20_transfer_del;
178 pscreen->transfer_map = nv20_transfer_map;
179 pscreen->transfer_unmap = nv20_transfer_unmap;
180 }