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