1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include "intel_screen.h"
29 #include "intel_context.h"
30 #include "intel_blit.h"
31 #include "intel_buffers.h"
32 #include "intel_depthstencil.h"
33 #include "intel_fbo.h"
34 #include "intel_batchbuffer.h"
35 #include "intel_reg.h"
38 #include "drirenderbuffer.h"
39 #include "framebuffer.h"
42 #include "pipe/p_context.h"
44 /* This block can be removed when libdrm >= 2.3.1 is required */
46 #ifndef DRM_VBLANK_FLIP
48 #define DRM_VBLANK_FLIP 0x8000000
50 typedef struct drm_i915_flip
{
54 #undef DRM_IOCTL_I915_FLIP
55 #define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \
62 * XXX move this into a new dri/common/cliprects.c file.
65 intel_intersect_cliprects(drm_clip_rect_t
* dst
,
66 const drm_clip_rect_t
* a
,
67 const drm_clip_rect_t
* b
)
71 GLint bw
= b
->x2
- bx
;
72 GLint bh
= b
->y2
- by
;
75 bw
-= a
->x1
- bx
, bx
= a
->x1
;
77 bh
-= a
->y1
- by
, by
= a
->y1
;
96 * Return pointer to current color drawing region, or NULL.
99 intel_drawbuf_region(struct intel_context
*intel
)
101 struct intel_renderbuffer
*irbColor
=
102 intel_renderbuffer(intel
->ctx
.DrawBuffer
->_ColorDrawBuffers
[0][0]);
104 return irbColor
->region
;
110 * Return pointer to current color reading region, or NULL.
113 intel_readbuf_region(struct intel_context
*intel
)
115 struct intel_renderbuffer
*irb
116 = intel_renderbuffer(intel
->ctx
.ReadBuffer
->_ColorReadBuffer
);
126 * Update the following fields for rendering:
127 * intel->numClipRects
131 intelSetRenderbufferClipRects(struct intel_context
*intel
)
133 /* zero-sized buffers might be legal? */
134 assert(intel
->ctx
.DrawBuffer
->Width
> 0);
135 assert(intel
->ctx
.DrawBuffer
->Height
> 0);
136 intel
->fboRect
.x1
= 0;
137 intel
->fboRect
.y1
= 0;
138 intel
->fboRect
.x2
= intel
->ctx
.DrawBuffer
->Width
;
139 intel
->fboRect
.y2
= intel
->ctx
.DrawBuffer
->Height
;
140 intel
->numClipRects
= 1;
141 intel
->pClipRects
= &intel
->fboRect
;
146 * This will be called whenever the currently bound window is moved/resized.
147 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
150 intelWindowMoved(struct intel_context
*intel
)
152 GLcontext
*ctx
= &intel
->ctx
;
153 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
154 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
156 if (!intel
->ctx
.DrawBuffer
) {
157 /* when would this happen? -BP */
159 intel
->numClipRects
= 0;
162 /* Update Mesa's notion of window size */
163 driUpdateFramebufferSize(ctx
, dPriv
);
164 intel_fb
->Base
.Initialized
= GL_TRUE
; /* XXX remove someday */
167 drmI830Sarea
*sarea
= intel
->sarea
;
168 drm_clip_rect_t drw_rect
= { .x1
= dPriv
->x
, .x2
= dPriv
->x
+ dPriv
->w
,
169 .y1
= dPriv
->y
, .y2
= dPriv
->y
+ dPriv
->h
};
170 drm_clip_rect_t pipeA_rect
= { .x1
= sarea
->pipeA_x
, .y1
= sarea
->pipeA_y
,
171 .x2
= sarea
->pipeA_x
+ sarea
->pipeA_w
,
172 .y2
= sarea
->pipeA_y
+ sarea
->pipeA_h
};
173 drm_clip_rect_t pipeB_rect
= { .x1
= sarea
->pipeB_x
, .y1
= sarea
->pipeB_y
,
174 .x2
= sarea
->pipeB_x
+ sarea
->pipeB_w
,
175 .y2
= sarea
->pipeB_y
+ sarea
->pipeB_h
};
176 GLint areaA
= driIntersectArea( drw_rect
, pipeA_rect
);
177 GLint areaB
= driIntersectArea( drw_rect
, pipeB_rect
);
178 GLuint flags
= intel_fb
->vblank_flags
;
182 /* Update page flipping info
192 intel_fb
->pf_current_page
= (intel
->sarea
->pf_current_page
>>
193 (intel_fb
->pf_pipes
& 0x2)) & 0x3;
195 intel_fb
->pf_num_pages
= 2 /*intel->intelScreen->third.handle ? 3 : 2*/;
197 pf_active
= pf_pipes
&& (pf_pipes
& intel
->sarea
->pf_active
) == pf_pipes
;
199 if (INTEL_DEBUG
& DEBUG_LOCK
)
200 if (pf_active
!= intel_fb
->pf_active
)
201 _mesa_printf("%s - Page flipping %sactive\n", __progname
,
202 pf_active
? "" : "in");
205 /* Sync pages between pipes if we're flipping on both at the same time */
206 if (pf_pipes
== 0x3 && pf_pipes
!= intel_fb
->pf_pipes
&&
207 (intel
->sarea
->pf_current_page
& 0x3) !=
208 (((intel
->sarea
->pf_current_page
) >> 2) & 0x3)) {
209 drm_i915_flip_t flip
;
211 if (intel_fb
->pf_current_page
==
212 (intel
->sarea
->pf_current_page
& 0x3)) {
213 /* XXX: This is ugly, but emitting two flips 'in a row' can cause
214 * lockups for unknown reasons.
216 intel
->sarea
->pf_current_page
=
217 intel
->sarea
->pf_current_page
& 0x3;
218 intel
->sarea
->pf_current_page
|=
219 ((intel_fb
->pf_current_page
+ intel_fb
->pf_num_pages
- 1) %
220 intel_fb
->pf_num_pages
) << 2;
224 intel
->sarea
->pf_current_page
=
225 intel
->sarea
->pf_current_page
& (0x3 << 2);
226 intel
->sarea
->pf_current_page
|=
227 (intel_fb
->pf_current_page
+ intel_fb
->pf_num_pages
- 1) %
228 intel_fb
->pf_num_pages
;
233 drmCommandWrite(intel
->driFd
, DRM_I915_FLIP
, &flip
, sizeof(flip
));
236 intel_fb
->pf_pipes
= pf_pipes
;
239 intel_fb
->pf_active
= pf_active
;
240 intel_flip_renderbuffers(intel_fb
);
241 intel_draw_buffer(&intel
->ctx
, intel
->ctx
.DrawBuffer
);
243 /* Update vblank info
245 if (areaB
> areaA
|| (areaA
== areaB
&& areaB
> 0)) {
246 flags
= intel_fb
->vblank_flags
| VBLANK_FLAG_SECONDARY
;
248 flags
= intel_fb
->vblank_flags
& ~VBLANK_FLAG_SECONDARY
;
251 if (flags
!= intel_fb
->vblank_flags
&& intel_fb
->vblank_flags
&&
252 !(intel_fb
->vblank_flags
& VBLANK_FLAG_NO_IRQ
)) {
256 vbl
.request
.type
= DRM_VBLANK_ABSOLUTE
;
258 if ( intel_fb
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
259 vbl
.request
.type
|= DRM_VBLANK_SECONDARY
;
262 for (i
= 0; i
< intel_fb
->pf_num_pages
; i
++) {
263 if (!intel_fb
->color_rb
[i
] ||
264 (intel_fb
->vbl_waited
- intel_fb
->color_rb
[i
]->vbl_pending
) <=
268 vbl
.request
.sequence
= intel_fb
->color_rb
[i
]->vbl_pending
;
269 drmWaitVBlank(intel
->driFd
, &vbl
);
272 intel_fb
->vblank_flags
= flags
;
273 driGetCurrentVBlank(dPriv
, intel_fb
->vblank_flags
, &intel_fb
->vbl_seq
);
274 intel_fb
->vbl_waited
= intel_fb
->vbl_seq
;
276 for (i
= 0; i
< intel_fb
->pf_num_pages
; i
++) {
277 if (intel_fb
->color_rb
[i
])
278 intel_fb
->color_rb
[i
]->vbl_pending
= intel_fb
->vbl_waited
;
283 /* This will be picked up by looking at the dirty state flags:
286 /* Update hardware scissor */
287 // ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
288 // ctx->Scissor.Width, ctx->Scissor.Height);
290 /* Re-calculate viewport related state */
291 // ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
298 /* Emit wait for pending flips */
300 intel_wait_flips(struct intel_context
*intel
, GLuint batch_flags
)
302 struct intel_framebuffer
*intel_fb
=
303 (struct intel_framebuffer
*) intel
->ctx
.DrawBuffer
;
304 struct intel_renderbuffer
*intel_rb
=
305 intel_get_renderbuffer(&intel_fb
->Base
,
306 intel_fb
->Base
._ColorDrawBufferMask
[0] ==
307 BUFFER_BIT_FRONT_LEFT
? BUFFER_FRONT_LEFT
:
310 if (intel_fb
->Base
.Name
== 0 && intel_rb
->pf_pending
== intel_fb
->pf_seq
) {
311 GLint pf_pipes
= intel_fb
->pf_pipes
;
314 /* Wait for pending flips to take effect */
315 BEGIN_BATCH(2, batch_flags
);
316 OUT_BATCH(pf_pipes
& 0x1 ? (MI_WAIT_FOR_EVENT
| MI_WAIT_FOR_PLANE_A_FLIP
)
318 OUT_BATCH(pf_pipes
& 0x2 ? (MI_WAIT_FOR_EVENT
| MI_WAIT_FOR_PLANE_B_FLIP
)
322 intel_rb
->pf_pending
--;
327 /* Flip the front & back buffers
330 intelPageFlip(const __DRIdrawablePrivate
* dPriv
)
332 struct intel_context
*intel
;
334 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
336 if (INTEL_DEBUG
& DEBUG_IOCTL
)
337 fprintf(stderr
, "%s\n", __FUNCTION__
);
340 assert(dPriv
->driContextPriv
);
341 assert(dPriv
->driContextPriv
->driverPrivate
);
343 intel
= (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
345 if (intel
->intelScreen
->drmMinor
< 9)
348 intelFlush(&intel
->ctx
);
352 LOCK_HARDWARE(intel
);
354 if (dPriv
->numClipRects
&& intel_fb
->pf_active
) {
355 drm_i915_flip_t flip
;
357 flip
.pipes
= intel_fb
->pf_pipes
;
359 ret
= drmCommandWrite(intel
->driFd
, DRM_I915_FLIP
, &flip
, sizeof(flip
));
362 UNLOCK_HARDWARE(intel
);
364 if (ret
|| !intel_fb
->pf_active
)
367 if (!dPriv
->numClipRects
) {
368 usleep(10000); /* throttle invisible client 10ms */
371 intel_fb
->pf_current_page
= (intel
->sarea
->pf_current_page
>>
372 (intel_fb
->pf_pipes
& 0x2)) & 0x3;
374 if (dPriv
->numClipRects
!= 0) {
375 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_FRONT_LEFT
)->pf_pending
=
376 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_BACK_LEFT
)->pf_pending
=
380 intel_flip_renderbuffers(intel_fb
);
381 intel_draw_buffer(&intel
->ctx
, &intel_fb
->Base
);
383 if (INTEL_DEBUG
& DEBUG_IOCTL
)
384 fprintf(stderr
, "%s: success\n", __FUNCTION__
);
392 intelScheduleSwap(const __DRIdrawablePrivate
* dPriv
, GLboolean
*missed_target
)
394 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
395 unsigned int interval
= driGetVBlankInterval(dPriv
, intel_fb
->vblank_flags
);
396 struct intel_context
*intel
=
397 intelScreenContext(dPriv
->driScreenPriv
->private);
398 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
400 drm_i915_vblank_swap_t swap
;
403 if (!intel_fb
->vblank_flags
||
404 (intel_fb
->vblank_flags
& VBLANK_FLAG_NO_IRQ
) ||
405 intelScreen
->drmMinor
< (intel_fb
->pf_active
? 9 : 6))
408 swap
.seqtype
= DRM_VBLANK_ABSOLUTE
;
410 if (intel_fb
->vblank_flags
& VBLANK_FLAG_SYNC
) {
411 swap
.seqtype
|= DRM_VBLANK_NEXTONMISS
;
412 } else if (interval
== 0) {
416 swap
.drawable
= dPriv
->hHWDrawable
;
417 target
= swap
.sequence
= intel_fb
->vbl_seq
+ interval
;
419 if ( intel_fb
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
420 swap
.seqtype
|= DRM_VBLANK_SECONDARY
;
423 LOCK_HARDWARE(intel
);
425 intel_batchbuffer_flush(intel
->batch
);
427 if ( intel_fb
->pf_active
) {
428 swap
.seqtype
|= DRM_VBLANK_FLIP
;
430 intel_fb
->pf_current_page
= (((intel
->sarea
->pf_current_page
>>
431 (intel_fb
->pf_pipes
& 0x2)) & 0x3) + 1) %
432 intel_fb
->pf_num_pages
;
435 if (!drmCommandWriteRead(intel
->driFd
, DRM_I915_VBLANK_SWAP
, &swap
,
437 intel_fb
->vbl_seq
= swap
.sequence
;
438 swap
.sequence
-= target
;
439 *missed_target
= swap
.sequence
> 0 && swap
.sequence
<= (1 << 23);
441 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_BACK_LEFT
)->vbl_pending
=
442 intel_get_renderbuffer(&intel_fb
->Base
,
443 BUFFER_FRONT_LEFT
)->vbl_pending
=
446 if (swap
.seqtype
& DRM_VBLANK_FLIP
) {
447 intel_flip_renderbuffers(intel_fb
);
448 intel_draw_buffer(&intel
->ctx
, intel
->ctx
.DrawBuffer
);
453 if (swap
.seqtype
& DRM_VBLANK_FLIP
) {
454 intel_fb
->pf_current_page
= ((intel
->sarea
->pf_current_page
>>
455 (intel_fb
->pf_pipes
& 0x2)) & 0x3) %
456 intel_fb
->pf_num_pages
;
462 UNLOCK_HARDWARE(intel
);
468 intelSwapBuffers(__DRIdrawablePrivate
* dPriv
)
470 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
471 GET_CURRENT_CONTEXT(ctx
);
472 struct intel_context
*intel
;
477 intel
= intel_context(ctx
);
479 if (ctx
->Visual
.doubleBufferMode
) {
480 GLboolean missed_target
;
481 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
484 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
486 if (!intelScheduleSwap(dPriv
, &missed_target
)) {
487 driWaitForVBlank(dPriv
, &intel_fb
->vbl_seq
, intel_fb
->vblank_flags
,
490 intelCopyBuffer(dPriv
, NULL
);
493 intel_fb
->swap_count
++;
494 (*dri_interface
->getUST
) (&ust
);
496 intel_fb
->swap_missed_count
++;
497 intel_fb
->swap_missed_ust
= ust
- intel_fb
->swap_ust
;
500 intel_fb
->swap_ust
= ust
;
504 /* XXX this shouldn't be an error but we can't handle it for now */
505 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
510 intelCopySubBuffer(__DRIdrawablePrivate
* dPriv
, int x
, int y
, int w
, int h
)
512 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
513 struct intel_context
*intel
=
514 (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
515 GLcontext
*ctx
= &intel
->ctx
;
517 if (ctx
->Visual
.doubleBufferMode
) {
518 drm_clip_rect_t rect
;
519 /* fixup cliprect (driDrawable may have changed?) later */
524 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
525 intelCopyBuffer(dPriv
, &rect
);
529 /* XXX this shouldn't be an error but we can't handle it for now */
530 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
536 * Update the hardware state for drawing into a window or framebuffer object.
538 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
539 * places within the driver.
541 * Basically, this needs to be called any time the current framebuffer
542 * changes, the renderbuffers change, or we need to draw into different
546 intel_draw_buffer(GLcontext
* ctx
, struct gl_framebuffer
*fb
)
548 struct intel_context
*intel
= intel_context(ctx
);
549 struct pipe_region
*colorRegion
, *depthRegion
= NULL
;
550 struct intel_renderbuffer
*irbDepth
= NULL
, *irbStencil
= NULL
;
553 /* this can happen during the initial context initialization */
557 /* Do this here, not core Mesa, since this function is called from
558 * many places within the driver.
560 if (ctx
->NewState
& (_NEW_BUFFERS
| _NEW_COLOR
| _NEW_PIXEL
)) {
561 /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
562 _mesa_update_framebuffer(ctx
);
563 /* this updates the DrawBuffer's Width/Height if it's a FBO */
564 _mesa_update_draw_buffer_bounds(ctx
);
567 if (fb
->_Status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
568 /* this may occur when we're called by glBindFrameBuffer() during
569 * the process of someone setting up renderbuffers, etc.
571 /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
576 intel_validate_paired_depth_stencil(ctx
, fb
);
579 * How many color buffers are we drawing into?
581 if (fb
->_NumColorDrawBuffers
[0] != 1) {
582 /* writing to 0 or 2 or 4 color buffers */
583 /*_mesa_debug(ctx, "Software rendering\n");*/
584 FALLBACK(intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_TRUE
);
587 /* draw to exactly one color buffer */
588 /*_mesa_debug(ctx, "Hardware rendering\n");*/
589 FALLBACK(intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_FALSE
);
593 * Get the intel_renderbuffer for the colorbuffer we're drawing into.
594 * And set up cliprects.
597 struct intel_renderbuffer
*irb
;
598 intelSetRenderbufferClipRects(intel
);
599 irb
= intel_renderbuffer(fb
->_ColorDrawBuffers
[0][0]);
600 colorRegion
= (irb
&& irb
->region
) ? irb
->region
: NULL
;
603 /* Update culling direction which changes depending on the
604 * orientation of the buffer:
606 if (ctx
->Driver
.FrontFace
)
607 ctx
->Driver
.FrontFace(ctx
, ctx
->Polygon
.FrontFace
);
609 ctx
->NewState
|= _NEW_POLYGON
;
612 FALLBACK(intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_TRUE
);
615 FALLBACK(intel
, INTEL_FALLBACK_DRAW_BUFFER
, GL_FALSE
);
619 *** Get depth buffer region and check if we need a software fallback.
620 *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
622 if (fb
->_DepthBuffer
&& fb
->_DepthBuffer
->Wrapped
) {
623 irbDepth
= intel_renderbuffer(fb
->_DepthBuffer
->Wrapped
);
624 if (irbDepth
&& irbDepth
->region
) {
625 FALLBACK(intel
, INTEL_FALLBACK_DEPTH_BUFFER
, GL_FALSE
);
626 depthRegion
= irbDepth
->region
;
629 FALLBACK(intel
, INTEL_FALLBACK_DEPTH_BUFFER
, GL_TRUE
);
634 /* not using depth buffer */
635 FALLBACK(intel
, INTEL_FALLBACK_DEPTH_BUFFER
, GL_FALSE
);
641 *** This can only be hardware accelerated if we're using a
642 *** combined DEPTH_STENCIL buffer (for now anyway).
644 if (fb
->_StencilBuffer
&& fb
->_StencilBuffer
->Wrapped
) {
645 irbStencil
= intel_renderbuffer(fb
->_StencilBuffer
->Wrapped
);
646 if (irbStencil
&& irbStencil
->region
) {
647 ASSERT(irbStencil
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
648 FALLBACK(intel
, INTEL_FALLBACK_STENCIL_BUFFER
, GL_FALSE
);
649 /* need to re-compute stencil hw state */
650 // ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
652 depthRegion
= irbStencil
->region
;
655 FALLBACK(intel
, INTEL_FALLBACK_STENCIL_BUFFER
, GL_TRUE
);
659 /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */
660 FALLBACK(intel
, INTEL_FALLBACK_STENCIL_BUFFER
, GL_FALSE
);
661 /* need to re-compute stencil hw state */
662 // ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
667 ** Release old regions, reference new regions
670 // intel->vtbl.set_draw_region(intel, colorRegion, depthRegion);
672 /* update viewport since it depends on window size */
673 // ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
674 // ctx->Viewport.Width, ctx->Viewport.Height);
676 /* Update hardware scissor */
677 // ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
678 // ctx->Scissor.Width, ctx->Scissor.Height);
683 intelDrawBuffer(GLcontext
* ctx
, GLenum mode
)
685 intel_draw_buffer(ctx
, ctx
->DrawBuffer
);
690 intelReadBuffer(GLcontext
* ctx
, GLenum mode
)
692 if (ctx
->ReadBuffer
== ctx
->DrawBuffer
) {
693 /* This will update FBO completeness status.
694 * A framebuffer will be incomplete if the GL_READ_BUFFER setting
695 * refers to a missing renderbuffer. Calling glReadBuffer can set
696 * that straight and can make the drawing buffer complete.
698 intel_draw_buffer(ctx
, ctx
->DrawBuffer
);
700 /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc)
701 * reference ctx->ReadBuffer and do appropriate state checks.
707 intelInitBufferFuncs(struct dd_function_table
*functions
)
709 functions
->DrawBuffer
= intelDrawBuffer
;
710 functions
->ReadBuffer
= intelReadBuffer
;