radeon/r200/r300: cleanup some of the renderbuffer code
[mesa.git] / src / gallium / state_trackers / glx / dri / dri_drawable.c
1 /**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
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 above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "dri_screen.h"
29 #include "dri_context.h"
30 #include "dri_swapbuffers.h"
31
32 #include "pipe/p_context.h"
33 #include "state_tracker/st_public.h"
34 #include "state_tracker/st_context.h"
35 #include "state_tracker/st_cb_fbo.h"
36
37
38 static void
39 blit_swapbuffers(__DRIdrawablePrivate *dPriv,
40 __DRIcontextPrivate *cPriv,
41 struct pipe_surface *src,
42 const drm_clip_rect_t *rect)
43 {
44 struct dri_screen *screen = dri_screen(dPriv->driScreenPriv);
45 struct dri_drawable *fb = dri_drawable(dPriv);
46 struct dri_context *context = dri_context(cPriv);
47
48 const int nbox = dPriv->numClipRects;
49 const drm_clip_rect_t *pbox = dPriv->pClipRects;
50
51 struct pipe_surface *dest = fb->front_surface;
52 const int backWidth = fb->stfb->Base.Width;
53 const int backHeight = fb->stfb->Base.Height;
54 int i;
55
56 for (i = 0; i < nbox; i++, pbox++) {
57 drm_clip_rect_t box;
58 drm_clip_rect_t sbox;
59
60 if (pbox->x1 > pbox->x2 ||
61 pbox->y1 > pbox->y2 ||
62 (pbox->x2 - pbox->x1) > dest->width ||
63 (pbox->y2 - pbox->y1) > dest->height)
64 continue;
65
66 box = *pbox;
67
68 if (rect) {
69 drm_clip_rect_t rrect;
70
71 rrect.x1 = dPriv->x + rect->x1;
72 rrect.y1 = (dPriv->h - rect->y1 - rect->y2) + dPriv->y;
73 rrect.x2 = rect->x2 + rrect.x1;
74 rrect.y2 = rect->y2 + rrect.y1;
75 if (rrect.x1 > box.x1)
76 box.x1 = rrect.x1;
77 if (rrect.y1 > box.y1)
78 box.y1 = rrect.y1;
79 if (rrect.x2 < box.x2)
80 box.x2 = rrect.x2;
81 if (rrect.y2 < box.y2)
82 box.y2 = rrect.y2;
83
84 if (box.x1 > box.x2 || box.y1 > box.y2)
85 continue;
86 }
87
88 /* restrict blit to size of actually rendered area */
89 if (box.x2 - box.x1 > backWidth)
90 box.x2 = backWidth + box.x1;
91 if (box.y2 - box.y1 > backHeight)
92 box.y2 = backHeight + box.y1;
93
94 debug_printf("%s: box %d,%d-%d,%d\n", __FUNCTION__,
95 box.x1, box.y1, box.x2, box.y2);
96
97 sbox.x1 = box.x1 - dPriv->x;
98 sbox.y1 = box.y1 - dPriv->y;
99
100 ctx->st->pipe->surface_copy( ctx->st->pipe,
101 FALSE,
102 dest,
103 box.x1, box.y1,
104 src,
105 sbox.x1, sbox.y1,
106 box.x2 - box.x1,
107 box.y2 - box.y1 );
108 }
109 }
110
111 /**
112 * Display a colorbuffer surface in an X window.
113 * Used for SwapBuffers and flushing front buffer rendering.
114 *
115 * \param dPriv the window/drawable to display into
116 * \param surf the surface to display
117 * \param rect optional subrect of surface to display (may be NULL).
118 */
119 static void
120 dri_display_surface(__DRIdrawablePrivate *dPriv,
121 struct pipe_surface *source,
122 const drm_clip_rect_t *rect)
123 {
124 struct dri_drawable *drawable = dri_drawable(dPriv);
125 struct dri_screen *screen = dri_screen(dPriv->driScreenPriv);
126 struct dri_context *context = screen->dummy_context;
127 struct pipe_winsys *winsys = screen->winsys;
128
129 if (!context)
130 return;
131
132 if (drawable->last_swap_fence) {
133 winsys->fence_finish( winsys,
134 drawable->last_swap_fence,
135 0 );
136
137 winsys->fence_reference( winsys,
138 &drawable->last_swap_fence,
139 NULL );
140 }
141
142 drawable->last_swap_fence = drawable->first_swap_fence;
143 drawable->first_swap_fence = NULL;
144
145 /* Call lock_hardware to update dPriv cliprects.
146 */
147 dri_lock_hardware(context, drawable);
148 {
149 if (dPriv->numClipRects) {
150 blit_swapbuffers( context, dPriv, source, rect );
151 }
152 }
153 dri_unlock_hardware(context);
154
155 if (drawble->stamp != drawable->dPriv->lastStamp) {
156 dri_update_window_size( dpriv );
157 }
158 }
159
160
161
162 /**
163 * This will be called a drawable is known to have moved/resized.
164 */
165 void
166 dri_update_window_size(__DRIdrawablePrivate *dPriv)
167 {
168 struct dri_drawable *drawable = dri_drawable(dPriv);
169 st_resize_framebuffer(drawable->stfb, dPriv->w, dPriv->h);
170 drawable->stamp = dPriv->lastStamp;
171 }
172
173
174
175 void
176 dri_swap_buffers(__DRIdrawablePrivate * dPriv)
177 {
178 struct dri_drawable *drawable = dri_drawable(dPriv);
179 struct pipe_surface *back_surf;
180
181 assert(drawable);
182 assert(drawable->stfb);
183
184 back_surf = st_get_framebuffer_surface(drawable->stfb,
185 ST_SURFACE_BACK_LEFT);
186 if (back_surf) {
187 st_notify_swapbuffers(drawable->stfb);
188 dri_display_surface(dPriv, back_surf, NULL);
189 st_notify_swapbuffers_complete(drawable->stfb);
190 }
191 }
192
193
194 /**
195 * Called via glXCopySubBufferMESA() to copy a subrect of the back
196 * buffer to the front buffer/screen.
197 */
198 void
199 dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
200 {
201 struct dri_drawable *drawable = dri_drawable(dPriv);
202 struct pipe_surface *back_surf;
203
204 assert(drawable);
205 assert(drawable->stfb);
206
207 back_surf = st_get_framebuffer_surface(drawable->stfb,
208 ST_SURFACE_BACK_LEFT);
209 if (back_surf) {
210 drm_clip_rect_t rect;
211 rect.x1 = x;
212 rect.y1 = y;
213 rect.x2 = w;
214 rect.y2 = h;
215
216 st_notify_swapbuffers(drawable->stfb);
217 dri_display_surface(dPriv, back_surf, &rect);
218 }
219 }
220
221
222
223 /*
224 * The state tracker keeps track of whether the fake frontbuffer has
225 * been touched by any rendering since the last time we copied its
226 * contents to the real frontbuffer. Our task is easy:
227 */
228 static void
229 dri_flush_frontbuffer( struct pipe_winsys *winsys,
230 struct pipe_surface *surf,
231 void *context_private)
232 {
233 struct dri_context *dri = (struct dri_context *) context_private;
234 __DRIdrawablePrivate *dPriv = dri->driDrawable;
235
236 dri_display_surface(dPriv, surf, NULL);
237 }
238
239
240
241 /* Need to create a surface which wraps the front surface to support
242 * client-side swapbuffers.
243 */
244 static void
245 dri_create_front_surface(struct dri_screen *screen,
246 struct pipe_winsys *winsys,
247 unsigned handle)
248 {
249 struct pipe_screen *pipe_screen = screen->pipe_screen;
250 struct pipe_texture *texture;
251 struct pipe_texture templat;
252 struct pipe_surface *surface;
253 struct pipe_buffer *buffer;
254 unsigned pitch;
255
256 assert(screen->front.cpp == 4);
257
258 // buffer = dri_buffer_from_handle(screen->winsys,
259 // "front", handle);
260
261 if (!buffer)
262 return;
263
264 screen->front.buffer = dri_bo(buffer);
265
266 memset(&templat, 0, sizeof(templat));
267 templat.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
268 templat.target = PIPE_TEXTURE_2D;
269 templat.last_level = 0;
270 templat.depth[0] = 1;
271 templat.format = PIPE_FORMAT_A8R8G8B8_UNORM;
272 templat.width[0] = screen->front.width;
273 templat.height[0] = screen->front.height;
274 pf_get_block(templat.format, &templat.block);
275 pitch = screen->front.pitch;
276
277 texture = pipe_screen->texture_blanket(pipe_screen,
278 &templat,
279 &pitch,
280 buffer);
281
282 /* Unref the buffer we don't need it anyways */
283 pipe_buffer_reference(screen, &buffer, NULL);
284
285 surface = pipe_screen->get_tex_surface(pipe_screen,
286 texture,
287 0,
288 0,
289 0,
290 PIPE_BUFFER_USAGE_GPU_WRITE);
291
292 screen->front.texture = texture;
293 screen->front.surface = surface;
294 }
295
296 /**
297 * This is called when we need to set up GL rendering to a new X window.
298 */
299 static boolean
300 dri_create_buffer(__DRIscreenPrivate *sPriv,
301 __DRIdrawablePrivate *dPriv,
302 const __GLcontextModes *visual,
303 boolean isPixmap)
304 {
305 enum pipe_format colorFormat, depthFormat, stencilFormat;
306 struct dri_drawable *drawable;
307
308 if (isPixmap)
309 goto fail; /* not implemented */
310
311 drawable = CALLOC_STRUCT(dri_drawable);
312 if (drawable == NULL)
313 goto fail;
314
315 /* XXX: todo: use the pipe_screen queries to figure out which
316 * render targets are supportable.
317 */
318 if (visual->redBits == 5)
319 colorFormat = PIPE_FORMAT_R5G6B5_UNORM;
320 else
321 colorFormat = PIPE_FORMAT_A8R8G8B8_UNORM;
322
323 if (visual->depthBits == 16)
324 depthFormat = PIPE_FORMAT_Z16_UNORM;
325 else if (visual->depthBits == 24) {
326 if (visual->stencilBits == 8)
327 depthFormat = PIPE_FORMAT_S8Z24_UNORM;
328 else
329 depthFormat = PIPE_FORMAT_X8Z24_UNORM;
330 }
331
332 drawable->stfb = st_create_framebuffer(visual,
333 colorFormat,
334 depthFormat,
335 dPriv->w,
336 dPriv->h,
337 (void*) drawable);
338 if (drawable->stfb == NULL)
339 goto fail;
340
341 dPriv->driverPrivate = (void *) drawable;
342 return GL_TRUE;
343
344 fail:
345 FREE(drawable);
346 return GL_FALSE;
347 }
348
349 static void
350 dri_destroy_buffer(__DRIdrawablePrivate *dPriv)
351 {
352 struct dri_drawable *drawable = dri_drawable(dPriv);
353
354 /* No particular need to wait on fences before dereferencing them:
355 */
356 winsys->fence_reference( winsys, &ctx->last_swap_fence, NULL );
357 winsys->fence_reference( winsys, &ctx->first_swap_fence, NULL );
358
359 st_unreference_framebuffer(drawable->stfb);
360
361 FREE(drawable);
362 }
363