/** * \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_drawing(fb) || brw_is_front_buffer_reading(fb) || !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_batchbuffer_flush(brw); 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_batchbuffer_flush(brw); 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); }
static void intel_glFlush(struct gl_context *ctx) { struct brw_context *brw = brw_context(ctx); intel_batchbuffer_flush(brw); intel_flush_front(ctx); if (brw_is_front_buffer_drawing(ctx->DrawBuffer)) brw->need_throttle = true; }
static void intel_update_image_buffers(struct brw_context *brw, __DRIdrawable *drawable) { struct gl_framebuffer *fb = drawable->driverPrivate; __DRIscreen *screen = brw->intelScreen->driScrnPriv; struct intel_renderbuffer *front_rb; struct intel_renderbuffer *back_rb; struct __DRIimageList images; unsigned int format; uint32_t buffer_mask = 0; 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 && (brw_is_front_buffer_drawing(fb) || brw_is_front_buffer_reading(fb) || !back_rb)) { buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; } if (back_rb) buffer_mask |= __DRI_IMAGE_BUFFER_BACK; (*screen->image.loader->getBuffers) (drawable, driGLFormatToImageFormat(format), &drawable->dri2.stamp, drawable->loaderPrivate, buffer_mask, &images); if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { drawable->w = images.front->width; drawable->h = images.front->height; intel_update_image_buffer(brw, 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(brw, drawable, back_rb, images.back, __DRI_IMAGE_BUFFER_BACK); } }
static void intelDrawBuffer(struct gl_context * ctx, GLenum mode) { if (brw_is_front_buffer_drawing(ctx->DrawBuffer)) { struct brw_context *const brw = brw_context(ctx); /* If we might be front-buffer rendering on this buffer for the first * time, invalidate our DRI drawable so we'll ask for new buffers * (including the fake front) before we start rendering again. */ dri2InvalidateDrawable(brw->driContext->driDrawablePriv); } }
/** * intel_prepare_render should be called anywhere that curent read/drawbuffer * state is required. */ void intel_prepare_render(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; __DRIcontext *driContext = brw->driContext; __DRIdrawable *drawable; drawable = driContext->driDrawablePriv; if (drawable && drawable->dri2.stamp != driContext->dri2.draw_stamp) { if (drawable->lastStamp != drawable->dri2.stamp) intel_update_renderbuffers(driContext, drawable); driContext->dri2.draw_stamp = drawable->dri2.stamp; } drawable = driContext->driReadablePriv; if (drawable && drawable->dri2.stamp != driContext->dri2.read_stamp) { if (drawable->lastStamp != drawable->dri2.stamp) intel_update_renderbuffers(driContext, drawable); driContext->dri2.read_stamp = drawable->dri2.stamp; } /* If we're currently rendering to the front buffer, the rendering * that will happen next will probably dirty the front buffer. So * mark it as dirty here. */ if (brw_is_front_buffer_drawing(ctx->DrawBuffer)) brw->front_buffer_dirty = true; /* Wait for the swapbuffers before the one we just emitted, so we * don't get too many swaps outstanding for apps that are GPU-heavy * but not CPU-heavy. * * We're using intelDRI2Flush (called from the loader before * swapbuffer) and glFlush (for front buffer rendering) as the * indicator that a frame is done and then throttle when we get * here as we prepare to render the next frame. At this point for * round trips for swap/copy and getting new buffers are done and * we'll spend less time waiting on the GPU. * * Unfortunately, we don't have a handle to the batch containing * the swap, and getting our hands on that doesn't seem worth it, * so we just us the first batch we emitted after the last swap. */ if (brw->need_throttle && brw->first_post_swapbuffers_batch) { if (!brw->disable_throttling) drm_intel_bo_wait_rendering(brw->first_post_swapbuffers_batch); drm_intel_bo_unreference(brw->first_post_swapbuffers_batch); brw->first_post_swapbuffers_batch = NULL; brw->need_throttle = false; } }
static void intel_update_image_buffer(struct brw_context *intel, __DRIdrawable *drawable, struct intel_renderbuffer *rb, __DRIimage *buffer, enum __DRIimageBufferMask buffer_type) { struct intel_region *region = buffer->region; struct gl_framebuffer *fb = drawable->driverPrivate; if (!rb || !region) return; unsigned num_samples = rb->Base.Base.NumSamples; /* Check and see if we're already bound to the right * buffer object */ if (num_samples == 0) { if (rb->mt && rb->mt->region && rb->mt->region->bo == region->bo) return; } else { if (rb->singlesample_mt && rb->singlesample_mt->region && rb->singlesample_mt->region->bo == region->bo) return; } intel_update_winsys_renderbuffer_miptree(intel, rb, region); if (brw_is_front_buffer_drawing(fb) && buffer_type == __DRI_IMAGE_BUFFER_FRONT && rb->Base.Base.NumSamples > 1) { intel_renderbuffer_upsample(intel, rb); } }
/** * \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 (brw_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 (int 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); } }
static void intel_update_image_buffer(struct brw_context *intel, __DRIdrawable *drawable, struct intel_renderbuffer *rb, __DRIimage *buffer, enum __DRIimageBufferMask buffer_type) { struct gl_framebuffer *fb = drawable->driverPrivate; if (!rb || !buffer->bo) return; unsigned num_samples = rb->Base.Base.NumSamples; /* Check and see if we're already bound to the right * buffer object */ struct intel_mipmap_tree *last_mt; if (num_samples == 0) last_mt = rb->mt; else last_mt = rb->singlesample_mt; if (last_mt && last_mt->bo == buffer->bo) return; intel_update_winsys_renderbuffer_miptree(intel, rb, buffer->bo, buffer->width, buffer->height, buffer->pitch); if (brw_is_front_buffer_drawing(fb) && buffer_type == __DRI_IMAGE_BUFFER_FRONT && rb->Base.Base.NumSamples > 1) { intel_renderbuffer_upsample(intel, rb); } }
/** * \brief Assign a DRI buffer's DRM region to a renderbuffer. * * This is called from intel_update_renderbuffers(). * * \par Note: * DRI buffers whose attachment point is DRI2BufferStencil or * DRI2BufferDepthStencil are handled as special cases. * * \param buffer_name is a human readable name, such as "dri2 front buffer", * that is passed to drm_intel_bo_gem_create_from_name(). * * \see intel_update_renderbuffers() */ static void intel_process_dri2_buffer(struct brw_context *brw, __DRIdrawable *drawable, __DRIbuffer *buffer, struct intel_renderbuffer *rb, const char *buffer_name) { struct gl_framebuffer *fb = drawable->driverPrivate; drm_intel_bo *bo; if (!rb) return; unsigned num_samples = rb->Base.Base.NumSamples; /* We try to avoid closing and reopening the same BO name, because the first * use of a mapping of the buffer involves a bunch of page faulting which is * moderately expensive. */ struct intel_mipmap_tree *last_mt; if (num_samples == 0) last_mt = rb->mt; else last_mt = rb->singlesample_mt; uint32_t old_name = 0; if (last_mt) { /* The bo already has a name because the miptree was created by a * previous call to intel_process_dri2_buffer(). If a bo already has a * name, then drm_intel_bo_flink() is a low-cost getter. It does not * create a new name. */ drm_intel_bo_flink(last_mt->bo, &old_name); } if (old_name == buffer->name) return; if (unlikely(INTEL_DEBUG & DEBUG_DRI)) { fprintf(stderr, "attaching buffer %d, at %d, cpp %d, pitch %d\n", buffer->name, buffer->attachment, buffer->cpp, buffer->pitch); } intel_miptree_release(&rb->mt); bo = drm_intel_bo_gem_create_from_name(brw->bufmgr, buffer_name, buffer->name); if (!bo) { fprintf(stderr, "Failed to open BO for returned DRI2 buffer " "(%dx%d, %s, named %d).\n" "This is likely a bug in the X Server that will lead to a " "crash soon.\n", drawable->w, drawable->h, buffer_name, buffer->name); return; } intel_update_winsys_renderbuffer_miptree(brw, rb, bo, drawable->w, drawable->h, buffer->pitch); if (brw_is_front_buffer_drawing(fb) && (buffer->attachment == __DRI_BUFFER_FRONT_LEFT || buffer->attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) && rb->Base.Base.NumSamples > 1) { intel_renderbuffer_upsample(brw, rb); } assert(rb->mt); drm_intel_bo_unreference(bo); }
/** * \brief Assign a DRI buffer's DRM region to a renderbuffer. * * This is called from intel_update_renderbuffers(). * * \par Note: * DRI buffers whose attachment point is DRI2BufferStencil or * DRI2BufferDepthStencil are handled as special cases. * * \param buffer_name is a human readable name, such as "dri2 front buffer", * that is passed to intel_region_alloc_for_handle(). * * \see intel_update_renderbuffers() * \see intel_region_alloc_for_handle() */ static void intel_process_dri2_buffer(struct brw_context *brw, __DRIdrawable *drawable, __DRIbuffer *buffer, struct intel_renderbuffer *rb, const char *buffer_name) { struct intel_region *region = NULL; struct gl_framebuffer *fb = drawable->driverPrivate; if (!rb) return; unsigned num_samples = rb->Base.Base.NumSamples; /* We try to avoid closing and reopening the same BO name, because the first * use of a mapping of the buffer involves a bunch of page faulting which is * moderately expensive. */ if (num_samples == 0) { if (rb->mt && rb->mt->region && rb->mt->region->name == buffer->name) return; } else { if (rb->singlesample_mt && rb->singlesample_mt->region && rb->singlesample_mt->region->name == buffer->name) return; } if (unlikely(INTEL_DEBUG & DEBUG_DRI)) { fprintf(stderr, "attaching buffer %d, at %d, cpp %d, pitch %d\n", buffer->name, buffer->attachment, buffer->cpp, buffer->pitch); } intel_miptree_release(&rb->mt); region = intel_region_alloc_for_handle(brw->intelScreen, buffer->cpp, drawable->w, drawable->h, buffer->pitch, buffer->name, buffer_name); if (!region) { fprintf(stderr, "Failed to make region for returned DRI2 buffer " "(%dx%d, named %d).\n" "This is likely a bug in the X Server that will lead to a " "crash soon.\n", drawable->w, drawable->h, buffer->name); return; } intel_update_winsys_renderbuffer_miptree(brw, rb, region); if (brw_is_front_buffer_drawing(fb) && (buffer->attachment == __DRI_BUFFER_FRONT_LEFT || buffer->attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) && rb->Base.Base.NumSamples > 1) { intel_renderbuffer_upsample(brw, rb); } assert(rb->mt); intel_region_release(®ion); }