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