intel_buffers.c revision df70d3049a396af3601d2a1747770635a74120bb
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 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 "intel_context.h" 29#include "intel_buffers.h" 30#include "intel_fbo.h" 31#include "intel_regions.h" 32#include "intel_batchbuffer.h" 33#include "main/framebuffer.h" 34#include "drirenderbuffer.h" 35 36 37/** 38 * XXX move this into a new dri/common/cliprects.c file. 39 */ 40GLboolean 41intel_intersect_cliprects(drm_clip_rect_t * dst, 42 const drm_clip_rect_t * a, 43 const drm_clip_rect_t * b) 44{ 45 GLint bx = b->x1; 46 GLint by = b->y1; 47 GLint bw = b->x2 - bx; 48 GLint bh = b->y2 - by; 49 50 if (bx < a->x1) 51 bw -= a->x1 - bx, bx = a->x1; 52 if (by < a->y1) 53 bh -= a->y1 - by, by = a->y1; 54 if (bx + bw > a->x2) 55 bw = a->x2 - bx; 56 if (by + bh > a->y2) 57 bh = a->y2 - by; 58 if (bw <= 0) 59 return GL_FALSE; 60 if (bh <= 0) 61 return GL_FALSE; 62 63 dst->x1 = bx; 64 dst->y1 = by; 65 dst->x2 = bx + bw; 66 dst->y2 = by + bh; 67 68 return GL_TRUE; 69} 70 71/** 72 * Return pointer to current color drawing region, or NULL. 73 */ 74struct intel_region * 75intel_drawbuf_region(struct intel_context *intel) 76{ 77 struct intel_renderbuffer *irbColor = 78 intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0]); 79 if (irbColor) 80 return irbColor->region; 81 else 82 return NULL; 83} 84 85/** 86 * Return pointer to current color reading region, or NULL. 87 */ 88struct intel_region * 89intel_readbuf_region(struct intel_context *intel) 90{ 91 struct intel_renderbuffer *irb 92 = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer); 93 if (irb) 94 return irb->region; 95 else 96 return NULL; 97} 98 99void 100intel_get_cliprects(struct intel_context *intel, 101 struct drm_clip_rect **cliprects, 102 unsigned int *num_cliprects, 103 int *x_off, int *y_off) 104{ 105 __DRIdrawablePrivate *dPriv = intel->driDrawable; 106 107 if (intel->constant_cliprect) { 108 /* FBO or DRI2 rendering, which can just use the fb's size. */ 109 intel->fboRect.x1 = 0; 110 intel->fboRect.y1 = 0; 111 intel->fboRect.x2 = intel->ctx.DrawBuffer->Width; 112 intel->fboRect.y2 = intel->ctx.DrawBuffer->Height; 113 114 *cliprects = &intel->fboRect; 115 *num_cliprects = 1; 116 *x_off = 0; 117 *y_off = 0; 118 } else if (intel->front_cliprects || dPriv->numBackClipRects == 0) { 119 /* use the front clip rects */ 120 *cliprects = dPriv->pClipRects; 121 *num_cliprects = dPriv->numClipRects; 122 *x_off = dPriv->x; 123 *y_off = dPriv->y; 124 } 125 else { 126 /* use the back clip rects */ 127 *num_cliprects = dPriv->numBackClipRects; 128 *cliprects = dPriv->pBackClipRects; 129 *x_off = dPriv->backX; 130 *y_off = dPriv->backY; 131 } 132} 133 134 135/** 136 * Update the hardware state for drawing into a window or framebuffer object. 137 * 138 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other 139 * places within the driver. 140 * 141 * Basically, this needs to be called any time the current framebuffer 142 * changes, the renderbuffers change, or we need to draw into different 143 * color buffers. 144 */ 145void 146intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb) 147{ 148 struct intel_context *intel = intel_context(ctx); 149 struct intel_region *colorRegions[MAX_DRAW_BUFFERS], *depthRegion = NULL; 150 struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; 151 152 if (!fb) { 153 /* this can happen during the initial context initialization */ 154 return; 155 } 156 157 /* Do this here, not core Mesa, since this function is called from 158 * many places within the driver. 159 */ 160 if (ctx->NewState & _NEW_BUFFERS) { 161 /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ 162 _mesa_update_framebuffer(ctx); 163 /* this updates the DrawBuffer's Width/Height if it's a FBO */ 164 _mesa_update_draw_buffer_bounds(ctx); 165 } 166 167 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 168 /* this may occur when we're called by glBindFrameBuffer() during 169 * the process of someone setting up renderbuffers, etc. 170 */ 171 /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/ 172 return; 173 } 174 175 /* 176 * How many color buffers are we drawing into? 177 */ 178 if (fb->_NumColorDrawBuffers == 0) { 179 /* writing to 0 */ 180 colorRegions[0] = NULL; 181 intel->constant_cliprect = GL_TRUE; 182 } 183 else if (fb->_NumColorDrawBuffers > 1) { 184 int i; 185 struct intel_renderbuffer *irb; 186 187 for (i = 0; i < fb->_NumColorDrawBuffers; i++) { 188 irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]); 189 colorRegions[i] = irb ? irb->region : NULL; 190 } 191 intel->constant_cliprect = GL_TRUE; 192 } 193 else { 194 /* Get the intel_renderbuffer for the single colorbuffer we're drawing 195 * into, and set up cliprects if it's . 196 */ 197 if (fb->Name == 0) { 198 intel->constant_cliprect = intel->driScreen->dri2.enabled; 199 /* drawing to window system buffer */ 200 if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { 201 if (!intel->constant_cliprect && !intel->front_cliprects) 202 intel_batchbuffer_flush(intel->batch); 203 intel->front_cliprects = GL_TRUE; 204 colorRegions[0] = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); 205 206 intel->front_buffer_dirty = GL_TRUE; 207 } 208 else { 209 if (!intel->constant_cliprect && intel->front_cliprects) 210 intel_batchbuffer_flush(intel->batch); 211 intel->front_cliprects = GL_FALSE; 212 colorRegions[0]= intel_get_rb_region(fb, BUFFER_BACK_LEFT); 213 } 214 } 215 else { 216 /* drawing to user-created FBO */ 217 struct intel_renderbuffer *irb; 218 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); 219 colorRegions[0] = (irb && irb->region) ? irb->region : NULL; 220 intel->constant_cliprect = GL_TRUE; 221 } 222 } 223 224 if (!colorRegions[0]) { 225 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); 226 } 227 else { 228 FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); 229 } 230 231 /*** 232 *** Get depth buffer region and check if we need a software fallback. 233 *** Note that the depth buffer is usually a DEPTH_STENCIL buffer. 234 ***/ 235 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { 236 irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); 237 if (irbDepth && irbDepth->region) { 238 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 239 depthRegion = irbDepth->region; 240 } 241 else { 242 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE); 243 depthRegion = NULL; 244 } 245 } 246 else { 247 /* not using depth buffer */ 248 FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); 249 depthRegion = NULL; 250 } 251 252 /*** 253 *** Stencil buffer 254 *** This can only be hardware accelerated if we're using a 255 *** combined DEPTH_STENCIL buffer. 256 ***/ 257 if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { 258 irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); 259 if (irbStencil && irbStencil->region) { 260 ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); 261 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 262 } 263 else { 264 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE); 265 } 266 } 267 else { 268 /* XXX FBO: instead of FALSE, pass ctx->Stencil._Enabled ??? */ 269 FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); 270 } 271 272 /* 273 * Update depth and stencil test state 274 */ 275 if (ctx->Driver.Enable) { 276 ctx->Driver.Enable(ctx, GL_DEPTH_TEST, 277 (ctx->Depth.Test && fb->Visual.depthBits > 0)); 278 ctx->Driver.Enable(ctx, GL_STENCIL_TEST, 279 (ctx->Stencil.Enabled && fb->Visual.stencilBits > 0)); 280 } 281 else { 282 /* Mesa's Stencil._Enabled field is updated when 283 * _NEW_BUFFERS | _NEW_STENCIL, but i965 code assumes that the value 284 * only changes with _NEW_STENCIL (which seems sensible). So flag it 285 * here since this is the _NEW_BUFFERS path. 286 */ 287 ctx->NewState |= (_NEW_DEPTH | _NEW_STENCIL); 288 } 289 290 intel->vtbl.set_draw_region(intel, colorRegions, depthRegion, 291 fb->_NumColorDrawBuffers); 292 293 /* update viewport since it depends on window size */ 294#ifdef I915 295 intelCalcViewport(ctx); 296#else 297 ctx->NewState |= _NEW_VIEWPORT; 298#endif 299 /* Set state we know depends on drawable parameters: 300 */ 301 if (ctx->Driver.Scissor) 302 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, 303 ctx->Scissor.Width, ctx->Scissor.Height); 304 intel->NewGLState |= _NEW_SCISSOR; 305 306 if (ctx->Driver.DepthRange) 307 ctx->Driver.DepthRange(ctx, 308 ctx->Viewport.Near, 309 ctx->Viewport.Far); 310 311 /* Update culling direction which changes depending on the 312 * orientation of the buffer: 313 */ 314 if (ctx->Driver.FrontFace) 315 ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace); 316 else 317 ctx->NewState |= _NEW_POLYGON; 318} 319 320 321static void 322intelDrawBuffer(GLcontext * ctx, GLenum mode) 323{ 324 if ((ctx->DrawBuffer != NULL) && (ctx->DrawBuffer->Name == 0)) { 325 struct intel_context *const intel = intel_context(ctx); 326 const GLboolean was_front_buffer_rendering = 327 intel->is_front_buffer_rendering; 328 329 intel->is_front_buffer_rendering = (mode == GL_FRONT_LEFT) 330 || (mode == GL_FRONT); 331 332 /* If we weren't front-buffer rendering before but we are now, make sure 333 * that the front-buffer has actually been allocated. 334 */ 335 if (!was_front_buffer_rendering && intel->is_front_buffer_rendering) { 336 intel_update_renderbuffers(intel->driContext, 337 intel->driContext->driDrawablePriv); 338 } 339 } 340 341 intel_draw_buffer(ctx, ctx->DrawBuffer); 342} 343 344 345static void 346intelReadBuffer(GLcontext * ctx, GLenum mode) 347{ 348 if ((ctx->DrawBuffer != NULL) && (ctx->DrawBuffer->Name == 0)) { 349 struct intel_context *const intel = intel_context(ctx); 350 const GLboolean was_front_buffer_reading = 351 intel->is_front_buffer_reading; 352 353 intel->is_front_buffer_reading = (mode == GL_FRONT_LEFT) 354 || (mode == GL_FRONT); 355 356 /* If we weren't front-buffer reading before but we are now, make sure 357 * that the front-buffer has actually been allocated. 358 */ 359 if (!was_front_buffer_reading && intel->is_front_buffer_reading) { 360 intel_update_renderbuffers(intel->driContext, 361 intel->driContext->driDrawablePriv); 362 } 363 } 364 365 if (ctx->ReadBuffer == ctx->DrawBuffer) { 366 /* This will update FBO completeness status. 367 * A framebuffer will be incomplete if the GL_READ_BUFFER setting 368 * refers to a missing renderbuffer. Calling glReadBuffer can set 369 * that straight and can make the drawing buffer complete. 370 */ 371 intel_draw_buffer(ctx, ctx->DrawBuffer); 372 } 373 /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc) 374 * reference ctx->ReadBuffer and do appropriate state checks. 375 */ 376} 377 378 379void 380intelInitBufferFuncs(struct dd_function_table *functions) 381{ 382 functions->DrawBuffer = intelDrawBuffer; 383 functions->ReadBuffer = intelReadBuffer; 384} 385