Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 1999-2006 Brian Paul 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 "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | */ |
||
24 | |||
25 | |||
26 | /** |
||
27 | * \file xm_dd.h |
||
28 | * General device driver functions for Xlib driver. |
||
29 | */ |
||
30 | |||
31 | #include "glxheader.h" |
||
32 | #include "main/bufferobj.h" |
||
33 | #include "main/context.h" |
||
34 | #include "main/colormac.h" |
||
35 | #include "main/fbobject.h" |
||
36 | #include "main/macros.h" |
||
37 | #include "main/mipmap.h" |
||
38 | #include "main/image.h" |
||
39 | #include "main/imports.h" |
||
40 | #include "main/mtypes.h" |
||
41 | #include "main/pbo.h" |
||
42 | #include "main/texformat.h" |
||
43 | #include "swrast/swrast.h" |
||
44 | #include "swrast/s_context.h" |
||
45 | #include "swrast_setup/swrast_setup.h" |
||
46 | #include "tnl/tnl.h" |
||
47 | #include "tnl/t_context.h" |
||
48 | #include "drivers/common/meta.h" |
||
49 | #include "xmesaP.h" |
||
50 | |||
51 | |||
52 | static void |
||
53 | finish_or_flush( struct gl_context *ctx ) |
||
54 | { |
||
55 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
56 | if (xmesa) { |
||
57 | _glthread_LOCK_MUTEX(_xmesa_lock); |
||
58 | XSync( xmesa->display, False ); |
||
59 | _glthread_UNLOCK_MUTEX(_xmesa_lock); |
||
60 | } |
||
61 | } |
||
62 | |||
63 | |||
64 | /* Implements glColorMask() */ |
||
65 | static void |
||
66 | color_mask(struct gl_context *ctx, |
||
67 | GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask) |
||
68 | { |
||
69 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
70 | XMesaBuffer xmbuf; |
||
71 | const int xclass = xmesa->xm_visual->visualType; |
||
72 | (void) amask; |
||
73 | |||
74 | if (_mesa_is_user_fbo(ctx->DrawBuffer)) |
||
75 | return; |
||
76 | |||
77 | xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
78 | |||
79 | if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { |
||
80 | unsigned long m; |
||
81 | if (rmask && gmask && bmask) { |
||
82 | m = ((unsigned long)~0L); |
||
83 | } |
||
84 | else { |
||
85 | m = 0; |
||
86 | if (rmask) m |= GET_REDMASK(xmesa->xm_visual); |
||
87 | if (gmask) m |= GET_GREENMASK(xmesa->xm_visual); |
||
88 | if (bmask) m |= GET_BLUEMASK(xmesa->xm_visual); |
||
89 | } |
||
90 | XMesaSetPlaneMask( xmesa->display, xmbuf->cleargc, m ); |
||
91 | } |
||
92 | } |
||
93 | |||
94 | |||
95 | |||
96 | /**********************************************************************/ |
||
97 | /*** glClear implementations ***/ |
||
98 | /**********************************************************************/ |
||
99 | |||
100 | |||
101 | /** |
||
102 | * Clear the front or back color buffer, if it's implemented with a pixmap. |
||
103 | */ |
||
104 | static void |
||
105 | clear_pixmap(struct gl_context *ctx, struct xmesa_renderbuffer *xrb, |
||
106 | GLint x, GLint y, GLint width, GLint height) |
||
107 | { |
||
108 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
109 | XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
110 | |||
111 | assert(xmbuf); |
||
112 | assert(xrb->pixmap); |
||
113 | assert(xmesa); |
||
114 | assert(xmesa->display); |
||
115 | assert(xrb->pixmap); |
||
116 | assert(xmbuf->cleargc); |
||
117 | |||
118 | XMesaFillRectangle( xmesa->display, xrb->pixmap, xmbuf->cleargc, |
||
119 | x, xrb->Base.Base.Height - y - height, |
||
120 | width, height ); |
||
121 | } |
||
122 | |||
123 | |||
124 | static void |
||
125 | clear_16bit_ximage( struct gl_context *ctx, struct xmesa_renderbuffer *xrb, |
||
126 | GLint x, GLint y, GLint width, GLint height) |
||
127 | { |
||
128 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
129 | GLuint pixel = (GLuint) xmesa->clearpixel; |
||
130 | GLint i, j; |
||
131 | |||
132 | if (xmesa->swapbytes) { |
||
133 | pixel = ((pixel >> 8) & 0x00ff) | ((pixel << 8) & 0xff00); |
||
134 | } |
||
135 | |||
136 | for (j = 0; j < height; j++) { |
||
137 | GLushort *ptr2 = PIXEL_ADDR2(xrb, x, y + j); |
||
138 | for (i = 0; i < width; i++) { |
||
139 | ptr2[i] = pixel; |
||
140 | } |
||
141 | } |
||
142 | } |
||
143 | |||
144 | |||
145 | /* Optimized code provided by Nozomi Ytow |
||
146 | static void |
||
147 | clear_24bit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb, |
||
148 | GLint x, GLint y, GLint width, GLint height) |
||
149 | { |
||
150 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
151 | const GLubyte r = xmesa->clearcolor[0]; |
||
152 | const GLubyte g = xmesa->clearcolor[1]; |
||
153 | const GLubyte b = xmesa->clearcolor[2]; |
||
154 | |||
155 | if (r == g && g == b) { |
||
156 | /* same value for all three components (gray) */ |
||
157 | GLint j; |
||
158 | for (j = 0; j < height; j++) { |
||
159 | bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j); |
||
160 | memset(ptr3, r, 3 * width); |
||
161 | } |
||
162 | } |
||
163 | else { |
||
164 | /* non-gray clear color */ |
||
165 | GLint i, j; |
||
166 | for (j = 0; j < height; j++) { |
||
167 | bgr_t *ptr3 = PIXEL_ADDR3(xrb, x, y + j); |
||
168 | for (i = 0; i < width; i++) { |
||
169 | ptr3->r = r; |
||
170 | ptr3->g = g; |
||
171 | ptr3->b = b; |
||
172 | ptr3++; |
||
173 | } |
||
174 | } |
||
175 | } |
||
176 | } |
||
177 | |||
178 | |||
179 | static void |
||
180 | clear_32bit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb, |
||
181 | GLint x, GLint y, GLint width, GLint height) |
||
182 | { |
||
183 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
184 | register GLuint pixel = (GLuint) xmesa->clearpixel; |
||
185 | |||
186 | if (!xrb->ximage) |
||
187 | return; |
||
188 | |||
189 | if (xmesa->swapbytes) { |
||
190 | pixel = ((pixel >> 24) & 0x000000ff) |
||
191 | | ((pixel >> 8) & 0x0000ff00) |
||
192 | | ((pixel << 8) & 0x00ff0000) |
||
193 | | ((pixel << 24) & 0xff000000); |
||
194 | } |
||
195 | |||
196 | if (width == xrb->Base.Base.Width && height == xrb->Base.Base.Height) { |
||
197 | /* clearing whole buffer */ |
||
198 | const GLuint n = xrb->Base.Base.Width * xrb->Base.Base.Height; |
||
199 | GLuint *ptr4 = (GLuint *) xrb->ximage->data; |
||
200 | if (pixel == 0) { |
||
201 | /* common case */ |
||
202 | memset(ptr4, pixel, 4 * n); |
||
203 | } |
||
204 | else { |
||
205 | GLuint i; |
||
206 | for (i = 0; i < n; i++) |
||
207 | ptr4[i] = pixel; |
||
208 | } |
||
209 | } |
||
210 | else { |
||
211 | /* clearing scissored region */ |
||
212 | GLint i, j; |
||
213 | for (j = 0; j < height; j++) { |
||
214 | GLuint *ptr4 = PIXEL_ADDR4(xrb, x, y + j); |
||
215 | for (i = 0; i < width; i++) { |
||
216 | ptr4[i] = pixel; |
||
217 | } |
||
218 | } |
||
219 | } |
||
220 | } |
||
221 | |||
222 | |||
223 | static void |
||
224 | clear_nbit_ximage(struct gl_context *ctx, struct xmesa_renderbuffer *xrb, |
||
225 | GLint x, GLint y, GLint width, GLint height) |
||
226 | { |
||
227 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
228 | XMesaImage *img = xrb->ximage; |
||
229 | GLint i, j; |
||
230 | |||
231 | /* TODO: optimize this */ |
||
232 | y = YFLIP(xrb, y); |
||
233 | for (j = 0; j < height; j++) { |
||
234 | for (i = 0; i < width; i++) { |
||
235 | XMesaPutPixel(img, x+i, y-j, xmesa->clearpixel); |
||
236 | } |
||
237 | } |
||
238 | } |
||
239 | |||
240 | |||
241 | |||
242 | static void |
||
243 | clear_buffers(struct gl_context *ctx, GLbitfield buffers) |
||
244 | { |
||
245 | if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { |
||
246 | /* this is a window system framebuffer */ |
||
247 | const GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask[0]; |
||
248 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
249 | XMesaBuffer b = XMESA_BUFFER(ctx->DrawBuffer); |
||
250 | const GLint x = ctx->DrawBuffer->_Xmin; |
||
251 | const GLint y = ctx->DrawBuffer->_Ymin; |
||
252 | const GLint width = ctx->DrawBuffer->_Xmax - x; |
||
253 | const GLint height = ctx->DrawBuffer->_Ymax - y; |
||
254 | |||
255 | _mesa_unclamped_float_rgba_to_ubyte(xmesa->clearcolor, |
||
256 | ctx->Color.ClearColor.f); |
||
257 | xmesa->clearpixel = xmesa_color_to_pixel(ctx, |
||
258 | xmesa->clearcolor[0], |
||
259 | xmesa->clearcolor[1], |
||
260 | xmesa->clearcolor[2], |
||
261 | xmesa->clearcolor[3], |
||
262 | xmesa->xm_visual->undithered_pf); |
||
263 | XMesaSetForeground(xmesa->display, b->cleargc, xmesa->clearpixel); |
||
264 | |||
265 | /* we can't handle color or index masking */ |
||
266 | if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) { |
||
267 | if (buffers & BUFFER_BIT_FRONT_LEFT) { |
||
268 | /* clear front color buffer */ |
||
269 | struct gl_renderbuffer *frontRb |
||
270 | = ctx->DrawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; |
||
271 | if (b->frontxrb == xmesa_renderbuffer(frontRb)) { |
||
272 | /* renderbuffer is not wrapped - great! */ |
||
273 | b->frontxrb->clearFunc(ctx, b->frontxrb, x, y, width, height); |
||
274 | buffers &= ~BUFFER_BIT_FRONT_LEFT; |
||
275 | } |
||
276 | else { |
||
277 | /* we can't directly clear an alpha-wrapped color buffer */ |
||
278 | } |
||
279 | } |
||
280 | if (buffers & BUFFER_BIT_BACK_LEFT) { |
||
281 | /* clear back color buffer */ |
||
282 | struct gl_renderbuffer *backRb |
||
283 | = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer; |
||
284 | if (b->backxrb == xmesa_renderbuffer(backRb)) { |
||
285 | /* renderbuffer is not wrapped - great! */ |
||
286 | b->backxrb->clearFunc(ctx, b->backxrb, x, y, width, height); |
||
287 | buffers &= ~BUFFER_BIT_BACK_LEFT; |
||
288 | } |
||
289 | } |
||
290 | } |
||
291 | } |
||
292 | if (buffers) |
||
293 | _swrast_Clear(ctx, buffers); |
||
294 | } |
||
295 | |||
296 | |||
297 | /* XXX these functions haven't been tested in the Xserver environment */ |
||
298 | |||
299 | |||
300 | /** |
||
301 | * Check if we can do an optimized glDrawPixels into an 8R8G8B visual. |
||
302 | */ |
||
303 | static GLboolean |
||
304 | can_do_DrawPixels_8R8G8B(struct gl_context *ctx, GLenum format, GLenum type) |
||
305 | { |
||
306 | if (format == GL_BGRA && |
||
307 | type == GL_UNSIGNED_BYTE && |
||
308 | ctx->DrawBuffer && |
||
309 | _mesa_is_winsys_fbo(ctx->DrawBuffer) && |
||
310 | ctx->Pixel.ZoomX == 1.0 && /* no zooming */ |
||
311 | ctx->Pixel.ZoomY == 1.0 && |
||
312 | ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) { |
||
313 | const SWcontext *swrast = SWRAST_CONTEXT(ctx); |
||
314 | |||
315 | if (swrast->NewState) |
||
316 | _swrast_validate_derived( ctx ); |
||
317 | |||
318 | if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ { |
||
319 | struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; |
||
320 | if (rb) { |
||
321 | struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); |
||
322 | if (xrb && |
||
323 | xrb->pixmap && /* drawing to pixmap or window */ |
||
324 | _mesa_get_format_bits(xrb->Base.Base.Format, GL_ALPHA_BITS) == 0) { |
||
325 | return GL_TRUE; |
||
326 | } |
||
327 | } |
||
328 | } |
||
329 | } |
||
330 | return GL_FALSE; |
||
331 | } |
||
332 | |||
333 | |||
334 | /** |
||
335 | * This function implements glDrawPixels() with an XPutImage call when |
||
336 | * drawing to the front buffer (X Window drawable). |
||
337 | * The image format must be GL_BGRA to match the PF_8R8G8B pixel format. |
||
338 | */ |
||
339 | static void |
||
340 | xmesa_DrawPixels_8R8G8B( struct gl_context *ctx, |
||
341 | GLint x, GLint y, GLsizei width, GLsizei height, |
||
342 | GLenum format, GLenum type, |
||
343 | const struct gl_pixelstore_attrib *unpack, |
||
344 | const GLvoid *pixels ) |
||
345 | { |
||
346 | if (can_do_DrawPixels_8R8G8B(ctx, format, type)) { |
||
347 | const SWcontext *swrast = SWRAST_CONTEXT( ctx ); |
||
348 | struct gl_pixelstore_attrib clippedUnpack = *unpack; |
||
349 | int dstX = x; |
||
350 | int dstY = y; |
||
351 | int w = width; |
||
352 | int h = height; |
||
353 | |||
354 | if (swrast->NewState) |
||
355 | _swrast_validate_derived( ctx ); |
||
356 | |||
357 | if (_mesa_is_bufferobj(unpack->BufferObj)) { |
||
358 | /* unpack from PBO */ |
||
359 | GLubyte *buf; |
||
360 | if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, |
||
361 | format, type, INT_MAX, pixels)) { |
||
362 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
363 | "glDrawPixels(invalid PBO access)"); |
||
364 | return; |
||
365 | } |
||
366 | buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, |
||
367 | unpack->BufferObj->Size, |
||
368 | GL_MAP_READ_BIT, |
||
369 | unpack->BufferObj); |
||
370 | if (!buf) { |
||
371 | /* buffer is already mapped - that's an error */ |
||
372 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
373 | "glDrawPixels(PBO is mapped)"); |
||
374 | return; |
||
375 | } |
||
376 | pixels = ADD_POINTERS(buf, pixels); |
||
377 | } |
||
378 | |||
379 | if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { |
||
380 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
381 | XMesaDisplay *dpy = xmesa->xm_visual->display; |
||
382 | XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
383 | const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ |
||
384 | struct xmesa_renderbuffer *xrb |
||
385 | = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); |
||
386 | const int srcX = clippedUnpack.SkipPixels; |
||
387 | const int srcY = clippedUnpack.SkipRows; |
||
388 | const int rowLength = clippedUnpack.RowLength; |
||
389 | XMesaImage ximage; |
||
390 | |||
391 | ASSERT(xmesa->xm_visual->dithered_pf == PF_8R8G8B); |
||
392 | ASSERT(xmesa->xm_visual->undithered_pf == PF_8R8G8B); |
||
393 | ASSERT(dpy); |
||
394 | ASSERT(gc); |
||
395 | |||
396 | /* This is a little tricky since all coordinates up to now have |
||
397 | * been in the OpenGL bottom-to-top orientation. X is top-to-bottom |
||
398 | * so we have to carefully compute the Y coordinates/addresses here. |
||
399 | */ |
||
400 | memset(&ximage, 0, sizeof(XMesaImage)); |
||
401 | ximage.width = width; |
||
402 | ximage.height = height; |
||
403 | ximage.format = ZPixmap; |
||
404 | ximage.data = (char *) pixels |
||
405 | + ((srcY + h - 1) * rowLength + srcX) * 4; |
||
406 | ximage.byte_order = LSBFirst; |
||
407 | ximage.bitmap_unit = 32; |
||
408 | ximage.bitmap_bit_order = LSBFirst; |
||
409 | ximage.bitmap_pad = 32; |
||
410 | ximage.depth = 32; |
||
411 | ximage.bits_per_pixel = 32; |
||
412 | ximage.bytes_per_line = -rowLength * 4; /* negative to flip image */ |
||
413 | /* it seems we don't need to set the ximage.red/green/blue_mask fields */ |
||
414 | /* flip Y axis for dest position */ |
||
415 | dstY = YFLIP(xrb, dstY) - h + 1; |
||
416 | XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); |
||
417 | } |
||
418 | |||
419 | if (_mesa_is_bufferobj(unpack->BufferObj)) { |
||
420 | ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj); |
||
421 | } |
||
422 | } |
||
423 | else { |
||
424 | /* software fallback */ |
||
425 | _swrast_DrawPixels(ctx, x, y, width, height, |
||
426 | format, type, unpack, pixels); |
||
427 | } |
||
428 | } |
||
429 | |||
430 | |||
431 | |||
432 | /** |
||
433 | * Check if we can do an optimized glDrawPixels into an 5R6G5B visual. |
||
434 | */ |
||
435 | static GLboolean |
||
436 | can_do_DrawPixels_5R6G5B(struct gl_context *ctx, GLenum format, GLenum type) |
||
437 | { |
||
438 | if (format == GL_RGB && |
||
439 | type == GL_UNSIGNED_SHORT_5_6_5 && |
||
440 | !ctx->Color.DitherFlag && /* no dithering */ |
||
441 | ctx->DrawBuffer && |
||
442 | _mesa_is_winsys_fbo(ctx->DrawBuffer) && |
||
443 | ctx->Pixel.ZoomX == 1.0 && /* no zooming */ |
||
444 | ctx->Pixel.ZoomY == 1.0 && |
||
445 | ctx->_ImageTransferState == 0 /* no color tables, scale/bias, etc */) { |
||
446 | const SWcontext *swrast = SWRAST_CONTEXT(ctx); |
||
447 | |||
448 | if (swrast->NewState) |
||
449 | _swrast_validate_derived( ctx ); |
||
450 | |||
451 | if ((swrast->_RasterMask & ~CLIP_BIT) == 0) /* no blend, z-test, etc */ { |
||
452 | struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; |
||
453 | if (rb) { |
||
454 | struct xmesa_renderbuffer *xrb = xmesa_renderbuffer(rb); |
||
455 | if (xrb && |
||
456 | xrb->pixmap && /* drawing to pixmap or window */ |
||
457 | _mesa_get_format_bits(xrb->Base.Base.Format, GL_ALPHA_BITS) == 0) { |
||
458 | return GL_TRUE; |
||
459 | } |
||
460 | } |
||
461 | } |
||
462 | } |
||
463 | return GL_FALSE; |
||
464 | } |
||
465 | |||
466 | |||
467 | /** |
||
468 | * This function implements glDrawPixels() with an XPutImage call when |
||
469 | * drawing to the front buffer (X Window drawable). The image format |
||
470 | * must be GL_RGB and image type must be GL_UNSIGNED_SHORT_5_6_5 to |
||
471 | * match the PF_5R6G5B pixel format. |
||
472 | */ |
||
473 | static void |
||
474 | xmesa_DrawPixels_5R6G5B( struct gl_context *ctx, |
||
475 | GLint x, GLint y, GLsizei width, GLsizei height, |
||
476 | GLenum format, GLenum type, |
||
477 | const struct gl_pixelstore_attrib *unpack, |
||
478 | const GLvoid *pixels ) |
||
479 | { |
||
480 | if (can_do_DrawPixels_5R6G5B(ctx, format, type)) { |
||
481 | const SWcontext *swrast = SWRAST_CONTEXT( ctx ); |
||
482 | struct gl_pixelstore_attrib clippedUnpack = *unpack; |
||
483 | int dstX = x; |
||
484 | int dstY = y; |
||
485 | int w = width; |
||
486 | int h = height; |
||
487 | |||
488 | if (swrast->NewState) |
||
489 | _swrast_validate_derived( ctx ); |
||
490 | |||
491 | if (_mesa_is_bufferobj(unpack->BufferObj)) { |
||
492 | /* unpack from PBO */ |
||
493 | GLubyte *buf; |
||
494 | if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, |
||
495 | format, type, INT_MAX, pixels)) { |
||
496 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
497 | "glDrawPixels(invalid PBO access)"); |
||
498 | return; |
||
499 | } |
||
500 | buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, |
||
501 | unpack->BufferObj->Size, |
||
502 | GL_MAP_READ_BIT, |
||
503 | unpack->BufferObj); |
||
504 | if (!buf) { |
||
505 | /* buffer is already mapped - that's an error */ |
||
506 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
507 | "glDrawPixels(PBO is mapped)"); |
||
508 | return; |
||
509 | } |
||
510 | pixels = ADD_POINTERS(buf, pixels); |
||
511 | } |
||
512 | |||
513 | if (_mesa_clip_drawpixels(ctx, &dstX, &dstY, &w, &h, &clippedUnpack)) { |
||
514 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
515 | XMesaDisplay *dpy = xmesa->xm_visual->display; |
||
516 | XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
517 | const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ |
||
518 | struct xmesa_renderbuffer *xrb |
||
519 | = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); |
||
520 | const int srcX = clippedUnpack.SkipPixels; |
||
521 | const int srcY = clippedUnpack.SkipRows; |
||
522 | const int rowLength = clippedUnpack.RowLength; |
||
523 | XMesaImage ximage; |
||
524 | |||
525 | ASSERT(xmesa->xm_visual->undithered_pf == PF_5R6G5B); |
||
526 | ASSERT(dpy); |
||
527 | ASSERT(gc); |
||
528 | |||
529 | /* This is a little tricky since all coordinates up to now have |
||
530 | * been in the OpenGL bottom-to-top orientation. X is top-to-bottom |
||
531 | * so we have to carefully compute the Y coordinates/addresses here. |
||
532 | */ |
||
533 | memset(&ximage, 0, sizeof(XMesaImage)); |
||
534 | ximage.width = width; |
||
535 | ximage.height = height; |
||
536 | ximage.format = ZPixmap; |
||
537 | ximage.data = (char *) pixels |
||
538 | + ((srcY + h - 1) * rowLength + srcX) * 2; |
||
539 | ximage.byte_order = LSBFirst; |
||
540 | ximage.bitmap_unit = 16; |
||
541 | ximage.bitmap_bit_order = LSBFirst; |
||
542 | ximage.bitmap_pad = 16; |
||
543 | ximage.depth = 16; |
||
544 | ximage.bits_per_pixel = 16; |
||
545 | ximage.bytes_per_line = -rowLength * 2; /* negative to flip image */ |
||
546 | /* it seems we don't need to set the ximage.red/green/blue_mask fields */ |
||
547 | /* flip Y axis for dest position */ |
||
548 | dstY = YFLIP(xrb, dstY) - h + 1; |
||
549 | XPutImage(dpy, xrb->pixmap, gc, &ximage, 0, 0, dstX, dstY, w, h); |
||
550 | } |
||
551 | |||
552 | if (unpack->BufferObj->Name) { |
||
553 | ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj); |
||
554 | } |
||
555 | } |
||
556 | else { |
||
557 | /* software fallback */ |
||
558 | _swrast_DrawPixels(ctx, x, y, width, height, |
||
559 | format, type, unpack, pixels); |
||
560 | } |
||
561 | } |
||
562 | |||
563 | |||
564 | /** |
||
565 | * Determine if we can do an optimized glCopyPixels. |
||
566 | */ |
||
567 | static GLboolean |
||
568 | can_do_CopyPixels(struct gl_context *ctx, GLenum type) |
||
569 | { |
||
570 | if (type == GL_COLOR && |
||
571 | ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */ |
||
572 | ctx->Pixel.ZoomX == 1.0 && /* no zooming */ |
||
573 | ctx->Pixel.ZoomY == 1.0 && |
||
574 | ctx->Color.DrawBuffer[0] == GL_FRONT && /* copy to front buf */ |
||
575 | ctx->Pixel.ReadBuffer == GL_FRONT && /* copy from front buf */ |
||
576 | ctx->ReadBuffer->_ColorReadBuffer && |
||
577 | ctx->DrawBuffer->_ColorDrawBuffers[0]) { |
||
578 | const SWcontext *swrast = SWRAST_CONTEXT( ctx ); |
||
579 | |||
580 | if (swrast->NewState) |
||
581 | _swrast_validate_derived( ctx ); |
||
582 | |||
583 | if ((swrast->_RasterMask & ~CLIP_BIT) == 0x0 && |
||
584 | ctx->ReadBuffer && |
||
585 | ctx->ReadBuffer->_ColorReadBuffer && |
||
586 | ctx->DrawBuffer && |
||
587 | ctx->DrawBuffer->_ColorDrawBuffers[0]) { |
||
588 | struct xmesa_renderbuffer *srcXrb |
||
589 | = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); |
||
590 | struct xmesa_renderbuffer *dstXrb |
||
591 | = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); |
||
592 | if (srcXrb->pixmap && dstXrb->pixmap) { |
||
593 | return GL_TRUE; |
||
594 | } |
||
595 | } |
||
596 | } |
||
597 | return GL_FALSE; |
||
598 | } |
||
599 | |||
600 | |||
601 | /** |
||
602 | * Implement glCopyPixels for the front color buffer (or back buffer Pixmap) |
||
603 | * for the color buffer. Don't support zooming, pixel transfer, etc. |
||
604 | * We do support copying from one window to another, ala glXMakeCurrentRead. |
||
605 | */ |
||
606 | static void |
||
607 | xmesa_CopyPixels( struct gl_context *ctx, |
||
608 | GLint srcx, GLint srcy, GLsizei width, GLsizei height, |
||
609 | GLint destx, GLint desty, GLenum type ) |
||
610 | { |
||
611 | if (can_do_CopyPixels(ctx, type)) { |
||
612 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
613 | XMesaDisplay *dpy = xmesa->xm_visual->display; |
||
614 | XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
615 | const XMesaGC gc = xmbuf->cleargc; /* effected by glColorMask */ |
||
616 | struct xmesa_renderbuffer *srcXrb |
||
617 | = xmesa_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); |
||
618 | struct xmesa_renderbuffer *dstXrb |
||
619 | = xmesa_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); |
||
620 | |||
621 | ASSERT(dpy); |
||
622 | ASSERT(gc); |
||
623 | |||
624 | /* Note: we don't do any special clipping work here. We could, |
||
625 | * but X will do it for us. |
||
626 | */ |
||
627 | srcy = YFLIP(srcXrb, srcy) - height + 1; |
||
628 | desty = YFLIP(dstXrb, desty) - height + 1; |
||
629 | XCopyArea(dpy, srcXrb->pixmap, dstXrb->pixmap, gc, |
||
630 | srcx, srcy, width, height, destx, desty); |
||
631 | } |
||
632 | else { |
||
633 | _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type ); |
||
634 | } |
||
635 | } |
||
636 | |||
637 | |||
638 | |||
639 | |||
640 | /* |
||
641 | * Every driver should implement a GetString function in order to |
||
642 | * return a meaningful GL_RENDERER string. |
||
643 | */ |
||
644 | static const GLubyte * |
||
645 | get_string( struct gl_context *ctx, GLenum name ) |
||
646 | { |
||
647 | (void) ctx; |
||
648 | switch (name) { |
||
649 | case GL_RENDERER: |
||
650 | return (const GLubyte *) "Mesa X11"; |
||
651 | case GL_VENDOR: |
||
652 | return NULL; |
||
653 | default: |
||
654 | return NULL; |
||
655 | } |
||
656 | } |
||
657 | |||
658 | |||
659 | /* |
||
660 | * We implement the glEnable function only because we care about |
||
661 | * dither enable/disable. |
||
662 | */ |
||
663 | static void |
||
664 | enable( struct gl_context *ctx, GLenum pname, GLboolean state ) |
||
665 | { |
||
666 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
667 | |||
668 | switch (pname) { |
||
669 | case GL_DITHER: |
||
670 | if (state) |
||
671 | xmesa->pixelformat = xmesa->xm_visual->dithered_pf; |
||
672 | else |
||
673 | xmesa->pixelformat = xmesa->xm_visual->undithered_pf; |
||
674 | break; |
||
675 | default: |
||
676 | ; /* silence compiler warning */ |
||
677 | } |
||
678 | } |
||
679 | |||
680 | |||
681 | /** |
||
682 | * Called when the driver should update its state, based on the new_state |
||
683 | * flags. |
||
684 | */ |
||
685 | void |
||
686 | xmesa_update_state( struct gl_context *ctx, GLbitfield new_state ) |
||
687 | { |
||
688 | const XMesaContext xmesa = XMESA_CONTEXT(ctx); |
||
689 | |||
690 | /* Propagate statechange information to swrast and swrast_setup |
||
691 | * modules. The X11 driver has no internal GL-dependent state. |
||
692 | */ |
||
693 | _swrast_InvalidateState( ctx, new_state ); |
||
694 | _tnl_InvalidateState( ctx, new_state ); |
||
695 | _vbo_InvalidateState( ctx, new_state ); |
||
696 | _swsetup_InvalidateState( ctx, new_state ); |
||
697 | |||
698 | if (_mesa_is_user_fbo(ctx->DrawBuffer)) |
||
699 | return; |
||
700 | |||
701 | /* |
||
702 | * GL_DITHER, GL_READ/DRAW_BUFFER, buffer binding state, etc. effect |
||
703 | * renderbuffer span/clear funcs. |
||
704 | * Check _NEW_COLOR to detect dither enable/disable. |
||
705 | */ |
||
706 | if (new_state & (_NEW_COLOR | _NEW_BUFFERS)) { |
||
707 | XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); |
||
708 | struct xmesa_renderbuffer *front_xrb, *back_xrb; |
||
709 | |||
710 | front_xrb = xmbuf->frontxrb; |
||
711 | if (front_xrb) { |
||
712 | front_xrb->clearFunc = clear_pixmap; |
||
713 | } |
||
714 | |||
715 | back_xrb = xmbuf->backxrb; |
||
716 | if (back_xrb) { |
||
717 | if (xmbuf->backxrb->pixmap) { |
||
718 | back_xrb->clearFunc = clear_pixmap; |
||
719 | } |
||
720 | else { |
||
721 | switch (xmesa->xm_visual->BitsPerPixel) { |
||
722 | case 16: |
||
723 | back_xrb->clearFunc = clear_16bit_ximage; |
||
724 | break; |
||
725 | case 24: |
||
726 | back_xrb->clearFunc = clear_24bit_ximage; |
||
727 | break; |
||
728 | case 32: |
||
729 | back_xrb->clearFunc = clear_32bit_ximage; |
||
730 | break; |
||
731 | default: |
||
732 | back_xrb->clearFunc = clear_nbit_ximage; |
||
733 | break; |
||
734 | } |
||
735 | } |
||
736 | } |
||
737 | } |
||
738 | } |
||
739 | |||
740 | |||
741 | /** |
||
742 | * Called by glViewport. |
||
743 | * This is a good time for us to poll the current X window size and adjust |
||
744 | * our renderbuffers to match the current window size. |
||
745 | * Remember, we have no opportunity to respond to conventional |
||
746 | * X Resize/StructureNotify events since the X driver has no event loop. |
||
747 | * Thus, we poll. |
||
748 | * Note that this trick isn't fool-proof. If the application never calls |
||
749 | * glViewport, our notion of the current window size may be incorrect. |
||
750 | * That problem led to the GLX_MESA_resize_buffers extension. |
||
751 | */ |
||
752 | static void |
||
753 | xmesa_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h) |
||
754 | { |
||
755 | XMesaContext xmctx = XMESA_CONTEXT(ctx); |
||
756 | XMesaBuffer xmdrawbuf = XMESA_BUFFER(ctx->WinSysDrawBuffer); |
||
757 | XMesaBuffer xmreadbuf = XMESA_BUFFER(ctx->WinSysReadBuffer); |
||
758 | xmesa_check_and_update_buffer_size(xmctx, xmdrawbuf); |
||
759 | xmesa_check_and_update_buffer_size(xmctx, xmreadbuf); |
||
760 | (void) x; |
||
761 | (void) y; |
||
762 | (void) w; |
||
763 | (void) h; |
||
764 | } |
||
765 | |||
766 | |||
767 | #if ENABLE_EXT_timer_query |
||
768 | |||
769 | /* |
||
770 | * The GL_EXT_timer_query extension is not enabled for the XServer |
||
771 | * indirect renderer. Not sure about how/if wrapping of gettimeofday() |
||
772 | * is done, etc. |
||
773 | */ |
||
774 | |||
775 | struct xmesa_query_object |
||
776 | { |
||
777 | struct gl_query_object Base; |
||
778 | struct timeval StartTime; |
||
779 | }; |
||
780 | |||
781 | |||
782 | static struct gl_query_object * |
||
783 | xmesa_new_query_object(struct gl_context *ctx, GLuint id) |
||
784 | { |
||
785 | struct xmesa_query_object *q = CALLOC_STRUCT(xmesa_query_object); |
||
786 | if (q) { |
||
787 | q->Base.Id = id; |
||
788 | q->Base.Ready = GL_TRUE; |
||
789 | } |
||
790 | return &q->Base; |
||
791 | } |
||
792 | |||
793 | |||
794 | static void |
||
795 | xmesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) |
||
796 | { |
||
797 | if (q->Target == GL_TIME_ELAPSED_EXT) { |
||
798 | struct xmesa_query_object *xq = (struct xmesa_query_object *) q; |
||
799 | (void) gettimeofday(&xq->StartTime, NULL); |
||
800 | } |
||
801 | } |
||
802 | |||
803 | |||
804 | /** |
||
805 | * Return the difference between the two given times in microseconds. |
||
806 | */ |
||
807 | static GLuint64EXT |
||
808 | time_diff(const struct timeval *t0, const struct timeval *t1) |
||
809 | { |
||
810 | GLuint64EXT seconds0 = t0->tv_sec & 0xff; /* 0 .. 255 seconds */ |
||
811 | GLuint64EXT seconds1 = t1->tv_sec & 0xff; /* 0 .. 255 seconds */ |
||
812 | GLuint64EXT nanosec0 = (seconds0 * 1000000 + t0->tv_usec) * 1000; |
||
813 | GLuint64EXT nanosec1 = (seconds1 * 1000000 + t1->tv_usec) * 1000; |
||
814 | return nanosec1 - nanosec0; |
||
815 | } |
||
816 | |||
817 | |||
818 | static void |
||
819 | xmesa_end_query(struct gl_context *ctx, struct gl_query_object *q) |
||
820 | { |
||
821 | if (q->Target == GL_TIME_ELAPSED_EXT) { |
||
822 | struct xmesa_query_object *xq = (struct xmesa_query_object *) q; |
||
823 | struct timeval endTime; |
||
824 | (void) gettimeofday(&endTime, NULL); |
||
825 | /* result is in nanoseconds! */ |
||
826 | q->Result = time_diff(&xq->StartTime, &endTime); |
||
827 | } |
||
828 | q->Ready = GL_TRUE; |
||
829 | } |
||
830 | |||
831 | #endif /* ENABLE_timer_query */ |
||
832 | |||
833 | |||
834 | /** |
||
835 | * Initialize the device driver function table with the functions |
||
836 | * we implement in this driver. |
||
837 | */ |
||
838 | void |
||
839 | xmesa_init_driver_functions( XMesaVisual xmvisual, |
||
840 | struct dd_function_table *driver ) |
||
841 | { |
||
842 | driver->GetString = get_string; |
||
843 | driver->UpdateState = xmesa_update_state; |
||
844 | driver->Flush = finish_or_flush; |
||
845 | driver->Finish = finish_or_flush; |
||
846 | driver->ColorMask = color_mask; |
||
847 | driver->Enable = enable; |
||
848 | driver->Viewport = xmesa_viewport; |
||
849 | if (TEST_META_FUNCS) { |
||
850 | driver->Clear = _mesa_meta_Clear; |
||
851 | driver->CopyPixels = _mesa_meta_CopyPixels; |
||
852 | driver->BlitFramebuffer = _mesa_meta_BlitFramebuffer; |
||
853 | driver->DrawPixels = _mesa_meta_DrawPixels; |
||
854 | driver->Bitmap = _mesa_meta_Bitmap; |
||
855 | } |
||
856 | else { |
||
857 | driver->Clear = clear_buffers; |
||
858 | driver->CopyPixels = xmesa_CopyPixels; |
||
859 | if (xmvisual->undithered_pf == PF_8R8G8B && |
||
860 | xmvisual->dithered_pf == PF_8R8G8B && |
||
861 | xmvisual->BitsPerPixel == 32) { |
||
862 | driver->DrawPixels = xmesa_DrawPixels_8R8G8B; |
||
863 | } |
||
864 | else if (xmvisual->undithered_pf == PF_5R6G5B) { |
||
865 | driver->DrawPixels = xmesa_DrawPixels_5R6G5B; |
||
866 | } |
||
867 | } |
||
868 | |||
869 | driver->MapRenderbuffer = xmesa_MapRenderbuffer; |
||
870 | driver->UnmapRenderbuffer = xmesa_UnmapRenderbuffer; |
||
871 | |||
872 | driver->GenerateMipmap = _mesa_generate_mipmap; |
||
873 | |||
874 | #if ENABLE_EXT_timer_query |
||
875 | driver->NewQueryObject = xmesa_new_query_object; |
||
876 | driver->BeginQuery = xmesa_begin_query; |
||
877 | driver->EndQuery = xmesa_end_query; |
||
878 | #endif |
||
879 | } |
||
880 | |||
881 | |||
882 | #define XMESA_NEW_POINT (_NEW_POINT | \ |
||
883 | _NEW_RENDERMODE | \ |
||
884 | _SWRAST_NEW_RASTERMASK) |
||
885 | |||
886 | #define XMESA_NEW_LINE (_NEW_LINE | \ |
||
887 | _NEW_TEXTURE | \ |
||
888 | _NEW_LIGHT | \ |
||
889 | _NEW_DEPTH | \ |
||
890 | _NEW_RENDERMODE | \ |
||
891 | _SWRAST_NEW_RASTERMASK) |
||
892 | |||
893 | #define XMESA_NEW_TRIANGLE (_NEW_POLYGON | \ |
||
894 | _NEW_TEXTURE | \ |
||
895 | _NEW_LIGHT | \ |
||
896 | _NEW_DEPTH | \ |
||
897 | _NEW_RENDERMODE | \ |
||
898 | _SWRAST_NEW_RASTERMASK) |
||
899 | |||
900 | |||
901 | /** |
||
902 | * Extend the software rasterizer with our line/point/triangle |
||
903 | * functions. |
||
904 | * Called during context creation only. |
||
905 | */ |
||
906 | void xmesa_register_swrast_functions( struct gl_context *ctx ) |
||
907 | { |
||
908 | SWcontext *swrast = SWRAST_CONTEXT( ctx ); |
||
909 | |||
910 | swrast->choose_point = xmesa_choose_point; |
||
911 | swrast->choose_line = xmesa_choose_line; |
||
912 | swrast->choose_triangle = xmesa_choose_triangle; |
||
913 | |||
914 | /* XXX these lines have no net effect. Remove??? */ |
||
915 | swrast->InvalidatePointMask |= XMESA_NEW_POINT; |
||
916 | swrast->InvalidateLineMask |= XMESA_NEW_LINE; |
||
917 | swrast->InvalidateTriangleMask |= XMESA_NEW_TRIANGLE; |
||
918 | }>>>>>><>><>>>>>>><> |