+
+/**
+ * \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(). It is used only if either
+ * the hardware or the X driver lacks separate stencil support.
+ *
+ * \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_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer **buffers,
+ int *buffer_count)
+{
+ assert(!intel->must_use_separate_stencil);
+
+ __DRIscreen *screen = intel->intelScreen->driScrnPriv;
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+
+ if (screen->dri2.loader
+ && screen->dri2.loader->base.version > 2
+ && screen->dri2.loader->getBuffersWithFormat != NULL) {
+
+ 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;
+ struct intel_renderbuffer *depth_rb;
+ struct intel_renderbuffer *stencil_rb;
+
+ 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);
+
+ 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 && stencil_rb) {
+ attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL;
+ attachments[i++] = intel_bits_per_pixel(depth_rb);
+ } else if (depth_rb) {
+ attachments[i++] = __DRI_BUFFER_DEPTH;
+ attachments[i++] = intel_bits_per_pixel(depth_rb);
+ } else if (stencil_rb) {
+ attachments[i++] = __DRI_BUFFER_STENCIL;
+ attachments[i++] = intel_bits_per_pixel(stencil_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);
+
+ } else if (screen->dri2.loader) {
+
+ int i = 0;
+ const int max_attachments = 4;
+ unsigned *attachments = calloc(max_attachments, sizeof(unsigned));
+
+ 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;
+
+ assert(i <= max_attachments);
+
+ *buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
+ &drawable->w,
+ &drawable->h,
+ attachments, i,
+ buffer_count,
+ drawable->loaderPrivate);
+ free(attachments);
+
+ } else {
+ *buffers = NULL;
+ *buffer_count = 0;
+ }
+}
+
+/**
+ * \brief Assign a DRI buffer's DRM region to a renderbuffer.
+ *
+ * This is called from intel_update_renderbuffers(). It is used only if
+ * either the hardware or the X driver lacks separate stencil support.
+ *
+ * \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()
+ * \see intel_renderbuffer_set_region()
+ */
+static void
+intel_process_dri2_buffer_no_separate_stencil(struct intel_context *intel,
+ __DRIdrawable *drawable,
+ __DRIbuffer *buffer,
+ struct intel_renderbuffer *rb,
+ const char *buffer_name)
+{
+ assert(!intel->must_use_separate_stencil);
+
+ struct gl_framebuffer *fb = drawable->driverPrivate;
+ struct intel_region *region = NULL;
+ struct intel_renderbuffer *depth_rb = NULL;
+
+ if (!rb)
+ return;
+
+ if (rb->region && rb->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);
+ }
+
+ bool identify_depth_and_stencil = false;
+ if (buffer->attachment == __DRI_BUFFER_STENCIL) {
+ struct intel_renderbuffer *depth_rb =
+ intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ identify_depth_and_stencil = depth_rb && depth_rb->region;
+ }
+
+ if (identify_depth_and_stencil) {
+ if (unlikely(INTEL_DEBUG & DEBUG_DRI)) {
+ fprintf(stderr, "(reusing depth buffer as stencil)\n");
+ }
+ intel_region_reference(®ion, depth_rb->region);
+ } else {
+ region = intel_region_alloc_for_handle(intel->intelScreen,
+ buffer->cpp,
+ drawable->w,
+ drawable->h,
+ buffer->pitch / buffer->cpp,
+ buffer->name,
+ buffer_name);
+ }
+
+ intel_renderbuffer_set_region(intel, rb, region);
+ intel_region_release(®ion);
+
+ if (buffer->attachment == __DRI_BUFFER_DEPTH_STENCIL) {
+ struct intel_renderbuffer *stencil_rb =
+ intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if (!stencil_rb)
+ return;
+
+ if (stencil_rb->region && stencil_rb->region->name == buffer->name)
+ return;
+
+ intel_renderbuffer_set_region(intel, stencil_rb, region);
+ }
+}