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