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