1c250e9fe4494449077f5b2c8fbdd9f5954507ac
[profile/ivi/mesa.git] / src / gallium / drivers / nvfx / nvfx_transfer.c
1 #include "pipe/p_state.h"
2 #include "pipe/p_defines.h"
3 #include "util/u_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 "nvfx_context.h"
9 #include "nvfx_screen.h"
10 #include "nvfx_state.h"
11
12 struct nvfx_transfer {
13         struct pipe_transfer base;
14         struct pipe_surface *surface;
15         boolean direct;
16 };
17
18 static void
19 nvfx_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 nvfx_transfer_new(struct pipe_context *pipe, 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 pipe_screen *pscreen = pipe->screen;
42         struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
43         struct nvfx_transfer *tx;
44         struct pipe_texture tx_tex_template, *tx_tex;
45         static int no_transfer = -1;
46         if(no_transfer < 0)
47                 no_transfer = debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/);
48
49         tx = CALLOC_STRUCT(nvfx_transfer);
50         if (!tx)
51                 return NULL;
52
53         pipe_texture_reference(&tx->base.texture, pt);
54         tx->base.x = x;
55         tx->base.y = y;
56         tx->base.width = w;
57         tx->base.height = h;
58         tx->base.stride = mt->level[level].pitch;
59         tx->base.usage = usage;
60         tx->base.face = face;
61         tx->base.level = level;
62         tx->base.zslice = zslice;
63
64         /* Direct access to texture */
65         if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC || no_transfer) &&
66             pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
67         {
68                 tx->direct = true;
69                 tx->surface = pscreen->get_tex_surface(pscreen, pt,
70                                                        face, level, zslice,
71                                                        pipe_transfer_buffer_flags(&tx->base));
72                 return &tx->base;
73         }
74
75         tx->direct = false;
76
77         nvfx_compatible_transfer_tex(pt, w, h, &tx_tex_template);
78
79         tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
80         if (!tx_tex)
81         {
82                 FREE(tx);
83                 return NULL;
84         }
85
86         tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch;
87
88         tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
89                                                0, 0, 0,
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 nvfx_screen *nvscreen = nvfx_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, x, y,
114                                       w, h);
115
116                 pipe_surface_reference(&src, NULL);
117         }
118
119         return &tx->base;
120 }
121
122 static void
123 nvfx_transfer_del(struct pipe_context *pipe,
124                   struct pipe_transfer *ptx)
125 {
126         struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
127
128         if (!tx->direct && (ptx->usage & PIPE_TRANSFER_WRITE)) {
129                 struct pipe_screen *pscreen = pipe->screen;
130                 struct nvfx_screen *nvscreen = nvfx_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 | NOUVEAU_BUFFER_USAGE_NO_RENDER);
136
137                 /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
138                 nvscreen->eng2d->copy(nvscreen->eng2d,
139                                       dst, tx->base.x, tx->base.y,
140                                       tx->surface, 0, 0,
141                                       tx->base.width, tx->base.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 nvfx_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
153 {
154         struct pipe_screen *pscreen = pipe->screen;
155         struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
156         struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
157         struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
158         void *map = pipe_buffer_map(pscreen, mt->buffer,
159                                     pipe_transfer_buffer_flags(ptx));
160
161         if(!tx->direct)
162                 return map + ns->base.offset;
163         else
164                 return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format);
165 }
166
167 static void
168 nvfx_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx)
169 {
170         struct pipe_screen *pscreen = pipe->screen;
171         struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
172         struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
173
174         pipe_buffer_unmap(pscreen, mt->buffer);
175 }
176
177 void
178 nvfx_init_transfer_functions(struct nvfx_context *nvfx)
179 {
180         nvfx->pipe.get_tex_transfer = nvfx_transfer_new;
181         nvfx->pipe.tex_transfer_destroy = nvfx_transfer_del;
182         nvfx->pipe.transfer_map = nvfx_transfer_map;
183         nvfx->pipe.transfer_unmap = nvfx_transfer_unmap;
184 }