7b3aa9948241613abb3bc3eac89bd191ef132e1d
[mesa.git] / src / mesa / drivers / dri / intel_winsys / intel_winsys_pipe.c
1 /**************************************************************************
2 *
3 * Copyright 2006 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 * Authors: Keith Whitwell <keithw-at-tungstengraphics-dot-com>
30 */
31
32 #include <stdlib.h>
33 #include <xf86drm.h>
34 #include "dri_bufpool.h"
35 #include "dri_bufmgr.h"
36
37 #include "intel_context.h"
38 #include "intel_winsys.h"
39 #include "intel_swapbuffers.h"
40 #include "intel_batchbuffer.h"
41
42 #include "pipe/p_winsys.h"
43 #include "pipe/p_defines.h"
44 #include "pipe/p_state.h"
45 #include "pipe/p_util.h"
46
47
48
49 struct intel_pipe_winsys {
50 struct pipe_winsys winsys;
51 struct _DriBufferPool *regionPool;
52 };
53
54
55
56 /* Turn a pipe winsys into an intel/pipe winsys:
57 */
58 static inline struct intel_pipe_winsys *
59 intel_pipe_winsys( struct pipe_winsys *winsys )
60 {
61 return (struct intel_pipe_winsys *)winsys;
62 }
63
64
65 /* Most callbacks map direcly onto dri_bufmgr operations:
66 */
67 static void *intel_buffer_map(struct pipe_winsys *winsys,
68 struct pipe_buffer_handle *buf,
69 unsigned flags )
70 {
71 unsigned drm_flags = 0;
72
73 if (flags & PIPE_BUFFER_FLAG_WRITE)
74 drm_flags |= DRM_BO_FLAG_WRITE;
75
76 if (flags & PIPE_BUFFER_FLAG_READ)
77 drm_flags |= DRM_BO_FLAG_READ;
78
79 return driBOMap( dri_bo(buf), drm_flags, 0 );
80 }
81
82 static void intel_buffer_unmap(struct pipe_winsys *winsys,
83 struct pipe_buffer_handle *buf)
84 {
85 driBOUnmap( dri_bo(buf) );
86 }
87
88
89 static void
90 intel_buffer_reference(struct pipe_winsys *winsys,
91 struct pipe_buffer_handle **ptr,
92 struct pipe_buffer_handle *buf)
93 {
94 if (*ptr) {
95 driBOUnReference( dri_bo(*ptr) );
96 *ptr = NULL;
97 }
98
99 if (buf) {
100 driBOReference( dri_bo(buf) );
101 *ptr = buf;
102 }
103 }
104
105
106 /* Grabs the hardware lock!
107 */
108 static void intel_buffer_data(struct pipe_winsys *winsys,
109 struct pipe_buffer_handle *buf,
110 unsigned size, const void *data,
111 unsigned usage )
112 {
113 driBOData( dri_bo(buf), size, data, 0 );
114 }
115
116 static void intel_buffer_subdata(struct pipe_winsys *winsys,
117 struct pipe_buffer_handle *buf,
118 unsigned long offset,
119 unsigned long size,
120 const void *data)
121 {
122 driBOSubData( dri_bo(buf), offset, size, data );
123 }
124
125 static void intel_buffer_get_subdata(struct pipe_winsys *winsys,
126 struct pipe_buffer_handle *buf,
127 unsigned long offset,
128 unsigned long size,
129 void *data)
130 {
131 driBOGetSubData( dri_bo(buf), offset, size, data );
132 }
133
134 /* Pipe has no concept of pools. We choose the tex/region pool
135 * for all buffers.
136 */
137 static struct pipe_buffer_handle *
138 intel_buffer_create(struct pipe_winsys *winsys,
139 unsigned alignment)
140 {
141 struct _DriBufferObject *buffer;
142 struct intel_pipe_winsys *iws = intel_pipe_winsys(winsys);
143 driGenBuffers( iws->regionPool,
144 "pipe buffer", 1, &buffer, alignment, 0, 0 );
145 return pipe_bo(buffer);
146 }
147
148
149 static struct pipe_buffer_handle *
150 intel_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes)
151 {
152 struct _DriBufferObject *buffer;
153 struct intel_pipe_winsys *iws = intel_pipe_winsys(winsys);
154 driGenUserBuffer( iws->regionPool,
155 "pipe user buffer", &buffer, ptr, bytes);
156 return pipe_bo(buffer);
157 }
158
159
160 /* The state tracker (should!) keep track of whether the fake
161 * frontbuffer has been touched by any rendering since the last time
162 * we copied its contents to the real frontbuffer. Our task is easy:
163 */
164 static void
165 intel_flush_frontbuffer( struct pipe_winsys *winsys,
166 struct pipe_surface *surf,
167 void *context_private)
168 {
169 struct intel_context *intel = (struct intel_context *) context_private;
170 __DRIdrawablePrivate *dPriv = intel->driDrawable;
171
172 intelDisplaySurface(dPriv, surf, NULL);
173 }
174
175
176 static unsigned
177 intel_i915_surface_pitch(struct pipe_winsys *winsys,
178 unsigned cpp, unsigned width, unsigned flags)
179 {
180 /* Choose a pitch to match hardware requirements - requires 64 byte
181 * alignment of render targets.
182 *
183 * XXX: is this ok for textures??
184 * clearly want to be able to render to textures under some
185 * circumstances, but maybe not always a requirement.
186 */
187
188 /* XXX is the pitch different for textures vs. drawables? */
189 if (flags & PIPE_SURFACE_FLAG_TEXTURE) /* or PIPE_SURFACE_FLAG_RENDER? */
190 return ((cpp * width + 63) & ~63) / cpp;
191 else
192 return ((cpp * width + 63) & ~63) / cpp;
193 }
194
195
196 static struct pipe_region *
197 intel_i915_region_alloc(struct pipe_winsys *winsys,
198 unsigned size, unsigned flags)
199 {
200 struct pipe_region *region = calloc(sizeof(*region), 1);
201 const unsigned alignment = 64;
202
203 region->refcount = 1;
204
205 region->buffer = winsys->buffer_create( winsys, alignment );
206
207 winsys->buffer_data( winsys,
208 region->buffer,
209 size,
210 NULL,
211 PIPE_BUFFER_USAGE_PIXEL );
212
213 return region;
214 }
215
216 static void
217 intel_i915_region_release(struct pipe_winsys *winsys,
218 struct pipe_region **region)
219 {
220 if (!*region)
221 return;
222
223 assert((*region)->refcount > 0);
224 (*region)->refcount--;
225
226 if ((*region)->refcount == 0) {
227 assert((*region)->map_refcount == 0);
228
229 winsys->buffer_reference( winsys, &((*region)->buffer), NULL );
230 free(*region);
231 }
232 *region = NULL;
233 }
234
235
236 static struct pipe_surface *
237 intel_i915_surface_alloc(struct pipe_winsys *winsys, unsigned format)
238 {
239 struct pipe_surface *surf = CALLOC_STRUCT(pipe_surface);
240 if (surf) {
241 surf->format = format;
242 surf->refcount = 1;
243 surf->winsys = winsys;
244 }
245 return surf;
246 }
247
248
249 static void
250 intel_i915_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
251 {
252 struct pipe_surface *surf = *s;
253 surf->refcount--;
254 if (surf->refcount == 0) {
255 if (surf->region)
256 winsys->region_release(winsys, &surf->region);
257 free(surf);
258 }
259 *s = NULL;
260 }
261
262
263
264 static void
265 intel_printf( struct pipe_winsys *winsys, const char *fmtString, ... )
266 {
267 va_list args;
268 va_start( args, fmtString );
269 vfprintf(stderr, fmtString, args);
270 va_end( args );
271 }
272
273 static const char *
274 intel_get_name( struct pipe_winsys *winsys )
275 {
276 return "Intel/DRI/ttm";
277 }
278
279
280 struct pipe_winsys *
281 intel_create_pipe_winsys( int fd )
282 {
283 struct intel_pipe_winsys *iws = CALLOC_STRUCT( intel_pipe_winsys );
284
285 /* Fill in this struct with callbacks that pipe will need to
286 * communicate with the window system, buffer manager, etc.
287 *
288 * Pipe would be happy with a malloc based memory manager, but
289 * the SwapBuffers implementation in this winsys driver requires
290 * that rendering be done to an appropriate _DriBufferObject.
291 */
292 iws->winsys.buffer_create = intel_buffer_create;
293 iws->winsys.user_buffer_create = intel_user_buffer_create;
294 iws->winsys.buffer_map = intel_buffer_map;
295 iws->winsys.buffer_unmap = intel_buffer_unmap;
296 iws->winsys.buffer_reference = intel_buffer_reference;
297 iws->winsys.buffer_data = intel_buffer_data;
298 iws->winsys.buffer_subdata = intel_buffer_subdata;
299 iws->winsys.buffer_get_subdata = intel_buffer_get_subdata;
300 iws->winsys.flush_frontbuffer = intel_flush_frontbuffer;
301 iws->winsys.printf = intel_printf;
302 iws->winsys.get_name = intel_get_name;
303 iws->winsys.region_alloc = intel_i915_region_alloc;
304 iws->winsys.region_release = intel_i915_region_release;
305 iws->winsys.surface_pitch = intel_i915_surface_pitch;
306 iws->winsys.surface_alloc = intel_i915_surface_alloc;
307 iws->winsys.surface_release = intel_i915_surface_release;
308
309 if (fd)
310 iws->regionPool = driDRMPoolInit(fd);
311
312 return &iws->winsys;
313 }
314
315
316 void
317 intel_destroy_pipe_winsys( struct pipe_winsys *winsys )
318 {
319 struct intel_pipe_winsys *iws = intel_pipe_winsys(winsys);
320 if (iws->regionPool) {
321 driPoolTakeDown(iws->regionPool);
322 }
323 free(iws);
324 }
325