99816a811d6e7ef1c310f402baf79cabfbe4669f
[mesa.git] / src / mesa / pipe / xlib / xm_winsys.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell
32 * Brian Paul
33 */
34
35
36 #include "glxheader.h"
37 #include "xmesaP.h"
38 #include "main/macros.h"
39
40 #include "pipe/p_winsys.h"
41 #include "pipe/softpipe/sp_winsys.h"
42
43
44 /**
45 * Low-level OS/window system memory buffer
46 */
47 struct xm_buffer
48 {
49 boolean userBuffer; /** Is this a user-space buffer? */
50 int refcount;
51 unsigned size;
52 void *data;
53 void *mapped;
54 };
55
56
57
58 /* Turn the softpipe opaque buffer pointer into a dri_bufmgr opaque
59 * buffer pointer...
60 */
61 static inline struct xm_buffer *
62 xm_bo( struct pipe_buffer_handle *bo )
63 {
64 return (struct xm_buffer *) bo;
65 }
66
67 static inline struct pipe_buffer_handle *
68 pipe_bo( struct xm_buffer *bo )
69 {
70 return (struct pipe_buffer_handle *) bo;
71 }
72
73
74 /* Most callbacks map direcly onto dri_bufmgr operations:
75 */
76 static void *
77 xm_buffer_map(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
78 unsigned flags)
79 {
80 struct xm_buffer *xm_buf = xm_bo(buf);
81 xm_buf->mapped = xm_buf->data;
82 return xm_buf->mapped;
83 }
84
85 static void
86 xm_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer_handle *buf)
87 {
88 struct xm_buffer *xm_buf = xm_bo(buf);
89 xm_buf->mapped = NULL;
90 }
91
92 static void
93 xm_buffer_reference(struct pipe_winsys *pws,
94 struct pipe_buffer_handle **ptr,
95 struct pipe_buffer_handle *buf)
96 {
97 if (*ptr) {
98 struct xm_buffer *oldBuf = xm_bo(*ptr);
99 oldBuf->refcount--;
100 assert(oldBuf->refcount >= 0);
101 if (oldBuf->refcount == 0) {
102 if (oldBuf->data) {
103 if (!oldBuf->userBuffer)
104 free(oldBuf->data);
105 oldBuf->data = NULL;
106 }
107 free(oldBuf);
108 }
109 *ptr = NULL;
110 }
111
112 assert(!(*ptr));
113
114 if (buf) {
115 struct xm_buffer *newBuf = xm_bo(buf);
116 newBuf->refcount++;
117 *ptr = buf;
118 }
119 }
120
121 static void
122 xm_buffer_data(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
123 unsigned size, const void *data, unsigned usage )
124 {
125 struct xm_buffer *xm_buf = xm_bo(buf);
126 assert(!xm_buf->userBuffer);
127 if (xm_buf->size != size) {
128 if (xm_buf->data)
129 free(xm_buf->data);
130 xm_buf->data = malloc(size);
131 xm_buf->size = size;
132 }
133 if (data)
134 memcpy(xm_buf->data, data, size);
135 }
136
137 static void
138 xm_buffer_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
139 unsigned long offset, unsigned long size, const void *data)
140 {
141 struct xm_buffer *xm_buf = xm_bo(buf);
142 GLubyte *b = (GLubyte *) xm_buf->data;
143 assert(!xm_buf->userBuffer);
144 assert(b);
145 memcpy(b + offset, data, size);
146 }
147
148 static void
149 xm_buffer_get_subdata(struct pipe_winsys *pws, struct pipe_buffer_handle *buf,
150 unsigned long offset, unsigned long size, void *data)
151 {
152 const struct xm_buffer *xm_buf = xm_bo(buf);
153 const GLubyte *b = (GLubyte *) xm_buf->data;
154 assert(!xm_buf->userBuffer);
155 assert(b);
156 memcpy(data, b + offset, size);
157 }
158
159 static void
160 xm_flush_frontbuffer(struct pipe_winsys *pws,
161 struct pipe_surface *surf,
162 void *context_private)
163 {
164 /* The Xlib driver's front color surfaces are actually X Windows so
165 * this flush is a no-op.
166 * If we instead did front buffer rendering to a temporary XImage,
167 * this would be the place to copy the Ximage to the on-screen Window.
168 */
169 }
170
171
172 static void
173 xm_printf(struct pipe_winsys *pws, const char *fmtString, ...)
174 {
175 va_list args;
176 va_start( args, fmtString );
177 vfprintf(stderr, fmtString, args);
178 va_end( args );
179 }
180
181 static const char *
182 xm_get_name(struct pipe_winsys *pws)
183 {
184 return "Xlib";
185 }
186
187
188 static struct pipe_buffer_handle *
189 xm_buffer_create(struct pipe_winsys *pws, unsigned alignment)
190 {
191 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
192 buffer->refcount = 1;
193 return pipe_bo(buffer);
194 }
195
196
197 /**
198 * Create buffer which wraps user-space data.
199 */
200 static struct pipe_buffer_handle *
201 xm_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
202 {
203 struct xm_buffer *buffer = CALLOC_STRUCT(xm_buffer);
204 buffer->userBuffer = TRUE;
205 buffer->refcount = 1;
206 buffer->data = ptr;
207 buffer->size = bytes;
208 return pipe_bo(buffer);
209 }
210
211
212
213 /**
214 * Round n up to next multiple.
215 */
216 static INLINE unsigned
217 round_up(unsigned n, unsigned multiple)
218 {
219 return (n + multiple - 1) & ~(multiple - 1);
220 }
221
222
223 static unsigned
224 xm_surface_pitch(struct pipe_winsys *winsys, unsigned cpp, unsigned width,
225 unsigned flags)
226 {
227 return round_up(width, 64 / cpp);
228 }
229
230
231 static struct pipe_region *
232 xm_region_alloc(struct pipe_winsys *winsys, unsigned size, unsigned flags)
233 {
234 struct pipe_region *region = CALLOC_STRUCT(pipe_region);
235 const unsigned alignment = 64;
236
237 region->refcount = 1;
238
239 assert(size > 0);
240
241 region->buffer = winsys->buffer_create( winsys, alignment );
242
243 /* NULL data --> just allocate the space */
244 winsys->buffer_data( winsys,
245 region->buffer,
246 size,
247 NULL,
248 PIPE_BUFFER_USAGE_PIXEL );
249 return region;
250 }
251
252
253 static void
254 xm_region_release(struct pipe_winsys *winsys, struct pipe_region **region)
255 {
256 if (!*region)
257 return;
258
259 assert((*region)->refcount > 0);
260 (*region)->refcount--;
261
262 if ((*region)->refcount == 0) {
263 assert((*region)->map_refcount == 0);
264
265 winsys->buffer_reference( winsys, &((*region)->buffer), NULL );
266 free(*region);
267 }
268 *region = NULL;
269 }
270
271
272 /**
273 * Called via pipe->surface_alloc() to create new surfaces (textures,
274 * renderbuffers, etc.
275 */
276 static struct pipe_surface *
277 xm_surface_alloc(struct pipe_winsys *ws, GLuint pipeFormat)
278 {
279 struct xmesa_surface *xms = CALLOC_STRUCT(xmesa_surface);
280
281 assert(ws);
282 assert(pipeFormat);
283
284 xms->surface.format = pipeFormat;
285 xms->surface.refcount = 1;
286 xms->surface.winsys = ws;
287 #if 0
288 /*
289 * This is really just a softpipe surface, not an XImage/Pixmap surface.
290 */
291 softpipe_init_surface_funcs(&xms->surface);
292 #endif
293 return &xms->surface;
294 }
295
296
297
298 static void
299 xm_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
300 {
301 struct pipe_surface *surf = *s;
302 surf->refcount--;
303 if (surf->refcount == 0) {
304 if (surf->region)
305 winsys->region_release(winsys, &surf->region);
306 free(surf);
307 }
308 *s = NULL;
309 }
310
311
312
313 /**
314 * Return pointer to a pipe_winsys object.
315 * For Xlib, this is a singleton object.
316 * Nothing special for the Xlib driver so no subclassing or anything.
317 */
318 struct pipe_winsys *
319 xmesa_get_pipe_winsys(void)
320 {
321 static struct pipe_winsys *ws = NULL;
322
323 if (!ws) {
324 ws = CALLOC_STRUCT(pipe_winsys);
325
326 /* Fill in this struct with callbacks that pipe will need to
327 * communicate with the window system, buffer manager, etc.
328 */
329 ws->buffer_create = xm_buffer_create;
330 ws->user_buffer_create = xm_user_buffer_create;
331 ws->buffer_map = xm_buffer_map;
332 ws->buffer_unmap = xm_buffer_unmap;
333 ws->buffer_reference = xm_buffer_reference;
334 ws->buffer_data = xm_buffer_data;
335 ws->buffer_subdata = xm_buffer_subdata;
336 ws->buffer_get_subdata = xm_buffer_get_subdata;
337
338 ws->region_alloc = xm_region_alloc;
339 ws->region_release = xm_region_release;
340
341 ws->surface_pitch = xm_surface_pitch;
342 ws->surface_alloc = xm_surface_alloc;
343 ws->surface_release = xm_surface_release;
344
345 ws->flush_frontbuffer = xm_flush_frontbuffer;
346 ws->printf = xm_printf;
347 ws->get_name = xm_get_name;
348 }
349
350 return ws;
351 }
352
353
354 /**
355 * XXX this depends on the depths supported by the screen (8/16/32/etc).
356 * Maybe when we're about to create a context/drawable we create a new
357 * softpipe_winsys object that corresponds to the specified screen...
358 *
359 * Also, this query only really matters for on-screen drawables.
360 * For textures and FBOs we (softpipe) can support any format.o
361 */
362 static boolean
363 xmesa_is_format_supported(struct softpipe_winsys *sws, uint format)
364 {
365 /* Any format supported by softpipe can be listed here.
366 * This query is not used for allocating window-system color buffers
367 * (which would depend on the screen depth/bpp).
368 */
369 switch (format) {
370 case PIPE_FORMAT_U_A8_R8_G8_B8:
371 case PIPE_FORMAT_S_R16_G16_B16_A16:
372 case PIPE_FORMAT_S8_Z24:
373 case PIPE_FORMAT_U_S8:
374 case PIPE_FORMAT_U_Z16:
375 case PIPE_FORMAT_U_Z32:
376 return TRUE;
377 default:
378 return FALSE;
379 };
380 }
381
382
383 /**
384 * Return pointer to a softpipe_winsys object.
385 * For Xlib, this is a singleton object.
386 */
387 static struct softpipe_winsys *
388 xmesa_get_softpipe_winsys(void)
389 {
390 static struct softpipe_winsys *spws = NULL;
391
392 if (!spws) {
393 spws = CALLOC_STRUCT(softpipe_winsys);
394 if (spws) {
395 spws->is_format_supported = xmesa_is_format_supported;
396 }
397 }
398
399 return spws;
400 }
401
402
403 struct pipe_context *
404 xmesa_create_context(XMesaContext xmesa)
405 {
406 struct pipe_winsys *pws = xmesa_get_pipe_winsys();
407 struct softpipe_winsys *spws = xmesa_get_softpipe_winsys();
408
409 return softpipe_create( pws, spws );
410 }