g3dvl: Add Nouveau winsys, libdriclient.
[mesa.git] / src / gallium / winsys / g3dvl / nouveau / nouveau_winsys_pipe.c
1 #include "pipe/p_winsys.h"
2 #include "pipe/p_defines.h"
3 #include "pipe/p_util.h"
4 #include "pipe/p_inlines.h"
5
6 #include "nouveau_context.h"
7 #include "nouveau_local.h"
8 #include "nouveau_screen.h"
9 #include "nouveau_swapbuffers.h"
10 #include "nouveau_winsys_pipe.h"
11
12 static void
13 nouveau_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surf,
14 void *context_private)
15 {
16 struct nouveau_context *nv = context_private;
17 dri_drawable_t *dri_drawable = nv->dri_drawable;
18
19 nouveau_copy_buffer(dri_drawable, surf, NULL);
20 }
21
22 static const char *
23 nouveau_get_name(struct pipe_winsys *pws)
24 {
25 return "Nouveau/DRI";
26 }
27
28 static struct pipe_surface *
29 nouveau_surface_alloc(struct pipe_winsys *ws)
30 {
31 struct pipe_surface *surf;
32
33 surf = CALLOC_STRUCT(pipe_surface);
34 if (!surf)
35 return NULL;
36
37 surf->refcount = 1;
38 surf->winsys = ws;
39 return surf;
40 }
41
42 /* Borrowed from Mesa's xm_winsys */
43 static unsigned int
44 round_up(unsigned n, unsigned multiple)
45 {
46 return (n + multiple - 1) & ~(multiple - 1);
47 }
48
49 static int
50 nouveau_surface_alloc_storage
51 (
52 struct pipe_winsys *pws,
53 struct pipe_surface *surface,
54 unsigned width,
55 unsigned height,
56 enum pipe_format format,
57 unsigned flags,
58 unsigned tex_usage
59 )
60 {
61 const unsigned int ALIGNMENT = 256;
62
63 assert(pws);
64 assert(surface);
65
66 surface->width = width;
67 surface->height = height;
68 surface->format = format;
69 pf_get_block(format, &surface->block);
70 surface->nblocksx = pf_get_nblocksx(&surface->block, width);
71 surface->nblocksy = pf_get_nblocksy(&surface->block, height);
72 surface->stride = round_up(surface->nblocksx * surface->block.size, ALIGNMENT);
73 surface->usage = flags;
74 surface->buffer = pws->buffer_create(pws, ALIGNMENT, PIPE_BUFFER_USAGE_PIXEL, surface->stride * surface->nblocksy);
75
76 return 0;
77 }
78
79 static void
80 nouveau_surface_release(struct pipe_winsys *ws, struct pipe_surface **s)
81 {
82 struct pipe_surface *surf = *s;
83
84 *s = NULL;
85 if (--surf->refcount <= 0) {
86 if (surf->buffer)
87 pipe_buffer_reference(ws, &surf->buffer, NULL);
88 free(surf);
89 }
90 }
91
92 static struct pipe_buffer *
93 nouveau_pipe_bo_create(struct pipe_winsys *pws, unsigned alignment,
94 unsigned usage, unsigned size)
95 {
96 struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
97 struct nouveau_context *nv = nvpws->nv;
98 struct nouveau_device *dev = nv->nv_screen->device;
99 struct nouveau_pipe_buffer *nvbuf;
100 uint32_t flags;
101
102 nvbuf = calloc(1, sizeof(*nvbuf));
103 if (!nvbuf)
104 return NULL;
105 nvbuf->base.refcount = 1;
106 nvbuf->base.alignment = alignment;
107 nvbuf->base.usage = usage;
108 nvbuf->base.size = size;
109
110 flags = NOUVEAU_BO_LOCAL;
111
112 if (usage & PIPE_BUFFER_USAGE_PIXEL) {
113 if (usage & NOUVEAU_BUFFER_USAGE_TEXTURE)
114 flags |= NOUVEAU_BO_GART;
115 flags |= NOUVEAU_BO_VRAM;
116 }
117
118 if (usage & PIPE_BUFFER_USAGE_VERTEX) {
119 if (nv->cap.hw_vertex_buffer)
120 flags |= NOUVEAU_BO_GART;
121 }
122
123 if (usage & PIPE_BUFFER_USAGE_INDEX) {
124 if (nv->cap.hw_index_buffer)
125 flags |= NOUVEAU_BO_GART;
126 }
127
128 if (nouveau_bo_new(dev, flags, alignment, size, &nvbuf->bo)) {
129 free(nvbuf);
130 return NULL;
131 }
132
133 return &nvbuf->base;
134 }
135
136 static struct pipe_buffer *
137 nouveau_pipe_bo_user_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
138 {
139 struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)pws;
140 struct nouveau_device *dev = nvpws->nv->nv_screen->device;
141 struct nouveau_pipe_buffer *nvbuf;
142
143 nvbuf = calloc(1, sizeof(*nvbuf));
144 if (!nvbuf)
145 return NULL;
146 nvbuf->base.refcount = 1;
147 nvbuf->base.size = bytes;
148
149 if (nouveau_bo_user(dev, ptr, bytes, &nvbuf->bo)) {
150 free(nvbuf);
151 return NULL;
152 }
153
154 return &nvbuf->base;
155 }
156
157 static void
158 nouveau_pipe_bo_del(struct pipe_winsys *ws, struct pipe_buffer *buf)
159 {
160 struct nouveau_pipe_buffer *nvbuf = nouveau_buffer(buf);
161
162 nouveau_bo_del(&nvbuf->bo);
163 free(nvbuf);
164 }
165
166 static void *
167 nouveau_pipe_bo_map(struct pipe_winsys *pws, struct pipe_buffer *buf,
168 unsigned flags)
169 {
170 struct nouveau_pipe_buffer *nvbuf = nouveau_buffer(buf);
171 uint32_t map_flags = 0;
172
173 if (flags & PIPE_BUFFER_USAGE_CPU_READ)
174 map_flags |= NOUVEAU_BO_RD;
175 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
176 map_flags |= NOUVEAU_BO_WR;
177
178 if (nouveau_bo_map(nvbuf->bo, map_flags))
179 return NULL;
180 return nvbuf->bo->map;
181 }
182
183 static void
184 nouveau_pipe_bo_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf)
185 {
186 struct nouveau_pipe_buffer *nvbuf = nouveau_buffer(buf);
187
188 nouveau_bo_unmap(nvbuf->bo);
189 }
190
191 static INLINE struct nouveau_fence *
192 nouveau_pipe_fence(struct pipe_fence_handle *pfence)
193 {
194 return (struct nouveau_fence *)pfence;
195 }
196
197 static void
198 nouveau_pipe_fence_reference(struct pipe_winsys *ws,
199 struct pipe_fence_handle **ptr,
200 struct pipe_fence_handle *pfence)
201 {
202 nouveau_fence_ref((void *)pfence, (void *)ptr);
203 }
204
205 static int
206 nouveau_pipe_fence_signalled(struct pipe_winsys *ws,
207 struct pipe_fence_handle *pfence, unsigned flag)
208 {
209 struct nouveau_pipe_winsys *nvpws = (struct nouveau_pipe_winsys *)ws;
210 struct nouveau_fence *fence = nouveau_pipe_fence(pfence);
211
212 if (nouveau_fence(fence)->signalled == 0)
213 nouveau_fence_flush(nvpws->nv->nvc->channel);
214
215 return !nouveau_fence(fence)->signalled;
216 }
217
218 static int
219 nouveau_pipe_fence_finish(struct pipe_winsys *ws,
220 struct pipe_fence_handle *pfence, unsigned flag)
221 {
222 struct nouveau_fence *fence = nouveau_pipe_fence(pfence);
223 struct nouveau_fence *ref = NULL;
224
225 nouveau_fence_ref(fence, &ref);
226 return nouveau_fence_wait(&ref);
227 }
228
229 struct pipe_winsys *
230 nouveau_create_pipe_winsys(struct nouveau_context *nv)
231 {
232 struct nouveau_pipe_winsys *nvpws;
233 struct pipe_winsys *pws;
234
235 nvpws = CALLOC_STRUCT(nouveau_pipe_winsys);
236 if (!nvpws)
237 return NULL;
238 nvpws->nv = nv;
239 pws = &nvpws->pws;
240
241 pws->flush_frontbuffer = nouveau_flush_frontbuffer;
242
243 pws->surface_alloc = nouveau_surface_alloc;
244 pws->surface_alloc_storage = nouveau_surface_alloc_storage;
245 pws->surface_release = nouveau_surface_release;
246
247 pws->buffer_create = nouveau_pipe_bo_create;
248 pws->buffer_destroy = nouveau_pipe_bo_del;
249 pws->user_buffer_create = nouveau_pipe_bo_user_create;
250 pws->buffer_map = nouveau_pipe_bo_map;
251 pws->buffer_unmap = nouveau_pipe_bo_unmap;
252
253 pws->fence_reference = nouveau_pipe_fence_reference;
254 pws->fence_signalled = nouveau_pipe_fence_signalled;
255 pws->fence_finish = nouveau_pipe_fence_finish;
256
257 pws->get_name = nouveau_get_name;
258
259 return &nvpws->pws;
260 }
261