static void intel_flush_front(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); __DRIcontext *driContext = intel->driContext; __DRIdrawable *driDrawable = driContext->driDrawablePriv; __DRIscreen *const screen = intel->intelScreen->driScrnPriv; if (_mesa_is_winsys_fbo(ctx->DrawBuffer) && intel->front_buffer_dirty) { if (screen->dri2.loader->flushFrontBuffer != NULL && driDrawable && driDrawable->loaderPrivate) { /* Downsample before flushing FAKE_FRONT_LEFT to FRONT_LEFT. * * This potentially downsamples both front and back buffer. It * is unnecessary to downsample the back, but harms nothing except * performance. And no one cares about front-buffer render * performance. */ intel_downsample_for_dri2_flush(intel, driDrawable); screen->dri2.loader->flushFrontBuffer(driDrawable, driDrawable->loaderPrivate); /* We set the dirty bit in intel_prepare_render() if we're * front buffer rendering once we get there. */ intel->front_buffer_dirty = false; } } }
void GLAPIENTRY _mesa_GetMultisamplefv(GLenum pname, GLuint index, GLfloat * val) { GET_CURRENT_CONTEXT(ctx); if (ctx->NewState & _NEW_BUFFERS) { _mesa_update_state(ctx); } switch (pname) { case GL_SAMPLE_POSITION: { if ((int) index >= ctx->DrawBuffer->Visual.samples) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetMultisamplefv(index)" ); return; } ctx->Driver.GetSamplePosition(ctx, ctx->DrawBuffer, index, val); /* winsys FBOs are upside down */ if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) val[1] = 1 - val[1]; return; } default: _mesa_error( ctx, GL_INVALID_ENUM, "glGetMultisamplefv(pname)" ); return; } }
static void intel_flush_front(struct gl_context *ctx) { struct brw_context *brw = brw_context(ctx); __DRIcontext *driContext = brw->driContext; __DRIdrawable *driDrawable = driContext->driDrawablePriv; __DRIscreen *const screen = brw->intelScreen->driScrnPriv; if (brw->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) { if (flushFront(screen) && driDrawable && driDrawable->loaderPrivate) { /* Resolve before flushing FAKE_FRONT_LEFT to FRONT_LEFT. * * This potentially resolves both front and back buffer. It * is unnecessary to resolve the back, but harms nothing except * performance. And no one cares about front-buffer render * performance. */ intel_resolve_for_dri2_flush(brw, driDrawable); intel_batchbuffer_flush(brw); flushFront(screen)(driDrawable, driDrawable->loaderPrivate); /* We set the dirty bit in intel_prepare_render() if we're * front buffer rendering once we get there. */ brw->front_buffer_dirty = false; } } }
/** * Polygon stipple offset packet */ static void upload_polygon_stipple_offset(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* _NEW_POLYGON */ if (!ctx->Polygon.StippleFlag) return; BEGIN_BATCH(2); OUT_BATCH(_3DSTATE_POLY_STIPPLE_OFFSET << 16 | (2-2)); /* _NEW_BUFFERS * * If we're drawing to a system window we have to invert the Y axis * in order to match the OpenGL pixel coordinate system, and our * offset must be matched to the window position. If we're drawing * to a user-created FBO then our native pixel coordinate system * works just fine, and there's no window system to worry about. */ if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) OUT_BATCH((32 - (_mesa_geometric_height(ctx->DrawBuffer) & 31)) & 31); else OUT_BATCH(0); ADVANCE_BATCH(); }
/** * Update a gl_framebuffer's derived state. * * Specifically, update these framebuffer fields: * _ColorDrawBuffers * _NumColorDrawBuffers * _ColorReadBuffer * * If the framebuffer is user-created, make sure it's complete. * * The following functions (at least) can effect framebuffer state: * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, * glRenderbufferStorageEXT. */ static void update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { if (_mesa_is_winsys_fbo(fb)) { /* This is a window-system framebuffer */ /* Need to update the FB's GL_DRAW_BUFFER state to match the * context state (GL_READ_BUFFER too). */ if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { _mesa_drawbuffers(ctx, fb, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); } } else { /* This is a user-created framebuffer. * Completeness only matters for user-created framebuffers. */ if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { _mesa_test_framebuffer_completeness(ctx, fb); } } /* Strictly speaking, we don't need to update the draw-state * if this FB is bound as ctx->ReadBuffer (and conversely, the * read-state if this FB is bound as ctx->DrawBuffer), but no * harm. */ update_color_draw_buffers(ctx, fb); update_color_read_buffer(ctx, fb); compute_depth_max(fb); }
static void upload_polygon_stipple_offset(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &brw->intel.ctx; /* _NEW_POLYGON */ if (!ctx->Polygon.StippleFlag) return; if (intel->gen == 6) intel_emit_post_sync_nonzero_flush(intel); BEGIN_BATCH(2); OUT_BATCH(_3DSTATE_POLY_STIPPLE_OFFSET << 16 | (2-2)); /* _NEW_BUFFERS * * If we're drawing to a system window we have to invert the Y axis * in order to match the OpenGL pixel coordinate system, and our * offset must be matched to the window position. If we're drawing * to a user-created FBO then our native pixel coordinate system * works just fine, and there's no window system to worry about. */ if (_mesa_is_winsys_fbo(brw->intel.ctx.DrawBuffer)) OUT_BATCH((32 - (ctx->DrawBuffer->Height & 31)) & 31); else OUT_BATCH(0); CACHED_BATCH(); }
static void upload_polygon_stipple(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &brw->intel.ctx; GLuint i; /* _NEW_POLYGON */ if (!ctx->Polygon.StippleFlag) return; if (intel->gen == 6) intel_emit_post_sync_nonzero_flush(intel); BEGIN_BATCH(33); OUT_BATCH(_3DSTATE_POLY_STIPPLE_PATTERN << 16 | (33 - 2)); /* Polygon stipple is provided in OpenGL order, i.e. bottom * row first. If we're rendering to a window (i.e. the * default frame buffer object, 0), then we need to invert * it to match our pixel layout. But if we're rendering * to a FBO (i.e. any named frame buffer object), we *don't* * need to invert - we already match the layout. */ if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { for (i = 0; i < 32; i++) OUT_BATCH(ctx->PolygonStipple[31 - i]); /* invert */ } else { for (i = 0; i < 32; i++) OUT_BATCH(ctx->PolygonStipple[i]); } CACHED_BATCH(); }
/** * Update the viewport transformation matrix. Depends on: * - viewport pos/size * - depthrange * - window pos/size or FBO size */ void intelCalcViewport(struct gl_context * ctx) { struct intel_context *intel = intel_context(ctx); if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { _math_matrix_viewport(&intel->ViewportMatrix, ctx->Viewport.X, ctx->DrawBuffer->Height - ctx->Viewport.Y, ctx->Viewport.Width, -ctx->Viewport.Height, ctx->Viewport.Near, ctx->Viewport.Far, 1.0); } else { _math_matrix_viewport(&intel->ViewportMatrix, ctx->Viewport.X, ctx->Viewport.Y, ctx->Viewport.Width, ctx->Viewport.Height, ctx->Viewport.Near, ctx->Viewport.Far, 1.0); } }
/** * XXX THIS IS OBSOLETE - drivers should take care of detecting window * size changes and act accordingly, likely calling _mesa_resize_framebuffer(). * * GL_MESA_resize_buffers extension. * * When this function is called, we'll ask the window system how large * the current window is. If it's a new size, we'll call the driver's * ResizeBuffers function. The driver will then resize its color buffers * as needed, and maybe call the swrast's routine for reallocating * swrast-managed depth/stencil/accum/etc buffers. * \note This function should only be called through the GL API, not * from device drivers (as was done in the past). */ void _mesa_resizebuffers( struct gl_context *ctx ) { ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx ); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glResizeBuffersMESA\n"); if (!ctx->Driver.GetBufferSize) { return; } if (ctx->WinSysDrawBuffer) { GLuint newWidth, newHeight; struct gl_framebuffer *buffer = ctx->WinSysDrawBuffer; assert(_mesa_is_winsys_fbo(buffer)); /* ask device driver for size of output buffer */ ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); /* see if size of device driver's color buffer (window) has changed */ if (buffer->Width != newWidth || buffer->Height != newHeight) { if (ctx->Driver.ResizeBuffers) ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); } } if (ctx->WinSysReadBuffer && ctx->WinSysReadBuffer != ctx->WinSysDrawBuffer) { GLuint newWidth, newHeight; struct gl_framebuffer *buffer = ctx->WinSysReadBuffer; assert(_mesa_is_winsys_fbo(buffer)); /* ask device driver for size of read buffer */ ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); /* see if size of device driver's color buffer (window) has changed */ if (buffer->Width != newWidth || buffer->Height != newHeight) { if (ctx->Driver.ResizeBuffers) ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); } } ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ }
/** * Cast wrapper to convert a struct gl_framebuffer to an st_framebuffer. * Return NULL if the struct gl_framebuffer is a user-created framebuffer. * We'll only return non-null for window system framebuffers. * Note that this function may fail. */ static INLINE struct st_framebuffer * st_ws_framebuffer(struct gl_framebuffer *fb) { /* FBO cannot be casted. See st_new_framebuffer */ if (fb && _mesa_is_winsys_fbo(fb)) return (struct st_framebuffer *) fb; return NULL; }
/** * Update the current drawbuffer's _ColorDrawBufferIndex[] list, etc. * from the context's Color.DrawBuffer[] state. * Use when changing contexts. */ void _mesa_update_draw_buffers(struct gl_context *ctx) { /* should be a window system FBO */ assert(_mesa_is_winsys_fbo(ctx->DrawBuffer)); _mesa_drawbuffers(ctx, ctx->DrawBuffer, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); }
static void intel_viewport(struct gl_context *ctx) { struct brw_context *brw = brw_context(ctx); __DRIcontext *driContext = brw->driContext; if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { dri2InvalidateDrawable(driContext->driDrawablePriv); dri2InvalidateDrawable(driContext->driReadablePriv); } }
/** * Check if we're about to draw into the front color buffer. * If so, set the intel->front_buffer_dirty field to true. */ void intel_check_front_buffer_rendering(struct intel_context *intel) { const struct gl_framebuffer *fb = intel->ctx.DrawBuffer; if (_mesa_is_winsys_fbo(fb)) { /* drawing to window system buffer */ if (fb->_NumColorDrawBuffers > 0) { if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { intel->front_buffer_dirty = true; } } } }
static void intel_noninvalidate_viewport(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); __DRIcontext *driContext = intel->driContext; intelCalcViewport(ctx); if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { dri2InvalidateDrawable(driContext->driDrawablePriv); dri2InvalidateDrawable(driContext->driReadablePriv); } }
static void intel_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h) { struct intel_context *intel = intel_context(ctx); __DRIcontext *driContext = intel->driContext; if (intel->saved_viewport) intel->saved_viewport(ctx, x, y, w, h); if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { dri2InvalidateDrawable(driContext->driDrawablePriv); dri2InvalidateDrawable(driContext->driReadablePriv); } }
/** * Update the current drawbuffer's _ColorDrawBufferIndex[] list, etc. * from the context's Color.DrawBuffer[] state. * Use when changing contexts. */ void _mesa_update_draw_buffers(struct gl_context *ctx) { GLenum buffers[MAX_DRAW_BUFFERS]; GLuint i; /* should be a window system FBO */ assert(_mesa_is_winsys_fbo(ctx->DrawBuffer)); for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) buffers[i] = ctx->Color.DrawBuffer[i]; _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL); }
/** * Like \sa _mesa_drawbuffers(), this is a helper function for setting * GL_READ_BUFFER state in the context and current FBO. * \param ctx the rendering context * \param buffer GL_FRONT, GL_BACK, GL_COLOR_ATTACHMENT0, etc. * \param bufferIndex the numerical index corresponding to 'buffer' */ void _mesa_readbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, GLenum buffer, GLint bufferIndex) { if ((fb == ctx->ReadBuffer) && _mesa_is_winsys_fbo(fb)) { /* Only update the per-context READ_BUFFER state if we're bound to * a window-system framebuffer. */ ctx->Pixel.ReadBuffer = buffer; } fb->ColorReadBuffer = buffer; fb->_ColorReadBufferIndex = bufferIndex; ctx->NewState |= _NEW_BUFFERS; }
static void nouveau_flush(struct gl_context *ctx) { struct nouveau_context *nctx = to_nouveau_context(ctx); struct nouveau_pushbuf *push = context_push(ctx); PUSH_KICK(push); if (_mesa_is_winsys_fbo(ctx->DrawBuffer) && ctx->DrawBuffer->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { __DRIscreen *screen = nctx->screen->dri_screen; __DRIdri2LoaderExtension *dri2 = screen->dri2.loader; __DRIdrawable *drawable = nctx->dri_context->driDrawablePriv; dri2->flushFrontBuffer(drawable, drawable->loaderPrivate); } }
/* ============================================================= * Hardware clipping */ static void i830Scissor(struct gl_context * ctx) { struct i830_context *i830 = i830_context(ctx); int x1, y1, x2, y2; if (!ctx->DrawBuffer) return; DBG("%s %d,%d %dx%d\n", __func__, ctx->Scissor.ScissorArray[0].X, ctx->Scissor.ScissorArray[0].Y, ctx->Scissor.ScissorArray[0].Width, ctx->Scissor.ScissorArray[0].Height); if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { x1 = ctx->Scissor.ScissorArray[0].X; y1 = ctx->DrawBuffer->Height - (ctx->Scissor.ScissorArray[0].Y + ctx->Scissor.ScissorArray[0].Height); x2 = ctx->Scissor.ScissorArray[0].X + ctx->Scissor.ScissorArray[0].Width - 1; y2 = y1 + ctx->Scissor.ScissorArray[0].Height - 1; DBG("%s %d..%d,%d..%d (inverted)\n", __func__, x1, x2, y1, y2); } else { /* FBO - not inverted */ x1 = ctx->Scissor.ScissorArray[0].X; y1 = ctx->Scissor.ScissorArray[0].Y; x2 = ctx->Scissor.ScissorArray[0].X + ctx->Scissor.ScissorArray[0].Width - 1; y2 = ctx->Scissor.ScissorArray[0].Y + ctx->Scissor.ScissorArray[0].Height - 1; DBG("%s %d..%d,%d..%d (not inverted)\n", __func__, x1, x2, y1, y2); } x1 = CLAMP(x1, 0, ctx->DrawBuffer->Width - 1); y1 = CLAMP(y1, 0, ctx->DrawBuffer->Height - 1); x2 = CLAMP(x2, 0, ctx->DrawBuffer->Width - 1); y2 = CLAMP(y2, 0, ctx->DrawBuffer->Height - 1); DBG("%s %d..%d,%d..%d (clamped)\n", __func__, x1, x2, y1, y2); I830_STATECHANGE(i830, I830_UPLOAD_BUFFERS); i830->state.Buffer[I830_DESTREG_SR1] = (y1 << 16) | (x1 & 0xffff); i830->state.Buffer[I830_DESTREG_SR2] = (y2 << 16) | (x2 & 0xffff); }
static void intelReadBuffer(struct gl_context * ctx, GLenum mode) { if (ctx->DrawBuffer && _mesa_is_winsys_fbo(ctx->DrawBuffer)) { struct intel_context *const intel = intel_context(ctx); const bool was_front_buffer_reading = intel->is_front_buffer_reading; intel->is_front_buffer_reading = (mode == GL_FRONT_LEFT) || (mode == GL_FRONT); /* If we weren't front-buffer reading before but we are now, * invalidate our DRI drawable so we'll ask for new buffers * (including the fake front) before we start reading again. */ if (!was_front_buffer_reading && intel->is_front_buffer_reading) dri2InvalidateDrawable(intel->driContext->driReadablePriv); } }
/** * Resize the given framebuffer's renderbuffers to the new width and height. * This should only be used for window-system framebuffers, not * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). * This will typically be called directly from a device driver. * * \note it's possible for ctx to be null since a window can be resized * without a currently bound rendering context. */ void _mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, GLuint width, GLuint height) { GLuint i; /* XXX I think we could check if the size is not changing * and return early. */ /* Can only resize win-sys framebuffer objects */ assert(_mesa_is_winsys_fbo(fb)); for (i = 0; i < BUFFER_COUNT; i++) { struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { struct gl_renderbuffer *rb = att->Renderbuffer; /* only resize if size is changing */ if (rb->Width != width || rb->Height != height) { if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { assert(rb->Width == width); assert(rb->Height == height); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); /* no return */ } } } } fb->Width = width; fb->Height = height; if (ctx) { /* update scissor / window bounds */ _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); /* Signal new buffer state so that swrast will update its clipping * info (the CLIP_BIT flag). */ ctx->NewState |= _NEW_BUFFERS; } }
static void intel_flush_front(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); __DRIcontext *driContext = intel->driContext; __DRIdrawable *driDrawable = driContext->driDrawablePriv; __DRIscreen *const screen = intel->intelScreen->driScrnPriv; if (intel->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) { if (flushFront(screen) && driDrawable && driDrawable->loaderPrivate) { flushFront(screen)(driDrawable, driDrawable->loaderPrivate); /* We set the dirty bit in intel_prepare_render() if we're * front buffer rendering once we get there. */ intel->front_buffer_dirty = false; } } }
/* ============================================================= * Hardware clipping */ static void i915Scissor(struct gl_context * ctx, GLint x, GLint y, GLsizei w, GLsizei h) { struct i915_context *i915 = I915_CONTEXT(ctx); int x1, y1, x2, y2; if (!ctx->DrawBuffer) return; DBG("%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h); if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) { x1 = x; y1 = ctx->DrawBuffer->Height - (y + h); x2 = x + w - 1; y2 = y1 + h - 1; DBG("%s %d..%d,%d..%d (inverted)\n", __FUNCTION__, x1, x2, y1, y2); } else { /* FBO - not inverted */ x1 = x; y1 = y; x2 = x + w - 1; y2 = y + h - 1; DBG("%s %d..%d,%d..%d (not inverted)\n", __FUNCTION__, x1, x2, y1, y2); } x1 = CLAMP(x1, 0, ctx->DrawBuffer->Width - 1); y1 = CLAMP(y1, 0, ctx->DrawBuffer->Height - 1); x2 = CLAMP(x2, 0, ctx->DrawBuffer->Width - 1); y2 = CLAMP(y2, 0, ctx->DrawBuffer->Height - 1); DBG("%s %d..%d,%d..%d (clamped)\n", __FUNCTION__, x1, x2, y1, y2); I915_STATECHANGE(i915, I915_UPLOAD_BUFFERS); i915->state.Buffer[I915_DESTREG_SR1] = (y1 << 16) | (x1 & 0xffff); i915->state.Buffer[I915_DESTREG_SR2] = (y2 << 16) | (x2 & 0xffff); }
bool intel_copy_texsubimage(struct intel_context *intel, struct intel_texture_image *intelImage, GLint dstx, GLint dsty, struct intel_renderbuffer *irb, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_context *ctx = &intel->ctx; struct intel_region *region; const GLenum internalFormat = intelImage->base.Base.InternalFormat; bool copy_supported = false; bool copy_supported_with_alpha_override = false; intel_prepare_render(intel); if (!intelImage->mt || !irb || !irb->mt) { if (unlikely(INTEL_DEBUG & DEBUG_PERF)) fprintf(stderr, "%s fail %p %p (0x%08x)\n", __FUNCTION__, intelImage->mt, irb, internalFormat); return false; } else { region = irb->mt->region; assert(region); } /* According to the Ivy Bridge PRM, Vol1 Part4, section 1.2.1.2 (Graphics * Data Size Limitations): * * The BLT engine is capable of transferring very large quantities of * graphics data. Any graphics data read from and written to the * destination is permitted to represent a number of pixels that * occupies up to 65,536 scan lines and up to 32,768 bytes per scan line * at the destination. The maximum number of pixels that may be * represented per scan line’s worth of graphics data depends on the * color depth. * * Furthermore, intelEmitCopyBlit (which is called below) uses a signed * 16-bit integer to represent buffer pitch, so it can only handle buffer * pitches < 32k. * * As a result of these two limitations, we can only use the blitter to do * this copy when the region's pitch is less than 32k. */ if (region->pitch >= 32768) return false; if (intelImage->base.Base.TexObject->Target == GL_TEXTURE_1D_ARRAY || intelImage->base.Base.TexObject->Target == GL_TEXTURE_2D_ARRAY) { perf_debug("no support for array textures\n"); } copy_supported = intelImage->base.Base.TexFormat == intel_rb_format(irb); /* Converting ARGB8888 to XRGB8888 is trivial: ignore the alpha bits */ if (intel_rb_format(irb) == MESA_FORMAT_ARGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_XRGB8888) { copy_supported = true; } /* Converting XRGB8888 to ARGB8888 requires setting the alpha bits to 1.0 */ if (intel_rb_format(irb) == MESA_FORMAT_XRGB8888 && intelImage->base.Base.TexFormat == MESA_FORMAT_ARGB8888) { copy_supported_with_alpha_override = true; } if (!copy_supported && !copy_supported_with_alpha_override) { if (unlikely(INTEL_DEBUG & DEBUG_PERF)) fprintf(stderr, "%s mismatched formats %s, %s\n", __FUNCTION__, _mesa_get_format_name(intelImage->base.Base.TexFormat), _mesa_get_format_name(intel_rb_format(irb))); return false; } { GLuint image_x, image_y; GLshort src_pitch; /* get dest x/y in destination texture */ intel_miptree_get_image_offset(intelImage->mt, intelImage->base.Base.Level, intelImage->base.Base.Face, &image_x, &image_y); /* The blitter can't handle Y-tiled buffers. */ if (intelImage->mt->region->tiling == I915_TILING_Y) { return false; } if (_mesa_is_winsys_fbo(ctx->ReadBuffer)) { /* Flip vertical orientation for system framebuffers */ y = ctx->ReadBuffer->Height - (y + height); src_pitch = -region->pitch; } else { /* reading from a FBO, y is already oriented the way we like */ src_pitch = region->pitch; } /* blit from src buffer to texture */ if (!intelEmitCopyBlit(intel, intelImage->mt->cpp, src_pitch, region->bo, 0, region->tiling, intelImage->mt->region->pitch, intelImage->mt->region->bo, 0, intelImage->mt->region->tiling, irb->draw_x + x, irb->draw_y + y, image_x + dstx, image_y + dsty, width, height, GL_COPY)) { return false; } } if (copy_supported_with_alpha_override) intel_set_teximage_alpha_to_one(ctx, intelImage); return true; }
/** * Use blitting to clear the renderbuffers named by 'flags'. * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferIndexes field * since that might include software renderbuffers or renderbuffers * which we're clearing with triangles. * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear */ GLbitfield intelClearWithBlit(struct gl_context *ctx, GLbitfield mask) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; GLuint clear_depth_value, clear_depth_mask; GLint cx, cy, cw, ch; GLbitfield fail_mask = 0; BATCH_LOCALS; /* Note: we don't use this function on Gen7+ hardware, so we can safely * ignore fast color clear issues. */ assert(intel->gen < 7); /* * Compute values for clearing the buffers. */ clear_depth_value = 0; clear_depth_mask = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth_value = (GLuint) (fb->_DepthMax * ctx->Depth.Clear); clear_depth_mask = XY_BLT_WRITE_RGB; } if (mask & BUFFER_BIT_STENCIL) { clear_depth_value |= (ctx->Stencil.Clear & 0xff) << 24; clear_depth_mask |= XY_BLT_WRITE_ALPHA; } cx = fb->_Xmin; if (_mesa_is_winsys_fbo(fb)) cy = ctx->DrawBuffer->Height - fb->_Ymax; else cy = fb->_Ymin; cw = fb->_Xmax - fb->_Xmin; ch = fb->_Ymax - fb->_Ymin; if (cw == 0 || ch == 0) return 0; /* Loop over all renderbuffers */ mask &= (1 << BUFFER_COUNT) - 1; while (mask) { GLuint buf = ffs(mask) - 1; bool is_depth_stencil = buf == BUFFER_DEPTH || buf == BUFFER_STENCIL; struct intel_renderbuffer *irb; int x1, y1, x2, y2; uint32_t clear_val; uint32_t BR13, CMD; struct intel_region *region; int pitch, cpp; drm_intel_bo *aper_array[2]; mask &= ~(1 << buf); irb = intel_get_renderbuffer(fb, buf); if (irb && irb->mt) { region = irb->mt->region; assert(region); assert(region->bo); } else { fail_mask |= 1 << buf; continue; } /* OK, clear this renderbuffer */ x1 = cx + irb->draw_x; y1 = cy + irb->draw_y; x2 = cx + cw + irb->draw_x; y2 = cy + ch + irb->draw_y; pitch = region->pitch; cpp = region->cpp; DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", __FUNCTION__, region->bo, pitch, x1, y1, x2 - x1, y2 - y1); BR13 = 0xf0 << 16; CMD = XY_COLOR_BLT_CMD; /* Setup the blit command */ if (cpp == 4) { if (is_depth_stencil) { CMD |= clear_depth_mask; } else { /* clearing RGBA */ CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } } assert(region->tiling != I915_TILING_Y); BR13 |= pitch; if (is_depth_stencil) { clear_val = clear_depth_value; } else { uint8_t clear[4]; GLfloat *color = ctx->Color.ClearColor.f; _mesa_unclamped_float_rgba_to_ubyte(clear, color); switch (intel_rb_format(irb)) { case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: clear_val = PACK_COLOR_8888(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_RGB565: clear_val = PACK_COLOR_565(clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB4444: clear_val = PACK_COLOR_4444(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_ARGB1555: clear_val = PACK_COLOR_1555(clear[3], clear[0], clear[1], clear[2]); break; case MESA_FORMAT_A8: clear_val = PACK_COLOR_8888(clear[3], clear[3], clear[3], clear[3]); break; default: fail_mask |= 1 << buf; continue; } } BR13 |= br13_for_cpp(cpp); assert(x1 < x2); assert(y1 < y2); /* do space check before going any further */ aper_array[0] = intel->batch.bo; aper_array[1] = region->bo; if (drm_intel_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array)) != 0) { intel_batchbuffer_flush(intel); } BEGIN_BATCH(6); OUT_BATCH(CMD | (6 - 2)); OUT_BATCH(BR13); OUT_BATCH((y1 << 16) | x1); OUT_BATCH((y2 << 16) | x2); OUT_RELOC_FENCED(region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(clear_val); ADVANCE_BATCH(); if (intel->always_flush_cache) intel_batchbuffer_emit_mi_flush(intel); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) mask &= ~(BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); } return fail_mask; }
/** * Helper function to set the GL_DRAW_BUFFER state in the context and * current FBO. Called via glDrawBuffer(), glDrawBuffersARB() * * All error checking will have been done prior to calling this function * so nothing should go wrong at this point. * * \param ctx current context * \param n number of color outputs to set * \param buffers array[n] of colorbuffer names, like GL_LEFT. * \param destMask array[n] of BUFFER_BIT_* bitmasks which correspond to the * colorbuffer names. (i.e. GL_FRONT_AND_BACK => * BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT). */ void _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, const GLbitfield *destMask) { struct gl_framebuffer *fb = ctx->DrawBuffer; GLbitfield mask[MAX_DRAW_BUFFERS]; GLuint buf; if (!destMask) { /* compute destMask values now */ const GLbitfield supportedMask = supported_buffer_bitmask(ctx, fb); GLuint output; for (output = 0; output < n; output++) { mask[output] = draw_buffer_enum_to_bitmask(ctx, buffers[output]); ASSERT(mask[output] != BAD_MASK); mask[output] &= supportedMask; } destMask = mask; } /* * destMask[0] may have up to four bits set * (ex: glDrawBuffer(GL_FRONT_AND_BACK)). * Otherwise, destMask[x] can only have one bit set. */ if (n > 0 && _mesa_bitcount(destMask[0]) > 1) { GLuint count = 0, destMask0 = destMask[0]; while (destMask0) { GLint bufIndex = ffs(destMask0) - 1; if (fb->_ColorDrawBufferIndexes[count] != bufIndex) { updated_drawbuffers(ctx); fb->_ColorDrawBufferIndexes[count] = bufIndex; } count++; destMask0 &= ~(1 << bufIndex); } fb->ColorDrawBuffer[0] = buffers[0]; fb->_NumColorDrawBuffers = count; } else { GLuint count = 0; for (buf = 0; buf < n; buf++ ) { if (destMask[buf]) { GLint bufIndex = ffs(destMask[buf]) - 1; /* only one bit should be set in the destMask[buf] field */ ASSERT(_mesa_bitcount(destMask[buf]) == 1); if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) { updated_drawbuffers(ctx); fb->_ColorDrawBufferIndexes[buf] = bufIndex; } count = buf + 1; } else { if (fb->_ColorDrawBufferIndexes[buf] != -1) { updated_drawbuffers(ctx); fb->_ColorDrawBufferIndexes[buf] = -1; } } fb->ColorDrawBuffer[buf] = buffers[buf]; } fb->_NumColorDrawBuffers = count; } /* set remaining outputs to -1 (GL_NONE) */ for (buf = fb->_NumColorDrawBuffers; buf < ctx->Const.MaxDrawBuffers; buf++) { if (fb->_ColorDrawBufferIndexes[buf] != -1) { updated_drawbuffers(ctx); fb->_ColorDrawBufferIndexes[buf] = -1; } } for (buf = n; buf < ctx->Const.MaxDrawBuffers; buf++) { fb->ColorDrawBuffer[buf] = GL_NONE; } if (_mesa_is_winsys_fbo(fb)) { /* also set context drawbuffer state */ for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) { updated_drawbuffers(ctx); ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf]; } } } }
/** * Called by glDrawBuffersARB; specifies the destination color renderbuffers * for N fragment program color outputs. * \sa _mesa_DrawBuffer * \param n number of outputs * \param buffers array [n] of renderbuffer names. Unlike glDrawBuffer, the * names cannot specify more than one buffer. For example, * GL_FRONT_AND_BACK is illegal. */ void GLAPIENTRY _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) { GLint output; GLbitfield usedBufferMask, supportedMask; GLbitfield destMask[MAX_DRAW_BUFFERS]; GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); /* Turns out n==0 is a valid input that should not produce an error. * The remaining code below correctly handles the n==0 case. * * From the OpenGL 3.0 specification, page 258: * "An INVALID_VALUE error is generated if n is greater than * MAX_DRAW_BUFFERS." */ if (n < 0 || n > (GLsizei) ctx->Const.MaxDrawBuffers) { _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)"); return; } supportedMask = supported_buffer_bitmask(ctx, ctx->DrawBuffer); usedBufferMask = 0x0; /* From the ES 3.0 specification, page 180: * "If the GL is bound to the default framebuffer, then n must be 1 * and the constant must be BACK or NONE." */ if (_mesa_is_gles3(ctx) && _mesa_is_winsys_fbo(ctx->DrawBuffer) && (n != 1 || (buffers[0] != GL_NONE && buffers[0] != GL_BACK))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffers(buffer)"); return; } /* complicated error checking... */ for (output = 0; output < n; output++) { if (buffers[output] == GL_NONE) { destMask[output] = 0x0; } else { /* Page 259 (page 275 of the PDF) in section 4.2.1 of the OpenGL 3.0 * spec (20080923) says: * * "If the GL is bound to a framebuffer object and DrawBuffers is * supplied with [...] COLOR_ATTACHMENTm where m is greater than * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error * INVALID_OPERATION results." */ if (_mesa_is_user_fbo(ctx->DrawBuffer) && buffers[output] >= GL_COLOR_ATTACHMENT0 + ctx->Const.MaxDrawBuffers) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(buffer)"); return; } destMask[output] = draw_buffer_enum_to_bitmask(ctx, buffers[output]); /* From the OpenGL 3.0 specification, page 258: * "Each buffer listed in bufs must be one of the values from tables * 4.5 or 4.6. Otherwise, an INVALID_ENUM error is generated. */ if (destMask[output] == BAD_MASK) { _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)"); return; } /* From the OpenGL 4.0 specification, page 256: * "For both the default framebuffer and framebuffer objects, the * constants FRONT, BACK, LEFT, RIGHT, and FRONT_AND_BACK are not * valid in the bufs array passed to DrawBuffers, and will result in * the error INVALID_ENUM. This restriction is because these * constants may themselves refer to multiple buffers, as shown in * table 4.4." * Previous versions of the OpenGL specification say INVALID_OPERATION, * but the Khronos conformance tests expect INVALID_ENUM. */ if (_mesa_bitcount(destMask[output]) > 1) { _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)"); return; } /* From the OpenGL 3.0 specification, page 259: * "If the GL is bound to the default framebuffer and DrawBuffers is * supplied with a constant (other than NONE) that does not indicate * any of the color buffers allocated to the GL context by the window * system, the error INVALID_OPERATION will be generated. * * If the GL is bound to a framebuffer object and DrawBuffers is * supplied with a constant from table 4.6 [...] then the error * INVALID_OPERATION results." */ destMask[output] &= supportedMask; if (destMask[output] == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(unsupported buffer)"); return; } /* ES 3.0 is even more restrictive. From the ES 3.0 spec, page 180: * "If the GL is bound to a framebuffer object, the ith buffer listed * in bufs must be COLOR_ATTACHMENTi or NONE. [...] INVALID_OPERATION." */ if (_mesa_is_gles3(ctx) && _mesa_is_user_fbo(ctx->DrawBuffer) && buffers[output] != GL_NONE && buffers[output] != GL_COLOR_ATTACHMENT0 + output) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffers(buffer)"); return; } /* From the OpenGL 3.0 specification, page 258: * "Except for NONE, a buffer may not appear more than once in the * array pointed to by bufs. Specifying a buffer more then once will * result in the error INVALID_OPERATION." */ if (destMask[output] & usedBufferMask) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(duplicated buffer)"); return; } /* update bitmask */ usedBufferMask |= destMask[output]; } } /* OK, if we get here, there were no errors so set the new state */ _mesa_drawbuffers(ctx, n, buffers, destMask); /* * Call device driver function. Note that n can be equal to 0, * in which case we don't want to reference buffers[0], which * may not be valid. */ if (ctx->Driver.DrawBuffers) ctx->Driver.DrawBuffers(ctx, n, buffers); else if (ctx->Driver.DrawBuffer) ctx->Driver.DrawBuffer(ctx, n > 0 ? buffers[0] : GL_NONE); }
static bool do_blit_drawpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid * pixels) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; drm_intel_bo *src_buffer; DBG("%s\n", __FUNCTION__); if (!intel_check_blit_fragment_ops(ctx, false)) return false; if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) { DBG("%s: fallback due to MRT\n", __FUNCTION__); return false; } struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (!_mesa_format_matches_format_and_type(irb->mt->format, format, type, false)) { DBG("%s: bad format for blit\n", __FUNCTION__); return false; } if (unpack->SwapBytes || unpack->LsbFirst || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: bad packing params\n", __FUNCTION__); return false; } int src_stride = _mesa_image_row_stride(unpack, width, format, type); bool src_flip = false; /* Mesa flips the src_stride for unpack->Invert, but we want our mt to have * a normal src_stride. */ if (unpack->Invert) { src_stride = -src_stride; src_flip = true; } src_offset = (GLintptr)pixels; src_offset += _mesa_image_offset(2, unpack, width, height, format, type, 0, 0, 0); intel_prepare_render(brw); src_buffer = intel_bufferobj_buffer(brw, src, src_offset, width * height * irb->mt->cpp); struct intel_mipmap_tree *pbo_mt = intel_miptree_create_for_bo(brw, src_buffer, irb->mt->format, src_offset, width, height, src_stride, I915_TILING_NONE); if (!pbo_mt) return false; if (!intel_miptree_blit(brw, pbo_mt, 0, 0, 0, 0, src_flip, irb->mt, irb->mt_level, irb->mt_layer, x, y, _mesa_is_winsys_fbo(ctx->DrawBuffer), width, height, GL_COPY)) { DBG("%s: blit failed\n", __FUNCTION__); intel_miptree_release(&pbo_mt); return false; } intel_miptree_release(&pbo_mt); if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += width * height; intel_check_front_buffer_rendering(brw); DBG("%s: success\n", __FUNCTION__); return true; }
/* * Render a bitmap. */ static bool do_blit_bitmap( struct gl_context *ctx, GLint dstx, GLint dsty, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *irb; GLfloat tmpColor[4]; GLubyte ubcolor[4]; GLuint color; GLsizei bitmap_width = width; GLsizei bitmap_height = height; GLint px, py; GLuint stipple[32]; GLint orig_dstx = dstx; GLint orig_dsty = dsty; /* Update draw buffer bounds */ _mesa_update_state(ctx); if (ctx->Depth.Test) { /* The blit path produces incorrect results when depth testing is on. * It seems the blit Z coord is always 1.0 (the far plane) so fragments * will likely be obscured by other, closer geometry. */ return false; } intel_prepare_render(intel); if (fb->_NumColorDrawBuffers != 1) { perf_debug("accelerated glBitmap() only supports rendering to a " "single color buffer\n"); return false; } irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]); if (_mesa_is_bufferobj(unpack->BufferObj)) { bitmap = map_pbo(ctx, width, height, unpack, bitmap); if (bitmap == NULL) return true; /* even though this is an error, we're done */ } COPY_4V(tmpColor, ctx->Current.RasterColor); if (_mesa_need_secondary_color(ctx)) { ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor); } UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]); switch (irb->mt->format) { case MESA_FORMAT_B8G8R8A8_UNORM: case MESA_FORMAT_B8G8R8X8_UNORM: color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]); break; case MESA_FORMAT_B5G6R5_UNORM: color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]); break; default: perf_debug("Unsupported format %s in accelerated glBitmap()\n", _mesa_get_format_name(irb->mt->format)); return false; } if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F)) return false; /* Clip to buffer bounds and scissor. */ if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &dstx, &dsty, &width, &height)) goto out; dsty = y_flip(fb, dsty, height); #define DY 32 #define DX 32 /* Chop it all into chunks that can be digested by hardware: */ for (py = 0; py < height; py += DY) { for (px = 0; px < width; px += DX) { int h = MIN2(DY, height - py); int w = MIN2(DX, width - px); GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8; GLenum logic_op = ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY; assert(sz <= sizeof(stipple)); memset(stipple, 0, sz); /* May need to adjust this when padding has been introduced in * sz above: * * Have to translate destination coordinates back into source * coordinates. */ int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack, bitmap, -orig_dstx + (dstx + px), -orig_dsty + y_flip(fb, dsty + py, h), w, h, (GLubyte *)stipple, 8, _mesa_is_winsys_fbo(fb)); if (count == 0) continue; if (!intelEmitImmediateColorExpandBlit(intel, irb->mt->cpp, (GLubyte *)stipple, sz, color, irb->mt->region->pitch, irb->mt->region->bo, 0, irb->mt->region->tiling, dstx + px, dsty + py, w, h, logic_op)) { return false; } if (ctx->Query.CurrentOcclusionObject) ctx->Query.CurrentOcclusionObject->Result += count; } } out: if (unlikely(INTEL_DEBUG & DEBUG_SYNC)) intel_batchbuffer_flush(intel); if (_mesa_is_bufferobj(unpack->BufferObj)) { /* done with PBO so unmap it now */ ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL); } intel_check_front_buffer_rendering(intel); return true; }
static GLboolean do_blit_readpixels(struct gl_context * ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid * pixels) { radeonContextPtr radeon = RADEON_CONTEXT(ctx); const struct radeon_renderbuffer *rrb = radeon_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); const gl_format dst_format = gl_format_and_type_to_mesa_format(format, type); unsigned dst_rowstride, dst_imagesize, aligned_rowstride, flip_y; struct radeon_bo *dst_buffer; GLint dst_x = 0, dst_y = 0; intptr_t dst_offset; /* It's not worth if number of pixels to copy is really small */ if (width * height < 100) { return GL_FALSE; } if (dst_format == MESA_FORMAT_NONE || !radeon->vtbl.check_blit(dst_format, rrb->pitch / rrb->cpp) || !radeon->vtbl.blit) { return GL_FALSE; } if (ctx->_ImageTransferState || ctx->Color.ColorLogicOpEnabled) { return GL_FALSE; } if (pack->SwapBytes || pack->LsbFirst) { return GL_FALSE; } if (pack->RowLength > 0) { dst_rowstride = pack->RowLength; } else { dst_rowstride = width; } if (!_mesa_clip_copytexsubimage(ctx, &dst_x, &dst_y, &x, &y, &width, &height)) { return GL_TRUE; } assert(x >= 0 && y >= 0); aligned_rowstride = get_texture_image_row_stride(radeon, dst_format, dst_rowstride, 0, GL_TEXTURE_2D); dst_rowstride *= _mesa_get_format_bytes(dst_format); if (_mesa_is_bufferobj(pack->BufferObj) && aligned_rowstride != dst_rowstride) return GL_FALSE; dst_imagesize = get_texture_image_size(dst_format, aligned_rowstride, height, 1, 0); if (!_mesa_is_bufferobj(pack->BufferObj)) { dst_buffer = radeon_bo_open(radeon->radeonScreen->bom, 0, dst_imagesize, 1024, RADEON_GEM_DOMAIN_GTT, 0); dst_offset = 0; } else { dst_buffer = get_radeon_buffer_object(pack->BufferObj)->bo; dst_offset = (intptr_t)pixels; } /* Disable source Y flipping for FBOs */ flip_y = _mesa_is_winsys_fbo(ctx->ReadBuffer); if (pack->Invert) { y = rrb->base.Base.Height - height - y; flip_y = !flip_y; } if (radeon->vtbl.blit(ctx, rrb->bo, rrb->draw_offset, rrb->base.Base.Format, rrb->pitch / rrb->cpp, rrb->base.Base.Width, rrb->base.Base.Height, x, y, dst_buffer, dst_offset, dst_format, aligned_rowstride / _mesa_get_format_bytes(dst_format), width, height, 0, /* dst_x */ 0, /* dst_y */ width, height, flip_y)) { if (!_mesa_is_bufferobj(pack->BufferObj)) { radeon_bo_map(dst_buffer, 0); copy_rows(pixels, dst_rowstride, dst_buffer->ptr, aligned_rowstride, height, dst_rowstride); radeon_bo_unmap(dst_buffer); radeon_bo_unref(dst_buffer); } return GL_TRUE; } if (!_mesa_is_bufferobj(pack->BufferObj)) radeon_bo_unref(dst_buffer); return GL_FALSE; }