/** * Get the intel_region which is the source for any glCopyTex[Sub]Image call. * * Do the best we can using the blitter. A future project is to use * the texture engine and fragment programs for these copies. */ static const struct intel_region * get_teximage_source(struct intel_context *intel, GLenum internalFormat) { struct intel_renderbuffer *irb; DBG("%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat)); switch (internalFormat) { case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16_ARB: irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH); if (irb && irb->region && irb->region->cpp == 2) return irb->region; return NULL; case GL_DEPTH24_STENCIL8_EXT: case GL_DEPTH_STENCIL_EXT: irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH); if (irb && irb->region && irb->region->cpp == 4) return irb->region; return NULL; case GL_RGBA: case GL_RGBA8: return intel_readbuf_region(intel); case GL_RGB: if (intel->intelScreen->cpp == 2) return intel_readbuf_region(intel); return NULL; default: return NULL; } }
static void intel_update_image_buffers(struct intel_context *intel, __DRIdrawable *drawable) { struct gl_framebuffer *fb = drawable->driverPrivate; __DRIscreen *screen = intel->intelScreen->driScrnPriv; struct intel_renderbuffer *front_rb; struct intel_renderbuffer *back_rb; struct __DRIimageList images; unsigned int format; uint32_t buffer_mask = 0; int ret; front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); if (back_rb) format = intel_rb_format(back_rb); else if (front_rb) format = intel_rb_format(front_rb); else return; if (front_rb && (_mesa_is_front_buffer_drawing(fb) || _mesa_is_front_buffer_reading(fb) || !back_rb)) { buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; } if (back_rb) buffer_mask |= __DRI_IMAGE_BUFFER_BACK; ret = screen->image.loader->getBuffers(drawable, driGLFormatToImageFormat(format), &drawable->dri2.stamp, drawable->loaderPrivate, buffer_mask, &images); if (!ret) return; if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { drawable->w = images.front->width; drawable->h = images.front->height; intel_update_image_buffer(intel, drawable, front_rb, images.front, __DRI_IMAGE_BUFFER_FRONT); } if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) { drawable->w = images.back->width; drawable->h = images.back->height; intel_update_image_buffer(intel, drawable, back_rb, images.back, __DRI_IMAGE_BUFFER_BACK); } }
void intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) { struct gl_framebuffer *fb = drawable->driverPrivate; struct intel_renderbuffer *rb; struct brw_context *brw = context->driverPrivate; __DRIbuffer *buffers = NULL; int i, count; const char *region_name; /* Set this up front, so that in case our buffers get invalidated * while we're getting new buffers, we don't clobber the stamp and * thus ignore the invalidate. */ drawable->lastStamp = drawable->dri2.stamp; if (unlikely(INTEL_DEBUG & DEBUG_DRI)) fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable); intel_query_dri2_buffers(brw, drawable, &buffers, &count); if (buffers == NULL) return; for (i = 0; i < count; i++) { switch (buffers[i].attachment) { case __DRI_BUFFER_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 front buffer"; break; case __DRI_BUFFER_FAKE_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 fake front buffer"; break; case __DRI_BUFFER_BACK_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); region_name = "dri2 back buffer"; break; case __DRI_BUFFER_DEPTH: case __DRI_BUFFER_HIZ: case __DRI_BUFFER_DEPTH_STENCIL: case __DRI_BUFFER_STENCIL: case __DRI_BUFFER_ACCUM: default: fprintf(stderr, "unhandled buffer attach event, attachment type %d\n", buffers[i].attachment); return; } intel_process_dri2_buffer(brw, drawable, &buffers[i], rb, region_name); } driUpdateFramebufferSize(&brw->ctx, drawable); }
/** * \brief Query DRI2 to obtain a DRIdrawable's buffers. * * To determine which DRI buffers to request, examine the renderbuffers * attached to the drawable's framebuffer. Then request the buffers with * DRI2GetBuffers() or DRI2GetBuffersWithFormat(). * * This is called from intel_update_renderbuffers(). * * \param drawable Drawable whose buffers are queried. * \param buffers [out] List of buffers returned by DRI2 query. * \param buffer_count [out] Number of buffers returned. * * \see intel_update_renderbuffers() * \see DRI2GetBuffers() * \see DRI2GetBuffersWithFormat() */ static void intel_query_dri2_buffers(struct brw_context *brw, __DRIdrawable *drawable, __DRIbuffer **buffers, int *buffer_count) { __DRIscreen *screen = brw->intelScreen->driScrnPriv; struct gl_framebuffer *fb = drawable->driverPrivate; int i = 0; unsigned attachments[8]; struct intel_renderbuffer *front_rb; struct intel_renderbuffer *back_rb; front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); memset(attachments, 0, sizeof(attachments)); if ((brw->is_front_buffer_rendering || brw->is_front_buffer_reading || !back_rb) && front_rb) { /* If a fake front buffer is in use, then querying for * __DRI_BUFFER_FRONT_LEFT will cause the server to copy the image from * the real front buffer to the fake front buffer. So before doing the * query, we need to make sure all the pending drawing has landed in the * real front buffer. */ intel_flush(&brw->ctx); intel_flush_front(&brw->ctx); attachments[i++] = __DRI_BUFFER_FRONT_LEFT; attachments[i++] = intel_bits_per_pixel(front_rb); } else if (front_rb && brw->front_buffer_dirty) { /* We have pending front buffer rendering, but we aren't querying for a * front buffer. If the front buffer we have is a fake front buffer, * the X server is going to throw it away when it processes the query. * So before doing the query, make sure all the pending drawing has * landed in the real front buffer. */ intel_flush(&brw->ctx); intel_flush_front(&brw->ctx); } if (back_rb) { attachments[i++] = __DRI_BUFFER_BACK_LEFT; attachments[i++] = intel_bits_per_pixel(back_rb); } assert(i <= ARRAY_SIZE(attachments)); *buffers = screen->dri2.loader->getBuffersWithFormat(drawable, &drawable->w, &drawable->h, attachments, i / 2, buffer_count, drawable->loaderPrivate); }
uint32_t brw_depthbuffer_format(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb; if (!drb && (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) && !srb->mt->stencil_mt && (intel_rb_format(srb) == MESA_FORMAT_S8_Z24 || intel_rb_format(srb) == MESA_FORMAT_Z32_FLOAT_X24S8)) { drb = srb; } if (!drb) return BRW_DEPTHFORMAT_D32_FLOAT; switch (drb->mt->format) { case MESA_FORMAT_Z16: return BRW_DEPTHFORMAT_D16_UNORM; case MESA_FORMAT_Z32_FLOAT: return BRW_DEPTHFORMAT_D32_FLOAT; case MESA_FORMAT_X8_Z24: if (intel->gen >= 6) { return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT; } else { /* Use D24_UNORM_S8, not D24_UNORM_X8. * * D24_UNORM_X8 was not introduced until Gen5. (See the Ironlake PRM, * Volume 2, Part 1, Section 8.4.6 "Depth/Stencil Buffer State", Bits * 3DSTATE_DEPTH_BUFFER.Surface_Format). * * However, on Gen5, D24_UNORM_X8 may be used only if separate * stencil is enabled, and we never enable it. From the Ironlake PRM, * same section as above, Bit 3DSTATE_DEPTH_BUFFER.Separate_Stencil_Buffer_Enable: * If this field is disabled, the Surface Format of the depth * buffer cannot be D24_UNORM_X8_UINT. */ return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; } case MESA_FORMAT_S8_Z24: return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; case MESA_FORMAT_Z32_FLOAT_X24S8: return BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT; default: _mesa_problem(ctx, "Unexpected depth format %s\n", _mesa_get_format_name(intel_rb_format(drb))); return BRW_DEPTHFORMAT_D16_UNORM; } }
static void prepare_depthbuffer(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb = intel_get_renderbuffer(fb, BUFFER_STENCIL); if (drb) brw_add_validated_bo(brw, drb->region->buffer); if (srb) brw_add_validated_bo(brw, srb->region->buffer); }
/** * \brief Prepare for entry into glBegin/glEnd block. * * Resolve buffers before entering a glBegin/glEnd block. This is * necessary to prevent recursive calls to FLUSH_VERTICES. * * This resolves the depth buffer of each enabled depth texture and the HiZ * buffer of the attached depth renderbuffer. * * Details * ------- * When vertices are queued during a glBegin/glEnd block, those vertices must * be drawn before any rendering state changes. To ensure this, Mesa calls * FLUSH_VERTICES as a prehook to such state changes. Therefore, * FLUSH_VERTICES itself cannot change rendering state without falling into a * recursive trap. * * This precludes meta-ops, namely buffer resolves, from occurring while any * vertices are queued. To prevent that situation, we resolve some buffers on * entering a glBegin/glEnd * * \see brwCleanupExecEnd() */ static void brwPrepareExecBegin(struct gl_context *ctx) { struct brw_context *brw = brw_context(ctx); struct intel_context *intel = &brw->intel; struct intel_renderbuffer *draw_irb; struct intel_texture_object *tex_obj; if (!intel->has_hiz) { /* The context uses no feature that requires buffer resolves. */ return; } /* Resolve each enabled texture. */ for (int i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { if (!ctx->Texture.Unit[i]._ReallyEnabled) continue; tex_obj = intel_texture_object(ctx->Texture.Unit[i]._Current); if (!tex_obj || !tex_obj->mt) continue; intel_miptree_all_slices_resolve_depth(intel, tex_obj->mt); } /* Resolve the attached depth buffer. */ draw_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH); if (draw_irb) { intel_renderbuffer_resolve_hiz(intel, draw_irb); } }
/* * \brief Resolve buffers before drawing. * * Resolve the depth buffer's HiZ buffer and resolve the depth buffer of each * enabled depth texture. * * (In the future, this will also perform MSAA resolves). */ static void brw_predraw_resolve_buffers(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *depth_irb; struct intel_texture_object *tex_obj; /* Resolve the depth buffer's HiZ buffer. */ depth_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH); if (depth_irb) intel_renderbuffer_resolve_hiz(brw, depth_irb); /* Resolve depth buffer of each enabled depth texture, and color buffer of * each fast-clear-enabled color texture. */ for (int i = 0; i < BRW_MAX_TEX_UNIT; i++) { if (!ctx->Texture.Unit[i]._ReallyEnabled) continue; tex_obj = intel_texture_object(ctx->Texture.Unit[i]._Current); if (!tex_obj || !tex_obj->mt) continue; intel_miptree_all_slices_resolve_depth(brw, tex_obj->mt); intel_miptree_resolve_color(brw, tex_obj->mt); } }
unsigned int gen7_depth_format(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_region *region = NULL; if (drb) region = drb->region; else return BRW_DEPTHFORMAT_D32_FLOAT; switch (region->cpp) { case 2: return BRW_DEPTHFORMAT_D16_UNORM; case 4: if (intel->depth_buffer_is_float) return BRW_DEPTHFORMAT_D32_FLOAT; else return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT; default: assert(!"Should not get here."); } return 0; }
void intel_resolve_for_dri2_flush(struct brw_context *brw, __DRIdrawable *drawable) { if (brw->gen < 6) { /* MSAA and fast color clear are not supported, so don't waste time * checking whether a resolve is needed. */ return; } struct gl_framebuffer *fb = drawable->driverPrivate; struct intel_renderbuffer *rb; /* Usually, only the back buffer will need to be downsampled. However, * the front buffer will also need it if the user has rendered into it. */ static const gl_buffer_index buffers[2] = { BUFFER_BACK_LEFT, BUFFER_FRONT_LEFT, }; for (int i = 0; i < 2; ++i) { rb = intel_get_renderbuffer(fb, buffers[i]); if (rb == NULL || rb->mt == NULL) continue; if (rb->mt->num_samples <= 1) intel_miptree_resolve_color(brw, rb->mt); else intel_miptree_downsample(brw, rb->mt); } }
void intel_downsample_for_dri2_flush(struct intel_context *intel, __DRIdrawable *drawable) { if (intel->gen < 6) { /* MSAA is not supported, so don't waste time checking for * a multisample buffer. */ return; } struct gl_framebuffer *fb = drawable->driverPrivate; struct intel_renderbuffer *rb; /* Usually, only the back buffer will need to be downsampled. However, * the front buffer will also need it if the user has rendered into it. */ static const gl_buffer_index buffers[2] = { BUFFER_BACK_LEFT, BUFFER_FRONT_LEFT, }; for (int i = 0; i < 2; ++i) { rb = intel_get_renderbuffer(fb, buffers[i]); if (rb == NULL || rb->mt == NULL) continue; intel_miptree_downsample(intel, rb->mt); } }
static void intel_update_dri2_buffers(struct intel_context *intel, __DRIdrawable *drawable) { __DRIbuffer *buffers = NULL; int i, count; const char *region_name; struct intel_renderbuffer *rb; struct gl_framebuffer *fb = drawable->driverPrivate; intel_query_dri2_buffers(intel, drawable, &buffers, &count); if (buffers == NULL) return; for (i = 0; i < count; i++) { switch (buffers[i].attachment) { case __DRI_BUFFER_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 front buffer"; break; case __DRI_BUFFER_FAKE_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 fake front buffer"; break; case __DRI_BUFFER_BACK_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); region_name = "dri2 back buffer"; break; case __DRI_BUFFER_DEPTH: case __DRI_BUFFER_HIZ: case __DRI_BUFFER_DEPTH_STENCIL: case __DRI_BUFFER_STENCIL: case __DRI_BUFFER_ACCUM: default: fprintf(stderr, "unhandled buffer attach event, attachment type %d\n", buffers[i].attachment); return; } intel_process_dri2_buffer(intel, drawable, &buffers[i], rb, region_name); } }
bool intel_framebuffer_has_hiz(struct gl_framebuffer *fb) { struct intel_renderbuffer *rb = NULL; if (fb) rb = intel_get_renderbuffer(fb, BUFFER_DEPTH); return rb && rb->mt && rb->mt->hiz_mt; }
struct intel_region* intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex) { struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex); if (irb && irb->mt) return irb->mt->region; else return NULL; }
/** * \brief Call this after drawing to mark which buffers need resolving * * If the depth buffer was written to and if it has an accompanying HiZ * buffer, then mark that it needs a depth resolve. * * If the color buffer is a multisample window system buffer, then * mark that it needs a downsample. */ static void brw_postdraw_set_buffers_need_resolve(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *front_irb = NULL; struct intel_renderbuffer *back_irb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); if (brw->is_front_buffer_rendering) front_irb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); if (front_irb) intel_renderbuffer_set_needs_downsample(front_irb); if (back_irb) intel_renderbuffer_set_needs_downsample(back_irb); if (depth_irb && ctx->Depth.Mask) intel_renderbuffer_set_needs_depth_resolve(depth_irb); }
void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct gl_framebuffer *fb = dPriv->driverPrivate; struct intel_context *intel = pDRICtx->driverPrivate; struct gl_context *ctx = &intel->ctx; struct intel_texture_object *intelObj; struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; int level = 0, internalFormat = 0; gl_format texFormat = MESA_FORMAT_NONE; texObj = _mesa_get_current_tex_object(ctx, target); intelObj = intel_texture_object(texObj); if (!intelObj) return; if (dPriv->lastStamp != dPriv->dri2.stamp || !pDRICtx->driScreenPriv->dri2.useInvalidate) intel_update_renderbuffers(pDRICtx, dPriv); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the region isn't set, then intel_update_renderbuffers was unable * to get the buffers for the drawable. */ if (!rb || !rb->mt) return; if (rb->mt->cpp == 4) { if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_XRGB8888; } else { internalFormat = GL_RGBA; texFormat = MESA_FORMAT_ARGB8888; } } else if (rb->mt->cpp == 2) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_RGB565; } _mesa_lock_texture(&intel->ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, level); intel_set_texture_image_region(ctx, texImage, rb->mt->region, target, internalFormat, texFormat, 0, rb->mt->region->width, rb->mt->region->height, 0, 0); _mesa_unlock_texture(&intel->ctx, texObj); }
void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct gl_framebuffer *fb = dPriv->driverPrivate; struct brw_context *brw = pDRICtx->driverPrivate; struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; int level = 0, internalFormat = 0; mesa_format texFormat = MESA_FORMAT_NONE; texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; if (dPriv->lastStamp != dPriv->dri2.stamp || !pDRICtx->driScreenPriv->dri2.useInvalidate) intel_update_renderbuffers(pDRICtx, dPriv); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the miptree isn't set, then intel_update_renderbuffers was unable * to get the BO for the drawable from the window system. */ if (!rb || !rb->mt) return; if (rb->mt->cpp == 4) { if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_B8G8R8X8_UNORM; } else { internalFormat = GL_RGBA; texFormat = MESA_FORMAT_B8G8R8A8_UNORM; } } else if (rb->mt->cpp == 2) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_B5G6R5_UNORM; } _mesa_lock_texture(&brw->ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, level); intel_miptree_make_shareable(brw, rb->mt); intel_set_texture_image_bo(ctx, texImage, rb->mt->bo, target, internalFormat, texFormat, 0, rb->Base.Base.Width, rb->Base.Base.Height, rb->mt->pitch, 0, 0, 0); _mesa_unlock_texture(&brw->ctx, texObj); }
/** * \brief Call this after drawing to mark which buffers need resolving * * If the depth buffer was written to and if it has an accompanying HiZ * buffer, then mark that it needs a depth resolve. * * If the color buffer is a multisample window system buffer, then * mark that it needs a downsample. * * Also mark any render targets which will be textured as needing a render * cache flush. */ static void brw_postdraw_set_buffers_need_resolve(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *front_irb = NULL; struct intel_renderbuffer *back_irb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct gl_renderbuffer_attachment *depth_att = &fb->Attachment[BUFFER_DEPTH]; if (_mesa_is_front_buffer_drawing(fb)) front_irb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); if (front_irb) front_irb->need_downsample = true; if (back_irb) back_irb->need_downsample = true; if (depth_irb && ctx->Depth.Mask) { intel_renderbuffer_att_set_needs_depth_resolve(depth_att); brw_render_cache_set_add_bo(brw, depth_irb->mt->bo); } if (ctx->Extensions.ARB_stencil_texturing && stencil_irb && ctx->Stencil._WriteEnabled) { brw_render_cache_set_add_bo(brw, stencil_irb->mt->bo); } for (unsigned i = 0; i < fb->_NumColorDrawBuffers; i++) { struct intel_renderbuffer *irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]); if (irb) { brw_render_cache_set_add_bo(brw, irb->mt->bo); if (intel_miptree_is_lossless_compressed(brw, irb->mt)) { irb->mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_UNRESOLVED; } } } }
/** * \brief Call this after drawing to mark which buffers need resolving * * If the depth buffer was written to and if it has an accompanying HiZ * buffer, then mark that it needs a depth resolve. * * (In the future, this will also mark needed MSAA resolves). */ static void brw_postdraw_set_buffers_need_resolve(struct brw_context *brw) { struct gl_context *ctx = &brw->intel.ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); if (depth_irb && ctx->Depth.Mask) { intel_renderbuffer_set_needs_depth_resolve(depth_irb); } }
/** * Get the intel_region which is the source for any glCopyTex[Sub]Image call. * * Do the best we can using the blitter. A future project is to use * the texture engine and fragment programs for these copies. */ static struct intel_renderbuffer * get_teximage_readbuffer(struct intel_context *intel, GLenum internalFormat) { DBG("%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat)); if (_mesa_is_depth_format(internalFormat) || _mesa_is_depthstencil_format(internalFormat)) return intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH); return intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer); }
struct intel_region* intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex) { struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex); if (irb && irb->mt) { if (attIndex == BUFFER_STENCIL && irb->mt->stencil_mt) return irb->mt->stencil_mt->region; else return irb->mt->region; } else return NULL; }
uint32_t brw_depthbuffer_format(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb; if (!drb && (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) && !srb->mt->stencil_mt && (intel_rb_format(srb) == MESA_FORMAT_Z24_UNORM_S8_UINT || intel_rb_format(srb) == MESA_FORMAT_Z32_FLOAT_S8X24_UINT)) { drb = srb; } if (!drb) return BRW_DEPTHFORMAT_D32_FLOAT; return brw_depth_format(brw, drb->mt->format); }
/** * \brief Query DRI2 to obtain a DRIdrawable's buffers. * * To determine which DRI buffers to request, examine the renderbuffers * attached to the drawable's framebuffer. Then request the buffers with * DRI2GetBuffers() or DRI2GetBuffersWithFormat(). * * This is called from intel_update_renderbuffers(). * * \param drawable Drawable whose buffers are queried. * \param buffers [out] List of buffers returned by DRI2 query. * \param buffer_count [out] Number of buffers returned. * * \see intel_update_renderbuffers() * \see DRI2GetBuffers() * \see DRI2GetBuffersWithFormat() */ static void intel_query_dri2_buffers(struct intel_context *intel, __DRIdrawable *drawable, __DRIbuffer **buffers, int *buffer_count) { __DRIscreen *screen = intel->intelScreen->driScrnPriv; struct gl_framebuffer *fb = drawable->driverPrivate; int i = 0; const int max_attachments = 4; unsigned *attachments = calloc(2 * max_attachments, sizeof(unsigned)); struct intel_renderbuffer *front_rb; struct intel_renderbuffer *back_rb; front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); if ((intel->is_front_buffer_rendering || intel->is_front_buffer_reading || !back_rb) && front_rb) { attachments[i++] = __DRI_BUFFER_FRONT_LEFT; attachments[i++] = intel_bits_per_pixel(front_rb); } if (back_rb) { attachments[i++] = __DRI_BUFFER_BACK_LEFT; attachments[i++] = intel_bits_per_pixel(back_rb); } assert(i <= 2 * max_attachments); *buffers = screen->dri2.loader->getBuffersWithFormat(drawable, &drawable->w, &drawable->h, attachments, i / 2, buffer_count, drawable->loaderPrivate); free(attachments); }
/** * Do additional "completeness" testing of a framebuffer object. */ static void intel_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) { const struct intel_renderbuffer *depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); const struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); int i; if (stencilRb && stencilRb != depthRb) { /* we only support combined depth/stencil buffers, not separate * stencil buffers. */ fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[i]; struct intel_renderbuffer *irb = intel_renderbuffer(rb); if (rb == NULL) continue; if (irb == NULL) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; continue; } switch (irb->Base.Format) { case MESA_FORMAT_ARGB8888: case MESA_FORMAT_XRGB8888: case MESA_FORMAT_RGB565: case MESA_FORMAT_ARGB1555: case MESA_FORMAT_ARGB4444: break; default: fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } }
uint32_t brw_depthbuffer_format(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *drb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *srb; if (!drb && (srb = intel_get_renderbuffer(fb, BUFFER_STENCIL)) && !srb->mt->stencil_mt && (srb->Base.Format == MESA_FORMAT_S8_Z24 || srb->Base.Format == MESA_FORMAT_Z32_FLOAT_X24S8)) { drb = srb; } if (!drb) return BRW_DEPTHFORMAT_D32_FLOAT; switch (drb->mt->format) { case MESA_FORMAT_Z16: return BRW_DEPTHFORMAT_D16_UNORM; case MESA_FORMAT_Z32_FLOAT: return BRW_DEPTHFORMAT_D32_FLOAT; case MESA_FORMAT_X8_Z24: if (intel->gen >= 5) return BRW_DEPTHFORMAT_D24_UNORM_X8_UINT; else /* Gen4 doesn't support X8; use S8 instead. */ return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; case MESA_FORMAT_S8_Z24: return BRW_DEPTHFORMAT_D24_UNORM_S8_UINT; case MESA_FORMAT_Z32_FLOAT_X24S8: return BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT; default: _mesa_problem(ctx, "Unexpected depth format %s\n", _mesa_get_format_name(drb->Base.Format)); return BRW_DEPTHFORMAT_D16_UNORM; } }
void brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { const struct gen_device_info *devinfo = &brw->screen->devinfo; struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct gl_program *prog = brw->programs[MESA_SHADER_FRAGMENT]; const struct brw_program *fp = brw_program_const(prog); GLuint lookup = 0; GLuint line_aa; memset(key, 0, sizeof(*key)); /* Build the index for table lookup */ if (devinfo->gen < 6) { struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH); /* _NEW_COLOR */ if (prog->info.fs.uses_discard || ctx->Color.AlphaEnabled) { lookup |= BRW_WM_IZ_PS_KILL_ALPHATEST_BIT; } if (prog->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { lookup |= BRW_WM_IZ_PS_COMPUTES_DEPTH_BIT; } /* _NEW_DEPTH */ if (depth_irb && ctx->Depth.Test) { lookup |= BRW_WM_IZ_DEPTH_TEST_ENABLE_BIT; if (brw_depth_writes_enabled(brw)) lookup |= BRW_WM_IZ_DEPTH_WRITE_ENABLE_BIT; } /* _NEW_STENCIL | _NEW_BUFFERS */ if (brw->stencil_enabled) { lookup |= BRW_WM_IZ_STENCIL_TEST_ENABLE_BIT; if (ctx->Stencil.WriteMask[0] || ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) lookup |= BRW_WM_IZ_STENCIL_WRITE_ENABLE_BIT; } key->iz_lookup = lookup; } line_aa = BRW_WM_AA_NEVER; /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ if (ctx->Line.SmoothFlag) { if (brw->reduced_primitive == GL_LINES) { line_aa = BRW_WM_AA_ALWAYS; } else if (brw->reduced_primitive == GL_TRIANGLES) { if (ctx->Polygon.FrontMode == GL_LINE) { line_aa = BRW_WM_AA_SOMETIMES; if (ctx->Polygon.BackMode == GL_LINE || (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_BACK)) line_aa = BRW_WM_AA_ALWAYS; } else if (ctx->Polygon.BackMode == GL_LINE) { line_aa = BRW_WM_AA_SOMETIMES; if ((ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT)) line_aa = BRW_WM_AA_ALWAYS; } } } key->line_aa = line_aa; /* _NEW_HINT */ key->high_quality_derivatives = prog->info.uses_fddx_fddy && ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (devinfo->gen < 6) key->stats_wm = brw->stats_wm; /* _NEW_LIGHT */ key->flat_shade = (prog->info.inputs_read & (VARYING_BIT_COL0 | VARYING_BIT_COL1)) && (ctx->Light.ShadeModel == GL_FLAT); /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ key->clamp_fragment_color = ctx->Color._ClampFragmentColor; /* _NEW_TEXTURE */ brw_populate_sampler_prog_key_data(ctx, prog, &key->tex); /* _NEW_BUFFERS */ key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; /* _NEW_COLOR */ key->force_dual_color_blend = brw->dual_color_blend_by_location && (ctx->Color.BlendEnabled & 1) && ctx->Color.Blend[0]._UsesDualSrc; /* _NEW_MULTISAMPLE, _NEW_BUFFERS */ key->alpha_to_coverage = _mesa_is_alpha_to_coverage_enabled(ctx); /* _NEW_COLOR, _NEW_BUFFERS */ key->alpha_test_replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && _mesa_is_alpha_test_enabled(ctx); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ /* Ignore sample qualifier while computing this flag. */ if (ctx->Multisample.Enabled) { key->persample_interp = ctx->Multisample.SampleShading && (ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer) > 1); key->multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; } /* BRW_NEW_VUE_MAP_GEOM_OUT */ if (devinfo->gen < 6 || util_bitcount64(prog->info.inputs_read & BRW_FS_VARYING_INPUT_MASK) > 16) { key->input_slots_valid = brw->vue_map_geom_out.slots_valid; } /* _NEW_COLOR | _NEW_BUFFERS */ /* Pre-gen6, the hardware alpha test always used each render * target's alpha to do alpha test, as opposed to render target 0's alpha * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ if (devinfo->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } /* The unique fragment program ID */ key->program_string_id = fp->id; /* Whether reads from the framebuffer should behave coherently. */ key->coherent_fb_fetch = ctx->Extensions.EXT_shader_framebuffer_fetch; }
/** * Implements fast depth clears on gen6+. * * Fast clears basically work by setting a flag in each of the subspans * represented in the HiZ buffer that says "When you need the depth values for * this subspan, it's the hardware's current clear value." Then later rendering * can just use the static clear value instead of referencing memory. * * The tricky part of the implementation is that you have to have the clear * value that was used on the depth buffer in place for all further rendering, * at least until a resolve to the real depth buffer happens. */ static bool brw_fast_clear_depth(struct gl_context *ctx) { struct intel_context *intel = intel_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_mipmap_tree *mt = depth_irb->mt; if (intel->gen < 6) return false; if (!mt->hiz_mt) return false; /* We only handle full buffer clears -- otherwise you'd have to track whether * a previous clear had happened at a different clear value and resolve it * first. */ if (ctx->Scissor.Enabled && !noop_scissor(ctx, fb)) { perf_debug("Failed to fast clear depth due to scissor being enabled. " "Possible 5%% performance win if avoided.\n"); return false; } /* The rendered area has to be 8x4 samples, not resolved pixels, so we look * at the miptree slice dimensions instead of renderbuffer size. */ if (mt->level[depth_irb->mt_level].width % 8 != 0 || mt->level[depth_irb->mt_level].height % 4 != 0) { perf_debug("Failed to fast clear depth due to width/height %d,%d not " "being aligned to 8,4. Possible 5%% performance win if " "avoided\n", mt->level[depth_irb->mt_level].width, mt->level[depth_irb->mt_level].height); return false; } uint32_t depth_clear_value; switch (mt->format) { case MESA_FORMAT_Z32_FLOAT_X24S8: case MESA_FORMAT_S8_Z24: /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be * enabled (the legacy method of clearing must be performed): * * - If the depth buffer format is D32_FLOAT_S8X24_UINT or * D24_UNORM_S8_UINT. */ return false; case MESA_FORMAT_Z32_FLOAT: depth_clear_value = float_as_int(ctx->Depth.Clear); break; case MESA_FORMAT_Z16: /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be * enabled (the legacy method of clearing must be performed): * * - DevSNB{W/A}]: When depth buffer format is D16_UNORM and the * width of the map (LOD0) is not multiple of 16, fast clear * optimization must be disabled. */ if (intel->gen == 6 && (mt->level[depth_irb->mt_level].width % 16) != 0) return false; /* FALLTHROUGH */ default: depth_clear_value = fb->_DepthMax * ctx->Depth.Clear; break; } /* If we're clearing to a new clear value, then we need to resolve any clear * flags out of the HiZ buffer into the real depth buffer. */ if (mt->depth_clear_value != depth_clear_value) { intel_miptree_all_slices_resolve_depth(intel, mt); mt->depth_clear_value = depth_clear_value; } /* From the Sandy Bridge PRM, volume 2 part 1, page 313: * * "If other rendering operations have preceded this clear, a * PIPE_CONTROL with write cache flush enabled and Z-inhibit disabled * must be issued before the rectangle primitive used for the depth * buffer clear operation. */ intel_batchbuffer_emit_mi_flush(intel); intel_hiz_exec(intel, mt, depth_irb->mt_level, depth_irb->mt_layer, GEN6_HIZ_OP_DEPTH_CLEAR); if (intel->gen == 6) { /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "DevSNB, DevSNB-B{W/A}]: Depth buffer clear pass must be followed * by a PIPE_CONTROL command with DEPTH_STALL bit set and Then * followed by Depth FLUSH' */ intel_batchbuffer_emit_mi_flush(intel); } /* Now, the HiZ buffer contains data that needs to be resolved to the depth * buffer. */ intel_renderbuffer_set_needs_depth_resolve(depth_irb); return true; }
void gen7_emit_depth_stencil_hiz(struct brw_context *brw, struct intel_mipmap_tree *depth_mt, uint32_t depth_offset, uint32_t depthbuffer_format, uint32_t depth_surface_type, struct intel_mipmap_tree *stencil_mt, bool hiz, bool separate_stencil, uint32_t width, uint32_t height, uint32_t tile_x, uint32_t tile_y) { struct gl_context *ctx = &brw->ctx; const uint8_t mocs = GEN7_MOCS_L3; struct gl_framebuffer *fb = ctx->DrawBuffer; uint32_t surftype; unsigned int depth = 1; unsigned int min_array_element; GLenum gl_target = GL_TEXTURE_2D; unsigned int lod; const struct intel_mipmap_tree *mt = depth_mt ? depth_mt : stencil_mt; const struct intel_renderbuffer *irb = NULL; const struct gl_renderbuffer *rb = NULL; intel_emit_depth_stall_flushes(brw); irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); if (!irb) irb = intel_get_renderbuffer(fb, BUFFER_STENCIL); rb = (struct gl_renderbuffer*) irb; if (rb) { depth = MAX2(rb->Depth, 1); if (rb->TexImage) gl_target = rb->TexImage->TexObject->Target; } switch (gl_target) { case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_CUBE_MAP: /* The PRM claims that we should use BRW_SURFACE_CUBE for this * situation, but experiments show that gl_Layer doesn't work when we do * this. So we use BRW_SURFACE_2D, since for rendering purposes this is * equivalent. */ surftype = BRW_SURFACE_2D; depth *= 6; break; default: surftype = translate_tex_target(gl_target); break; } if (fb->Layered || !irb) { min_array_element = 0; } else if (irb->mt->num_samples > 1) { /* Convert physical layer to logical layer. */ min_array_element = irb->mt_layer / irb->mt->num_samples; } else { min_array_element = irb->mt_layer; } lod = irb ? irb->mt_level - irb->mt->first_level : 0; if (mt) { width = mt->physical_width0; height = mt->physical_height0; } /* _NEW_DEPTH, _NEW_STENCIL, _NEW_BUFFERS */ BEGIN_BATCH(7); /* 3DSTATE_DEPTH_BUFFER dw0 */ OUT_BATCH(GEN7_3DSTATE_DEPTH_BUFFER << 16 | (7 - 2)); /* 3DSTATE_DEPTH_BUFFER dw1 */ OUT_BATCH((depth_mt ? depth_mt->region->pitch - 1 : 0) | (depthbuffer_format << 18) | ((hiz ? 1 : 0) << 22) | ((stencil_mt != NULL && ctx->Stencil._WriteEnabled) << 27) | ((ctx->Depth.Mask != 0) << 28) | (surftype << 29)); /* 3DSTATE_DEPTH_BUFFER dw2 */ if (depth_mt) { OUT_RELOC(depth_mt->region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); } else { OUT_BATCH(0); } /* 3DSTATE_DEPTH_BUFFER dw3 */ OUT_BATCH(((width - 1) << 4) | ((height - 1) << 18) | lod); /* 3DSTATE_DEPTH_BUFFER dw4 */ OUT_BATCH(((depth - 1) << 21) | (min_array_element << 10) | mocs); /* 3DSTATE_DEPTH_BUFFER dw5 */ OUT_BATCH(0); /* 3DSTATE_DEPTH_BUFFER dw6 */ OUT_BATCH((depth - 1) << 21); ADVANCE_BATCH(); if (!hiz) { BEGIN_BATCH(3); OUT_BATCH(GEN7_3DSTATE_HIER_DEPTH_BUFFER << 16 | (3 - 2)); OUT_BATCH(0); OUT_BATCH(0); ADVANCE_BATCH(); } else { struct intel_mipmap_tree *hiz_mt = depth_mt->hiz_mt; BEGIN_BATCH(3); OUT_BATCH(GEN7_3DSTATE_HIER_DEPTH_BUFFER << 16 | (3 - 2)); OUT_BATCH((mocs << 25) | (hiz_mt->region->pitch - 1)); OUT_RELOC(hiz_mt->region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); ADVANCE_BATCH(); } if (stencil_mt == NULL) { BEGIN_BATCH(3); OUT_BATCH(GEN7_3DSTATE_STENCIL_BUFFER << 16 | (3 - 2)); OUT_BATCH(0); OUT_BATCH(0); ADVANCE_BATCH(); } else { const int enabled = brw->is_haswell ? HSW_STENCIL_ENABLED : 0; BEGIN_BATCH(3); OUT_BATCH(GEN7_3DSTATE_STENCIL_BUFFER << 16 | (3 - 2)); /* The stencil buffer has quirky pitch requirements. From the * Sandybridge PRM, Volume 2 Part 1, page 329 (3DSTATE_STENCIL_BUFFER * dword 1 bits 16:0 - Surface Pitch): * * The pitch must be set to 2x the value computed based on width, as * the stencil buffer is stored with two rows interleaved. * * While the Ivybridge PRM lacks this comment, the BSpec contains the * same text, and experiments indicate that this is necessary. */ OUT_BATCH(enabled | mocs << 25 | (2 * stencil_mt->region->pitch - 1)); OUT_RELOC(stencil_mt->region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); ADVANCE_BATCH(); } BEGIN_BATCH(3); OUT_BATCH(GEN7_3DSTATE_CLEAR_PARAMS << 16 | (3 - 2)); OUT_BATCH(depth_mt ? depth_mt->depth_clear_value : 0); OUT_BATCH(1); ADVANCE_BATCH(); }
void intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) { struct gl_framebuffer *fb = drawable->driverPrivate; struct intel_renderbuffer *rb; struct intel_region *region, *depth_region; struct intel_context *intel = context->driverPrivate; struct intel_renderbuffer *front_rb, *back_rb, *depth_rb, *stencil_rb; __DRIbuffer *buffers = NULL; __DRIscreen *screen; int i, count; unsigned int attachments[10]; const char *region_name; /* If we're rendering to the fake front buffer, make sure all the * pending drawing has landed on the real front buffer. Otherwise * when we eventually get to DRI2GetBuffersWithFormat the stale * real front buffer contents will get copied to the new fake front * buffer. */ if (intel->is_front_buffer_rendering) intel_flush(&intel->ctx, GL_FALSE); /* Set this up front, so that in case our buffers get invalidated * while we're getting new buffers, we don't clobber the stamp and * thus ignore the invalidate. */ drawable->lastStamp = drawable->dri2.stamp; if (INTEL_DEBUG & DEBUG_DRI) fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable); screen = intel->intelScreen->driScrnPriv; if (screen->dri2.loader && (screen->dri2.loader->base.version > 2) && (screen->dri2.loader->getBuffersWithFormat != NULL)) { front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); depth_rb = intel_get_renderbuffer(fb, BUFFER_DEPTH); stencil_rb = intel_get_renderbuffer(fb, BUFFER_STENCIL); i = 0; if ((intel->is_front_buffer_rendering || intel->is_front_buffer_reading || !back_rb) && front_rb) { attachments[i++] = __DRI_BUFFER_FRONT_LEFT; attachments[i++] = intel_bits_per_pixel(front_rb); } if (back_rb) { attachments[i++] = __DRI_BUFFER_BACK_LEFT; attachments[i++] = intel_bits_per_pixel(back_rb); } if ((depth_rb != NULL) && (stencil_rb != NULL)) { attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL; attachments[i++] = intel_bits_per_pixel(depth_rb); } else if (depth_rb != NULL) { attachments[i++] = __DRI_BUFFER_DEPTH; attachments[i++] = intel_bits_per_pixel(depth_rb); } else if (stencil_rb != NULL) { attachments[i++] = __DRI_BUFFER_STENCIL; attachments[i++] = intel_bits_per_pixel(stencil_rb); } buffers = (*screen->dri2.loader->getBuffersWithFormat)(drawable, &drawable->w, &drawable->h, attachments, i / 2, &count, drawable->loaderPrivate); } else if (screen->dri2.loader) { i = 0; if (intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT)) attachments[i++] = __DRI_BUFFER_FRONT_LEFT; if (intel_get_renderbuffer(fb, BUFFER_BACK_LEFT)) attachments[i++] = __DRI_BUFFER_BACK_LEFT; if (intel_get_renderbuffer(fb, BUFFER_DEPTH)) attachments[i++] = __DRI_BUFFER_DEPTH; if (intel_get_renderbuffer(fb, BUFFER_STENCIL)) attachments[i++] = __DRI_BUFFER_STENCIL; buffers = (*screen->dri2.loader->getBuffers)(drawable, &drawable->w, &drawable->h, attachments, i, &count, drawable->loaderPrivate); } if (buffers == NULL) return; drawable->x = 0; drawable->y = 0; drawable->backX = 0; drawable->backY = 0; drawable->numClipRects = 1; drawable->pClipRects[0].x1 = 0; drawable->pClipRects[0].y1 = 0; drawable->pClipRects[0].x2 = drawable->w; drawable->pClipRects[0].y2 = drawable->h; drawable->numBackClipRects = 1; drawable->pBackClipRects[0].x1 = 0; drawable->pBackClipRects[0].y1 = 0; drawable->pBackClipRects[0].x2 = drawable->w; drawable->pBackClipRects[0].y2 = drawable->h; depth_region = NULL; for (i = 0; i < count; i++) { switch (buffers[i].attachment) { case __DRI_BUFFER_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 front buffer"; break; case __DRI_BUFFER_FAKE_FRONT_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); region_name = "dri2 fake front buffer"; break; case __DRI_BUFFER_BACK_LEFT: rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT); region_name = "dri2 back buffer"; break; case __DRI_BUFFER_DEPTH: rb = intel_get_renderbuffer(fb, BUFFER_DEPTH); region_name = "dri2 depth buffer"; break; case __DRI_BUFFER_DEPTH_STENCIL: rb = intel_get_renderbuffer(fb, BUFFER_DEPTH); region_name = "dri2 depth / stencil buffer"; break; case __DRI_BUFFER_STENCIL: rb = intel_get_renderbuffer(fb, BUFFER_STENCIL); region_name = "dri2 stencil buffer"; break; case __DRI_BUFFER_ACCUM: default: fprintf(stderr, "unhandled buffer attach event, attacment type %d\n", buffers[i].attachment); return; } if (rb == NULL) continue; if (rb->region && rb->region->name == buffers[i].name) continue; if (INTEL_DEBUG & DEBUG_DRI) fprintf(stderr, "attaching buffer %d, at %d, cpp %d, pitch %d\n", buffers[i].name, buffers[i].attachment, buffers[i].cpp, buffers[i].pitch); if (buffers[i].attachment == __DRI_BUFFER_STENCIL && depth_region) { if (INTEL_DEBUG & DEBUG_DRI) fprintf(stderr, "(reusing depth buffer as stencil)\n"); intel_region_reference(®ion, depth_region); } else region = intel_region_alloc_for_handle(intel, buffers[i].cpp, drawable->w, drawable->h, buffers[i].pitch / buffers[i].cpp, buffers[i].name, region_name); if (buffers[i].attachment == __DRI_BUFFER_DEPTH) depth_region = region; intel_renderbuffer_set_region(intel, rb, region); intel_region_release(®ion); if (buffers[i].attachment == __DRI_BUFFER_DEPTH_STENCIL) { rb = intel_get_renderbuffer(fb, BUFFER_STENCIL); if (rb != NULL) { struct intel_region *stencil_region = NULL; if (rb->region && rb->region->name == buffers[i].name) continue; intel_region_reference(&stencil_region, region); intel_renderbuffer_set_region(intel, rb, stencil_region); intel_region_release(&stencil_region); } } } driUpdateFramebufferSize(&intel->ctx, drawable); }
/** * 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; }