1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright 2009, VMware, Inc.
5 * All Rights Reserved.
6 * Copyright (C) 2010 LunarG Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 *    Keith Whitwell <keithw@vmware.com> Jakob Bornecrantz
28 *    <wallbraker@gmail.com> Chia-I Wu <olv@lunarg.com>
29 */
30
31#include <xf86drm.h>
32#include "GL/mesa_glinterop.h"
33#include "util/disk_cache.h"
34#include "util/u_memory.h"
35#include "util/u_inlines.h"
36#include "util/format/u_format.h"
37#include "util/u_debug.h"
38#include "util/libsync.h"
39#include "util/os_file.h"
40#include "frontend/drm_driver.h"
41#include "state_tracker/st_format.h"
42#include "state_tracker/st_cb_texture.h"
43#include "state_tracker/st_texture.h"
44#include "state_tracker/st_context.h"
45#include "pipe-loader/pipe_loader.h"
46#include "main/bufferobj.h"
47#include "main/texobj.h"
48
49#include "dri_util.h"
50
51#include "dri_helpers.h"
52#include "dri_drawable.h"
53#include "dri_query_renderer.h"
54
55#include "drm-uapi/drm_fourcc.h"
56
57struct dri2_buffer
58{
59   __DRIbuffer base;
60   struct pipe_resource *resource;
61};
62
63static inline struct dri2_buffer *
64dri2_buffer(__DRIbuffer * driBufferPriv)
65{
66   return (struct dri2_buffer *) driBufferPriv;
67}
68
69/**
70 * DRI2 flush extension.
71 */
72static void
73dri2_flush_drawable(__DRIdrawable *dPriv)
74{
75   dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1);
76}
77
78static void
79dri2_invalidate_drawable(__DRIdrawable *dPriv)
80{
81   struct dri_drawable *drawable = dri_drawable(dPriv);
82
83   dPriv->dri2.stamp++;
84   drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
85   drawable->texture_mask = 0;
86
87   p_atomic_inc(&drawable->base.stamp);
88}
89
90static const __DRI2flushExtension dri2FlushExtension = {
91    .base = { __DRI2_FLUSH, 4 },
92
93    .flush                = dri2_flush_drawable,
94    .invalidate           = dri2_invalidate_drawable,
95    .flush_with_flags     = dri_flush,
96};
97
98/**
99 * Retrieve __DRIbuffer from the DRI loader.
100 */
101static __DRIbuffer *
102dri2_drawable_get_buffers(struct dri_drawable *drawable,
103                          const enum st_attachment_type *atts,
104                          unsigned *count)
105{
106   __DRIdrawable *dri_drawable = drawable->dPriv;
107   const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
108   boolean with_format;
109   __DRIbuffer *buffers;
110   int num_buffers;
111   unsigned attachments[__DRI_BUFFER_COUNT];
112   unsigned num_attachments, i;
113
114   assert(loader);
115   assert(*count <= __DRI_BUFFER_COUNT);
116   with_format = dri_with_format(drawable->sPriv);
117
118   num_attachments = 0;
119
120   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
121   if (!with_format)
122      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
123
124   for (i = 0; i < *count; i++) {
125      enum pipe_format format;
126      unsigned bind;
127      int att, depth;
128
129      dri_drawable_get_format(drawable, atts[i], &format, &bind);
130      if (format == PIPE_FORMAT_NONE)
131         continue;
132
133      switch (atts[i]) {
134      case ST_ATTACHMENT_FRONT_LEFT:
135         /* already added */
136         if (!with_format)
137            continue;
138         att = __DRI_BUFFER_FRONT_LEFT;
139         break;
140      case ST_ATTACHMENT_BACK_LEFT:
141         att = __DRI_BUFFER_BACK_LEFT;
142         break;
143      case ST_ATTACHMENT_FRONT_RIGHT:
144         att = __DRI_BUFFER_FRONT_RIGHT;
145         break;
146      case ST_ATTACHMENT_BACK_RIGHT:
147         att = __DRI_BUFFER_BACK_RIGHT;
148         break;
149      default:
150         continue;
151      }
152
153      /*
154       * In this switch statement we must support all formats that
155       * may occur as the stvis->color_format.
156       */
157      switch(format) {
158      case PIPE_FORMAT_R16G16B16A16_FLOAT:
159         depth = 64;
160         break;
161      case PIPE_FORMAT_R16G16B16X16_FLOAT:
162         depth = 48;
163         break;
164      case PIPE_FORMAT_B10G10R10A2_UNORM:
165      case PIPE_FORMAT_R10G10B10A2_UNORM:
166      case PIPE_FORMAT_BGRA8888_UNORM:
167      case PIPE_FORMAT_RGBA8888_UNORM:
168	 depth = 32;
169	 break;
170      case PIPE_FORMAT_R10G10B10X2_UNORM:
171      case PIPE_FORMAT_B10G10R10X2_UNORM:
172         depth = 30;
173         break;
174      case PIPE_FORMAT_BGRX8888_UNORM:
175      case PIPE_FORMAT_RGBX8888_UNORM:
176	 depth = 24;
177	 break;
178      case PIPE_FORMAT_B5G6R5_UNORM:
179	 depth = 16;
180	 break;
181      default:
182	 depth = util_format_get_blocksizebits(format);
183	 assert(!"Unexpected format in dri2_drawable_get_buffers()");
184      }
185
186      attachments[num_attachments++] = att;
187      if (with_format) {
188         attachments[num_attachments++] = depth;
189      }
190   }
191
192   if (with_format) {
193      num_attachments /= 2;
194      buffers = loader->getBuffersWithFormat(dri_drawable,
195            &dri_drawable->w, &dri_drawable->h,
196            attachments, num_attachments,
197            &num_buffers, dri_drawable->loaderPrivate);
198   }
199   else {
200      buffers = loader->getBuffers(dri_drawable,
201            &dri_drawable->w, &dri_drawable->h,
202            attachments, num_attachments,
203            &num_buffers, dri_drawable->loaderPrivate);
204   }
205
206   if (buffers)
207      *count = num_buffers;
208
209   return buffers;
210}
211
212bool
213dri_image_drawable_get_buffers(struct dri_drawable *drawable,
214                               struct __DRIimageList *images,
215                               const enum st_attachment_type *statts,
216                               unsigned statts_count);
217bool
218dri_image_drawable_get_buffers(struct dri_drawable *drawable,
219                               struct __DRIimageList *images,
220                               const enum st_attachment_type *statts,
221                               unsigned statts_count)
222{
223   __DRIdrawable *dPriv = drawable->dPriv;
224   __DRIscreen *sPriv = drawable->sPriv;
225   unsigned int image_format = __DRI_IMAGE_FORMAT_NONE;
226   enum pipe_format pf;
227   uint32_t buffer_mask = 0;
228   unsigned i, bind;
229
230   for (i = 0; i < statts_count; i++) {
231      dri_drawable_get_format(drawable, statts[i], &pf, &bind);
232      if (pf == PIPE_FORMAT_NONE)
233         continue;
234
235      switch (statts[i]) {
236      case ST_ATTACHMENT_FRONT_LEFT:
237         buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
238         break;
239      case ST_ATTACHMENT_BACK_LEFT:
240         buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
241         break;
242      default:
243         continue;
244      }
245
246      switch (pf) {
247      case PIPE_FORMAT_R16G16B16A16_FLOAT:
248         image_format = __DRI_IMAGE_FORMAT_ABGR16161616F;
249         break;
250      case PIPE_FORMAT_R16G16B16X16_FLOAT:
251         image_format = __DRI_IMAGE_FORMAT_XBGR16161616F;
252         break;
253      case PIPE_FORMAT_B5G5R5A1_UNORM:
254         image_format = __DRI_IMAGE_FORMAT_ARGB1555;
255         break;
256      case PIPE_FORMAT_B5G6R5_UNORM:
257         image_format = __DRI_IMAGE_FORMAT_RGB565;
258         break;
259      case PIPE_FORMAT_BGRX8888_UNORM:
260         image_format = __DRI_IMAGE_FORMAT_XRGB8888;
261         break;
262      case PIPE_FORMAT_BGRA8888_UNORM:
263         image_format = __DRI_IMAGE_FORMAT_ARGB8888;
264         break;
265      case PIPE_FORMAT_RGBX8888_UNORM:
266         image_format = __DRI_IMAGE_FORMAT_XBGR8888;
267         break;
268      case PIPE_FORMAT_RGBA8888_UNORM:
269         image_format = __DRI_IMAGE_FORMAT_ABGR8888;
270         break;
271      case PIPE_FORMAT_B10G10R10X2_UNORM:
272         image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
273         break;
274      case PIPE_FORMAT_B10G10R10A2_UNORM:
275         image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
276         break;
277      case PIPE_FORMAT_R10G10B10X2_UNORM:
278         image_format = __DRI_IMAGE_FORMAT_XBGR2101010;
279         break;
280      case PIPE_FORMAT_R10G10B10A2_UNORM:
281         image_format = __DRI_IMAGE_FORMAT_ABGR2101010;
282         break;
283      default:
284         image_format = __DRI_IMAGE_FORMAT_NONE;
285         break;
286      }
287   }
288
289   return (*sPriv->image.loader->getBuffers) (dPriv, image_format,
290                                       (uint32_t *) &drawable->base.stamp,
291                                       dPriv->loaderPrivate, buffer_mask,
292                                       images);
293}
294
295static __DRIbuffer *
296dri2_allocate_buffer(__DRIscreen *sPriv,
297                     unsigned attachment, unsigned format,
298                     int width, int height)
299{
300   struct dri_screen *screen = dri_screen(sPriv);
301   struct dri2_buffer *buffer;
302   struct pipe_resource templ;
303   enum pipe_format pf;
304   unsigned bind = 0;
305   struct winsys_handle whandle;
306
307   /* struct pipe_resource height0 is 16-bit, avoid overflow */
308   if (height > 0xffff)
309      return NULL;
310
311   switch (attachment) {
312      case __DRI_BUFFER_FRONT_LEFT:
313      case __DRI_BUFFER_FAKE_FRONT_LEFT:
314         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
315         break;
316      case __DRI_BUFFER_BACK_LEFT:
317         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
318         break;
319      case __DRI_BUFFER_DEPTH:
320      case __DRI_BUFFER_DEPTH_STENCIL:
321      case __DRI_BUFFER_STENCIL:
322            bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
323         break;
324   }
325
326   /* because we get the handle and stride */
327   bind |= PIPE_BIND_SHARED;
328
329   switch (format) {
330      case 64:
331         pf = PIPE_FORMAT_R16G16B16A16_FLOAT;
332         break;
333      case 48:
334         pf = PIPE_FORMAT_R16G16B16X16_FLOAT;
335         break;
336      case 32:
337         pf = PIPE_FORMAT_BGRA8888_UNORM;
338         break;
339      case 30:
340         pf = PIPE_FORMAT_B10G10R10X2_UNORM;
341         break;
342      case 24:
343         pf = PIPE_FORMAT_BGRX8888_UNORM;
344         break;
345      case 16:
346         pf = PIPE_FORMAT_Z16_UNORM;
347         break;
348      default:
349         return NULL;
350   }
351
352   buffer = CALLOC_STRUCT(dri2_buffer);
353   if (!buffer)
354      return NULL;
355
356   memset(&templ, 0, sizeof(templ));
357   templ.bind = bind;
358   templ.format = pf;
359   templ.target = PIPE_TEXTURE_2D;
360   templ.last_level = 0;
361   templ.width0 = width;
362   templ.height0 = height;
363   templ.depth0 = 1;
364   templ.array_size = 1;
365
366   buffer->resource =
367      screen->base.screen->resource_create(screen->base.screen, &templ);
368   if (!buffer->resource) {
369      FREE(buffer);
370      return NULL;
371   }
372
373   memset(&whandle, 0, sizeof(whandle));
374   if (screen->can_share_buffer)
375      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
376   else
377      whandle.type = WINSYS_HANDLE_TYPE_KMS;
378
379   screen->base.screen->resource_get_handle(screen->base.screen, NULL,
380         buffer->resource, &whandle,
381         PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
382
383   buffer->base.attachment = attachment;
384   buffer->base.name = whandle.handle;
385   buffer->base.cpp = util_format_get_blocksize(pf);
386   buffer->base.pitch = whandle.stride;
387
388   return &buffer->base;
389}
390
391static void
392dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
393{
394   struct dri2_buffer *buffer = dri2_buffer(bPriv);
395
396   pipe_resource_reference(&buffer->resource, NULL);
397   FREE(buffer);
398}
399
400static void
401dri2_set_in_fence_fd(__DRIimage *img, int fd)
402{
403   validate_fence_fd(fd);
404   validate_fence_fd(img->in_fence_fd);
405   sync_accumulate("dri", &img->in_fence_fd, fd);
406}
407
408static void
409handle_in_fence(__DRIcontext *context, __DRIimage *img)
410{
411   struct dri_context *ctx = dri_context(context);
412   struct pipe_context *pipe = ctx->st->pipe;
413   struct pipe_fence_handle *fence;
414   int fd = img->in_fence_fd;
415
416   if (fd == -1)
417      return;
418
419   validate_fence_fd(fd);
420
421   img->in_fence_fd = -1;
422
423   pipe->create_fence_fd(pipe, &fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
424   pipe->fence_server_sync(pipe, fence);
425   pipe->screen->fence_reference(pipe->screen, &fence, NULL);
426
427   close(fd);
428}
429
430/*
431 * Backend functions for st_framebuffer interface.
432 */
433
434static void
435dri2_allocate_textures(struct dri_context *ctx,
436                       struct dri_drawable *drawable,
437                       const enum st_attachment_type *statts,
438                       unsigned statts_count)
439{
440   __DRIscreen *sPriv = drawable->sPriv;
441   __DRIdrawable *dri_drawable = drawable->dPriv;
442   struct dri_screen *screen = dri_screen(sPriv);
443   struct pipe_resource templ;
444   boolean alloc_depthstencil = FALSE;
445   unsigned i, j, bind;
446   const __DRIimageLoaderExtension *image = sPriv->image.loader;
447   /* Image specific variables */
448   struct __DRIimageList images;
449   /* Dri2 specific variables */
450   __DRIbuffer *buffers = NULL;
451   struct winsys_handle whandle;
452   unsigned num_buffers = statts_count;
453
454   assert(num_buffers <= __DRI_BUFFER_COUNT);
455
456   /* First get the buffers from the loader */
457   if (image) {
458      if (!dri_image_drawable_get_buffers(drawable, &images,
459                                          statts, statts_count))
460         return;
461   }
462   else {
463      buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
464      if (!buffers || (drawable->old_num == num_buffers &&
465                       drawable->old_w == dri_drawable->w &&
466                       drawable->old_h == dri_drawable->h &&
467                       memcmp(drawable->old, buffers,
468                              sizeof(__DRIbuffer) * num_buffers) == 0))
469         return;
470   }
471
472   /* Second clean useless resources*/
473
474   /* See if we need a depth-stencil buffer. */
475   for (i = 0; i < statts_count; i++) {
476      if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
477         alloc_depthstencil = TRUE;
478         break;
479      }
480   }
481
482   /* Delete the resources we won't need. */
483   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
484      /* Don't delete the depth-stencil buffer, we can reuse it. */
485      if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil)
486         continue;
487
488      /* Flush the texture before unreferencing, so that other clients can
489       * see what the driver has rendered.
490       */
491      if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) {
492         struct pipe_context *pipe = ctx->st->pipe;
493         pipe->flush_resource(pipe, drawable->textures[i]);
494      }
495
496      pipe_resource_reference(&drawable->textures[i], NULL);
497   }
498
499   if (drawable->stvis.samples > 1) {
500      for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
501         boolean del = TRUE;
502
503         /* Don't delete MSAA resources for the attachments which are enabled,
504          * we can reuse them. */
505         for (j = 0; j < statts_count; j++) {
506            if (i == statts[j]) {
507               del = FALSE;
508               break;
509            }
510         }
511
512         if (del) {
513            pipe_resource_reference(&drawable->msaa_textures[i], NULL);
514         }
515      }
516   }
517
518   /* Third use the buffers retrieved to fill the drawable info */
519
520   memset(&templ, 0, sizeof(templ));
521   templ.target = screen->target;
522   templ.last_level = 0;
523   templ.depth0 = 1;
524   templ.array_size = 1;
525
526   if (image) {
527      if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
528         struct pipe_resource **buf =
529            &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
530         struct pipe_resource *texture = images.front->texture;
531
532         dri_drawable->w = texture->width0;
533         dri_drawable->h = texture->height0;
534
535         pipe_resource_reference(buf, texture);
536         handle_in_fence(ctx->cPriv, images.front);
537      }
538
539      if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
540         struct pipe_resource **buf =
541            &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
542         struct pipe_resource *texture = images.back->texture;
543
544         dri_drawable->w = texture->width0;
545         dri_drawable->h = texture->height0;
546
547         pipe_resource_reference(buf, texture);
548         handle_in_fence(ctx->cPriv, images.back);
549      }
550
551      if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
552         struct pipe_resource **buf =
553            &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
554         struct pipe_resource *texture = images.back->texture;
555
556         dri_drawable->w = texture->width0;
557         dri_drawable->h = texture->height0;
558
559         pipe_resource_reference(buf, texture);
560         handle_in_fence(ctx->cPriv, images.back);
561
562         ctx->is_shared_buffer_bound = true;
563      } else {
564         ctx->is_shared_buffer_bound = false;
565      }
566
567      /* Note: if there is both a back and a front buffer,
568       * then they have the same size.
569       */
570      templ.width0 = dri_drawable->w;
571      templ.height0 = dri_drawable->h;
572   }
573   else {
574      memset(&whandle, 0, sizeof(whandle));
575
576      /* Process DRI-provided buffers and get pipe_resources. */
577      for (i = 0; i < num_buffers; i++) {
578         __DRIbuffer *buf = &buffers[i];
579         enum st_attachment_type statt;
580         enum pipe_format format;
581
582         switch (buf->attachment) {
583         case __DRI_BUFFER_FRONT_LEFT:
584            if (!screen->auto_fake_front) {
585               continue; /* invalid attachment */
586            }
587            FALLTHROUGH;
588         case __DRI_BUFFER_FAKE_FRONT_LEFT:
589            statt = ST_ATTACHMENT_FRONT_LEFT;
590            break;
591         case __DRI_BUFFER_BACK_LEFT:
592            statt = ST_ATTACHMENT_BACK_LEFT;
593            break;
594         default:
595            continue; /* invalid attachment */
596         }
597
598         dri_drawable_get_format(drawable, statt, &format, &bind);
599         if (format == PIPE_FORMAT_NONE)
600            continue;
601
602         /* dri2_drawable_get_buffers has already filled dri_drawable->w
603          * and dri_drawable->h */
604         templ.width0 = dri_drawable->w;
605         templ.height0 = dri_drawable->h;
606         templ.format = format;
607         templ.bind = bind;
608         whandle.handle = buf->name;
609         whandle.stride = buf->pitch;
610         whandle.offset = 0;
611         whandle.format = format;
612         whandle.modifier = DRM_FORMAT_MOD_INVALID;
613         if (screen->can_share_buffer)
614            whandle.type = WINSYS_HANDLE_TYPE_SHARED;
615         else
616            whandle.type = WINSYS_HANDLE_TYPE_KMS;
617         drawable->textures[statt] =
618            screen->base.screen->resource_from_handle(screen->base.screen,
619                  &templ, &whandle,
620                  PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
621         assert(drawable->textures[statt]);
622      }
623   }
624
625   /* Allocate private MSAA colorbuffers. */
626   if (drawable->stvis.samples > 1) {
627      for (i = 0; i < statts_count; i++) {
628         enum st_attachment_type statt = statts[i];
629
630         if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
631            continue;
632
633         if (drawable->textures[statt]) {
634            templ.format = drawable->textures[statt]->format;
635            templ.bind = drawable->textures[statt]->bind &
636                         ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
637            templ.nr_samples = drawable->stvis.samples;
638            templ.nr_storage_samples = drawable->stvis.samples;
639
640            /* Try to reuse the resource.
641             * (the other resource parameters should be constant)
642             */
643            if (!drawable->msaa_textures[statt] ||
644                drawable->msaa_textures[statt]->width0 != templ.width0 ||
645                drawable->msaa_textures[statt]->height0 != templ.height0) {
646               /* Allocate a new one. */
647               pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
648
649               drawable->msaa_textures[statt] =
650                  screen->base.screen->resource_create(screen->base.screen,
651                                                       &templ);
652               assert(drawable->msaa_textures[statt]);
653
654               /* If there are any MSAA resources, we should initialize them
655                * such that they contain the same data as the single-sample
656                * resources we just got from the X server.
657                *
658                * The reason for this is that the gallium frontend (and
659                * therefore the app) can access the MSAA resources only.
660                * The single-sample resources are not exposed
661                * to the gallium frontend.
662                *
663                */
664               dri_pipe_blit(ctx->st->pipe,
665                             drawable->msaa_textures[statt],
666                             drawable->textures[statt]);
667            }
668         }
669         else {
670            pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
671         }
672      }
673   }
674
675   /* Allocate a private depth-stencil buffer. */
676   if (alloc_depthstencil) {
677      enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
678      struct pipe_resource **zsbuf;
679      enum pipe_format format;
680      unsigned bind;
681
682      dri_drawable_get_format(drawable, statt, &format, &bind);
683
684      if (format) {
685         templ.format = format;
686         templ.bind = bind & ~PIPE_BIND_SHARED;
687
688         if (drawable->stvis.samples > 1) {
689            templ.nr_samples = drawable->stvis.samples;
690            templ.nr_storage_samples = drawable->stvis.samples;
691            zsbuf = &drawable->msaa_textures[statt];
692         }
693         else {
694            templ.nr_samples = 0;
695            templ.nr_storage_samples = 0;
696            zsbuf = &drawable->textures[statt];
697         }
698
699         /* Try to reuse the resource.
700          * (the other resource parameters should be constant)
701          */
702         if (!*zsbuf ||
703             (*zsbuf)->width0 != templ.width0 ||
704             (*zsbuf)->height0 != templ.height0) {
705            /* Allocate a new one. */
706            pipe_resource_reference(zsbuf, NULL);
707            *zsbuf = screen->base.screen->resource_create(screen->base.screen,
708                                                          &templ);
709            assert(*zsbuf);
710         }
711      }
712      else {
713         pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
714         pipe_resource_reference(&drawable->textures[statt], NULL);
715      }
716   }
717
718   /* For DRI2, we may get the same buffers again from the server.
719    * To prevent useless imports of gem names, drawable->old* is used
720    * to bypass the import if we get the same buffers. This doesn't apply
721    * to DRI3/Wayland, users of image.loader, since the buffer is managed
722    * by the client (no import), and the back buffer is going to change
723    * at every redraw.
724    */
725   if (!image) {
726      drawable->old_num = num_buffers;
727      drawable->old_w = dri_drawable->w;
728      drawable->old_h = dri_drawable->h;
729      memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
730   }
731}
732
733static bool
734dri2_flush_frontbuffer(struct dri_context *ctx,
735                       struct dri_drawable *drawable,
736                       enum st_attachment_type statt)
737{
738   __DRIdrawable *dri_drawable = drawable->dPriv;
739   const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
740   const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
741   const __DRImutableRenderBufferLoaderExtension *shared_buffer_loader =
742      drawable->sPriv->mutableRenderBuffer.loader;
743   struct pipe_context *pipe = ctx->st->pipe;
744   struct pipe_fence_handle *fence = NULL;
745   int fence_fd = -1;
746
747   /* We need to flush for front buffer rendering when either we're using the
748    * front buffer at the GL API level, or when EGL_KHR_mutable_render_buffer
749    * has redirected GL_BACK to the front buffer.
750    */
751   if (statt != ST_ATTACHMENT_FRONT_LEFT &&
752       (!ctx->is_shared_buffer_bound || statt != ST_ATTACHMENT_BACK_LEFT))
753         return false;
754
755   if (drawable->stvis.samples > 1) {
756      /* Resolve the buffer used for front rendering. */
757      dri_pipe_blit(ctx->st->pipe, drawable->textures[statt],
758                    drawable->msaa_textures[statt]);
759   }
760
761   if (drawable->textures[statt]) {
762      pipe->flush_resource(pipe, drawable->textures[statt]);
763   }
764
765   if (ctx->is_shared_buffer_bound) {
766      /* is_shared_buffer_bound should only be true with image extension: */
767      assert(image);
768      pipe->flush(pipe, &fence, PIPE_FLUSH_FENCE_FD);
769   } else {
770      pipe->flush(pipe, NULL, 0);
771   }
772
773   if (image) {
774      image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
775      if (ctx->is_shared_buffer_bound) {
776         if (fence)
777            fence_fd = pipe->screen->fence_get_fd(pipe->screen, fence);
778
779         shared_buffer_loader->displaySharedBuffer(dri_drawable, fence_fd,
780                                                   dri_drawable->loaderPrivate);
781
782         pipe->screen->fence_reference(pipe->screen, &fence, NULL);
783      }
784   }
785   else if (loader->flushFrontBuffer) {
786      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
787   }
788
789   return true;
790}
791
792/**
793 * The struct dri_drawable flush_swapbuffers callback
794 */
795static void
796dri2_flush_swapbuffers(struct dri_context *ctx,
797                       struct dri_drawable *drawable)
798{
799   __DRIdrawable *dri_drawable = drawable->dPriv;
800   const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
801
802   if (image && image->base.version >= 3 && image->flushSwapBuffers) {
803      image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate);
804   }
805}
806
807static void
808dri2_update_tex_buffer(struct dri_drawable *drawable,
809                       struct dri_context *ctx,
810                       struct pipe_resource *res)
811{
812   /* no-op */
813}
814
815static const struct dri2_format_mapping r8_g8b8_mapping = {
816   DRM_FORMAT_NV12,
817   __DRI_IMAGE_FORMAT_NONE,
818   __DRI_IMAGE_COMPONENTS_Y_UV,
819   PIPE_FORMAT_R8_G8B8_420_UNORM,
820   2,
821   { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
822     { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } }
823};
824
825static const struct dri2_format_mapping r8g8_r8b8_mapping = {
826   DRM_FORMAT_YUYV,
827   __DRI_IMAGE_FORMAT_NONE,
828   __DRI_IMAGE_COMPONENTS_Y_XUXV,
829   PIPE_FORMAT_R8G8_R8B8_UNORM, 2,
830   { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
831     { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } }
832};
833
834static const struct dri2_format_mapping g8r8_b8r8_mapping = {
835   DRM_FORMAT_UYVY,
836   __DRI_IMAGE_FORMAT_NONE,
837   __DRI_IMAGE_COMPONENTS_Y_XUXV,
838   PIPE_FORMAT_G8R8_B8R8_UNORM, 2,
839   { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
840     { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } }
841};
842
843static __DRIimage *
844dri2_create_image_from_winsys(__DRIscreen *_screen,
845                              int width, int height, const struct dri2_format_mapping *map,
846                              int num_handles, struct winsys_handle *whandle,
847                              unsigned bind,
848                              void *loaderPrivate)
849{
850   struct dri_screen *screen = dri_screen(_screen);
851   struct pipe_screen *pscreen = screen->base.screen;
852   __DRIimage *img;
853   struct pipe_resource templ;
854   unsigned tex_usage = 0;
855   int i;
856   bool use_lowered = false;
857   const unsigned format_planes = util_format_get_num_planes(map->pipe_format);
858
859   if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
860                                    PIPE_BIND_RENDER_TARGET))
861      tex_usage |= PIPE_BIND_RENDER_TARGET;
862   if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
863                                    PIPE_BIND_SAMPLER_VIEW))
864      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
865
866   /* For NV12, see if we have support for sampling r8_b8g8 */
867   if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV12 &&
868       pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8B8_420_UNORM,
869                                    screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
870      map = &r8_g8b8_mapping;
871      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
872   }
873
874   /* If the hardware supports R8G8_R8B8 style subsampled RGB formats, these
875    * can be used for YUYV and UYVY formats.
876    */
877   if (!tex_usage && map->pipe_format == PIPE_FORMAT_YUYV &&
878       pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8G8_R8B8_UNORM,
879                                    screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
880      map = &r8g8_r8b8_mapping;
881      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
882   }
883
884   if (!tex_usage && map->pipe_format == PIPE_FORMAT_UYVY &&
885       pscreen->is_format_supported(pscreen, PIPE_FORMAT_G8R8_B8R8_UNORM,
886                                    screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
887      map = &g8r8_b8r8_mapping;
888      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
889   }
890
891   if (!tex_usage && util_format_is_yuv(map->pipe_format)) {
892      /* YUV format sampling can be emulated by the GL gallium frontend by
893       * using multiple samplers of varying formats.
894       * If no tex_usage is set and we detect a YUV format,
895       * test for support of all planes' sampler formats and
896       * add sampler view usage.
897       */
898      use_lowered = true;
899      if (dri2_yuv_dma_buf_supported(screen, map))
900         tex_usage |= PIPE_BIND_SAMPLER_VIEW;
901   }
902
903   if (!tex_usage)
904      return NULL;
905
906   img = CALLOC_STRUCT(__DRIimageRec);
907   if (!img)
908      return NULL;
909
910   memset(&templ, 0, sizeof(templ));
911   templ.bind = tex_usage | bind;
912   templ.target = screen->target;
913   templ.last_level = 0;
914   templ.depth0 = 1;
915   templ.array_size = 1;
916   templ.width0 = width;
917   templ.height0 = height;
918
919   for (i = num_handles - 1; i >= format_planes; i--) {
920      struct pipe_resource *tex;
921
922      templ.next = img->texture;
923
924      tex = pscreen->resource_from_handle(pscreen, &templ, &whandle[i],
925                                          PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
926      if (!tex) {
927         pipe_resource_reference(&img->texture, NULL);
928         FREE(img);
929         return NULL;
930      }
931
932      img->texture = tex;
933   }
934
935   for (i = (use_lowered ? map->nplanes : format_planes) - 1; i >= 0; i--) {
936      struct pipe_resource *tex;
937
938      templ.next = img->texture;
939      templ.width0 = width >> map->planes[i].width_shift;
940      templ.height0 = height >> map->planes[i].height_shift;
941      if (use_lowered)
942         templ.format = dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format);
943      else
944         templ.format = map->pipe_format;
945      assert(templ.format != PIPE_FORMAT_NONE);
946
947      tex = pscreen->resource_from_handle(pscreen,
948               &templ, &whandle[use_lowered ? map->planes[i].buffer_index : i],
949               PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
950      if (!tex) {
951         pipe_resource_reference(&img->texture, NULL);
952         FREE(img);
953         return NULL;
954      }
955
956      /* Reject image creation if there's an inconsistency between
957       * content protection status of tex and img.
958       */
959      const struct driOptionCache *optionCache = &screen->dev->option_cache;
960      if (!driQueryOptionb(optionCache, "disable_protected_content_check") &&
961          (tex->bind & PIPE_BIND_PROTECTED) != (bind & PIPE_BIND_PROTECTED)) {
962         pipe_resource_reference(&img->texture, NULL);
963         pipe_resource_reference(&tex, NULL);
964         FREE(img);
965         return NULL;
966      }
967
968      img->texture = tex;
969   }
970
971   img->level = 0;
972   img->layer = 0;
973   img->use = 0;
974   img->in_fence_fd = -1;
975   img->loader_private = loaderPrivate;
976   img->sPriv = _screen;
977
978   return img;
979}
980
981static __DRIimage *
982dri2_create_image_from_name(__DRIscreen *_screen,
983                            int width, int height, int format,
984                            int name, int pitch, void *loaderPrivate)
985{
986   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
987   struct winsys_handle whandle;
988   __DRIimage *img;
989
990   if (!map)
991      return NULL;
992
993   memset(&whandle, 0, sizeof(whandle));
994   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
995   whandle.handle = name;
996   whandle.format = map->pipe_format;
997   whandle.modifier = DRM_FORMAT_MOD_INVALID;
998
999   whandle.stride = pitch * util_format_get_blocksize(map->pipe_format);
1000
1001   img = dri2_create_image_from_winsys(_screen, width, height, map,
1002                                       1, &whandle, 0, loaderPrivate);
1003
1004   if (!img)
1005      return NULL;
1006
1007   img->dri_components = map->dri_components;
1008   img->dri_fourcc = map->dri_fourcc;
1009   img->dri_format = map->dri_format;
1010
1011   return img;
1012}
1013
1014static unsigned
1015dri2_get_modifier_num_planes(__DRIscreen *_screen,
1016                             uint64_t modifier, int fourcc)
1017{
1018   struct pipe_screen *pscreen = dri_screen(_screen)->base.screen;
1019   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1020
1021   if (!map)
1022      return 0;
1023
1024   switch (modifier) {
1025   case DRM_FORMAT_MOD_LINEAR:
1026   /* DRM_FORMAT_MOD_NONE is the same as LINEAR */
1027   case DRM_FORMAT_MOD_INVALID:
1028      return util_format_get_num_planes(map->pipe_format);
1029   default:
1030      if (!pscreen->is_dmabuf_modifier_supported ||
1031          !pscreen->is_dmabuf_modifier_supported(pscreen, modifier,
1032                                                 map->pipe_format, NULL)) {
1033         return 0;
1034      }
1035
1036      if (pscreen->get_dmabuf_modifier_planes) {
1037         return pscreen->get_dmabuf_modifier_planes(pscreen, modifier,
1038                                                    map->pipe_format);
1039      }
1040
1041      return map->nplanes;
1042   }
1043}
1044
1045static __DRIimage *
1046dri2_create_image_from_fd(__DRIscreen *_screen,
1047                          int width, int height, int fourcc,
1048                          uint64_t modifier, int *fds, int num_fds,
1049                          int *strides, int *offsets,
1050                          unsigned bind, unsigned *error, void *loaderPrivate)
1051{
1052   struct winsys_handle whandles[4];
1053   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1054   __DRIimage *img = NULL;
1055   unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
1056   int i;
1057   const int expected_num_fds = dri2_get_modifier_num_planes(_screen, modifier, fourcc);
1058
1059   if (!map || expected_num_fds == 0) {
1060      err = __DRI_IMAGE_ERROR_BAD_MATCH;
1061      goto exit;
1062   }
1063
1064   if (num_fds != expected_num_fds) {
1065      err = __DRI_IMAGE_ERROR_BAD_MATCH;
1066      goto exit;
1067   }
1068
1069   memset(whandles, 0, sizeof(whandles));
1070
1071   for (i = 0; i < num_fds; i++) {
1072      if (fds[i] < 0) {
1073         err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1074         goto exit;
1075      }
1076
1077      whandles[i].type = WINSYS_HANDLE_TYPE_FD;
1078      whandles[i].handle = (unsigned)fds[i];
1079      whandles[i].stride = (unsigned)strides[i];
1080      whandles[i].offset = (unsigned)offsets[i];
1081      whandles[i].format = map->pipe_format;
1082      whandles[i].modifier = modifier;
1083      whandles[i].plane = i;
1084   }
1085
1086   img = dri2_create_image_from_winsys(_screen, width, height, map,
1087                                       num_fds, whandles, bind,
1088                                       loaderPrivate);
1089   if(img == NULL) {
1090      err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1091      goto exit;
1092   }
1093
1094   img->dri_components = map->dri_components;
1095   img->dri_fourcc = fourcc;
1096   img->dri_format = map->dri_format;
1097   img->imported_dmabuf = TRUE;
1098
1099exit:
1100   if (error)
1101      *error = err;
1102
1103   return img;
1104}
1105
1106static __DRIimage *
1107dri2_create_image_common(__DRIscreen *_screen,
1108                         int width, int height,
1109                         int format, unsigned int use,
1110                         const uint64_t *modifiers,
1111                         const unsigned count,
1112                         void *loaderPrivate)
1113{
1114   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1115   struct dri_screen *screen = dri_screen(_screen);
1116   struct pipe_screen *pscreen = screen->base.screen;
1117   __DRIimage *img;
1118   struct pipe_resource templ;
1119   unsigned tex_usage = 0;
1120
1121   if (!map)
1122      return NULL;
1123
1124   if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1125                                    0, 0, PIPE_BIND_RENDER_TARGET))
1126      tex_usage |= PIPE_BIND_RENDER_TARGET;
1127   if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1128                                    0, 0, PIPE_BIND_SAMPLER_VIEW))
1129      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
1130
1131   if (!tex_usage)
1132      return NULL;
1133
1134   if (use & __DRI_IMAGE_USE_SCANOUT)
1135      tex_usage |= PIPE_BIND_SCANOUT;
1136   if (use & __DRI_IMAGE_USE_SHARE)
1137      tex_usage |= PIPE_BIND_SHARED;
1138   if (use & __DRI_IMAGE_USE_LINEAR)
1139      tex_usage |= PIPE_BIND_LINEAR;
1140   if (use & __DRI_IMAGE_USE_CURSOR) {
1141      if (width != 64 || height != 64)
1142         return NULL;
1143      tex_usage |= PIPE_BIND_CURSOR;
1144   }
1145   if (use & __DRI_IMAGE_USE_PROTECTED)
1146      tex_usage |= PIPE_BIND_PROTECTED;
1147   if (use & __DRI_IMAGE_USE_PRIME_BUFFER)
1148      tex_usage |= PIPE_BIND_PRIME_BLIT_DST;
1149
1150   img = CALLOC_STRUCT(__DRIimageRec);
1151   if (!img)
1152      return NULL;
1153
1154   memset(&templ, 0, sizeof(templ));
1155   templ.bind = tex_usage;
1156   templ.format = map->pipe_format;
1157   templ.target = PIPE_TEXTURE_2D;
1158   templ.last_level = 0;
1159   templ.width0 = width;
1160   templ.height0 = height;
1161   templ.depth0 = 1;
1162   templ.array_size = 1;
1163
1164   if (modifiers)
1165      img->texture =
1166         screen->base.screen
1167            ->resource_create_with_modifiers(screen->base.screen,
1168                                             &templ,
1169                                             modifiers,
1170                                             count);
1171   else
1172      img->texture =
1173         screen->base.screen->resource_create(screen->base.screen, &templ);
1174   if (!img->texture) {
1175      FREE(img);
1176      return NULL;
1177   }
1178
1179   img->level = 0;
1180   img->layer = 0;
1181   img->dri_format = format;
1182   img->dri_fourcc = map->dri_fourcc;
1183   img->dri_components = 0;
1184   img->use = use;
1185   img->in_fence_fd = -1;
1186
1187   img->loader_private = loaderPrivate;
1188   img->sPriv = _screen;
1189   return img;
1190}
1191
1192static __DRIimage *
1193dri2_create_image(__DRIscreen *_screen,
1194                   int width, int height, int format,
1195                   unsigned int use, void *loaderPrivate)
1196{
1197   return dri2_create_image_common(_screen, width, height, format, use,
1198                                   NULL /* modifiers */, 0 /* count */,
1199                                   loaderPrivate);
1200}
1201
1202static __DRIimage *
1203dri2_create_image_with_modifiers(__DRIscreen *dri_screen,
1204                                 int width, int height, int format,
1205                                 const uint64_t *modifiers,
1206                                 const unsigned count,
1207                                 void *loaderPrivate)
1208{
1209   return dri2_create_image_common(dri_screen, width, height, format,
1210                                   __DRI_IMAGE_USE_SHARE, modifiers, count,
1211                                   loaderPrivate);
1212}
1213
1214static __DRIimage *
1215dri2_create_image_with_modifiers2(__DRIscreen *dri_screen,
1216                                 int width, int height, int format,
1217                                 const uint64_t *modifiers,
1218                                 const unsigned count, unsigned int use,
1219                                 void *loaderPrivate)
1220{
1221   return dri2_create_image_common(dri_screen, width, height, format, use,
1222                                   modifiers, count, loaderPrivate);
1223}
1224
1225static bool
1226dri2_query_image_common(__DRIimage *image, int attrib, int *value)
1227{
1228   switch (attrib) {
1229   case __DRI_IMAGE_ATTRIB_FORMAT:
1230      *value = image->dri_format;
1231      return true;
1232   case __DRI_IMAGE_ATTRIB_WIDTH:
1233      *value = image->texture->width0;
1234      return true;
1235   case __DRI_IMAGE_ATTRIB_HEIGHT:
1236      *value = image->texture->height0;
1237      return true;
1238   case __DRI_IMAGE_ATTRIB_COMPONENTS:
1239      if (image->dri_components == 0)
1240         return false;
1241      *value = image->dri_components;
1242      return true;
1243   case __DRI_IMAGE_ATTRIB_FOURCC:
1244      if (image->dri_fourcc) {
1245         *value = image->dri_fourcc;
1246      } else {
1247         const struct dri2_format_mapping *map;
1248
1249         map = dri2_get_mapping_by_format(image->dri_format);
1250         if (!map)
1251            return false;
1252
1253         *value = map->dri_fourcc;
1254      }
1255      return true;
1256   default:
1257      return false;
1258   }
1259}
1260
1261static bool
1262dri2_query_image_by_resource_handle(__DRIimage *image, int attrib, int *value)
1263{
1264   struct pipe_screen *pscreen = image->texture->screen;
1265   struct winsys_handle whandle;
1266   struct pipe_resource *tex;
1267   unsigned usage;
1268   memset(&whandle, 0, sizeof(whandle));
1269   whandle.plane = image->plane;
1270   int i;
1271
1272   switch (attrib) {
1273   case __DRI_IMAGE_ATTRIB_STRIDE:
1274   case __DRI_IMAGE_ATTRIB_OFFSET:
1275   case __DRI_IMAGE_ATTRIB_HANDLE:
1276      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1277      break;
1278   case __DRI_IMAGE_ATTRIB_NAME:
1279      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1280      break;
1281   case __DRI_IMAGE_ATTRIB_FD:
1282      whandle.type = WINSYS_HANDLE_TYPE_FD;
1283      break;
1284   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1285      for (i = 0, tex = image->texture; tex; tex = tex->next)
1286         i++;
1287      *value = i;
1288      return true;
1289   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1290   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1291      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1292      whandle.modifier = DRM_FORMAT_MOD_INVALID;
1293      break;
1294   default:
1295      return false;
1296   }
1297
1298   usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1299
1300   if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1301      usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1302
1303   if (!pscreen->resource_get_handle(pscreen, NULL, image->texture,
1304                                     &whandle, usage))
1305      return false;
1306
1307   switch (attrib) {
1308   case __DRI_IMAGE_ATTRIB_STRIDE:
1309      *value = whandle.stride;
1310      return true;
1311   case __DRI_IMAGE_ATTRIB_OFFSET:
1312      *value = whandle.offset;
1313      return true;
1314   case __DRI_IMAGE_ATTRIB_HANDLE:
1315   case __DRI_IMAGE_ATTRIB_NAME:
1316   case __DRI_IMAGE_ATTRIB_FD:
1317      *value = whandle.handle;
1318      return true;
1319   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1320      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1321         return false;
1322      *value = (whandle.modifier >> 32) & 0xffffffff;
1323      return true;
1324   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1325      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1326         return false;
1327      *value = whandle.modifier & 0xffffffff;
1328      return true;
1329   default:
1330      return false;
1331   }
1332}
1333
1334static bool
1335dri2_resource_get_param(__DRIimage *image, enum pipe_resource_param param,
1336                        unsigned handle_usage, uint64_t *value)
1337{
1338   struct pipe_screen *pscreen = image->texture->screen;
1339   if (!pscreen->resource_get_param)
1340      return false;
1341
1342   if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1343      handle_usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1344
1345   return pscreen->resource_get_param(pscreen, NULL, image->texture,
1346                                      image->plane, 0, 0, param, handle_usage,
1347                                      value);
1348}
1349
1350static bool
1351dri2_query_image_by_resource_param(__DRIimage *image, int attrib, int *value)
1352{
1353   enum pipe_resource_param param;
1354   uint64_t res_param;
1355   unsigned handle_usage;
1356
1357   if (!image->texture->screen->resource_get_param)
1358      return false;
1359
1360   switch (attrib) {
1361   case __DRI_IMAGE_ATTRIB_STRIDE:
1362      param = PIPE_RESOURCE_PARAM_STRIDE;
1363      break;
1364   case __DRI_IMAGE_ATTRIB_OFFSET:
1365      param = PIPE_RESOURCE_PARAM_OFFSET;
1366      break;
1367   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1368      param = PIPE_RESOURCE_PARAM_NPLANES;
1369      break;
1370   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1371   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1372      param = PIPE_RESOURCE_PARAM_MODIFIER;
1373      break;
1374   case __DRI_IMAGE_ATTRIB_HANDLE:
1375      param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS;
1376      break;
1377   case __DRI_IMAGE_ATTRIB_NAME:
1378      param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED;
1379      break;
1380   case __DRI_IMAGE_ATTRIB_FD:
1381      param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD;
1382      break;
1383   default:
1384      return false;
1385   }
1386
1387   handle_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1388
1389   if (!dri2_resource_get_param(image, param, handle_usage, &res_param))
1390      return false;
1391
1392   switch (attrib) {
1393   case __DRI_IMAGE_ATTRIB_STRIDE:
1394   case __DRI_IMAGE_ATTRIB_OFFSET:
1395   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1396      if (res_param > INT_MAX)
1397         return false;
1398      *value = (int)res_param;
1399      return true;
1400   case __DRI_IMAGE_ATTRIB_HANDLE:
1401   case __DRI_IMAGE_ATTRIB_NAME:
1402   case __DRI_IMAGE_ATTRIB_FD:
1403      if (res_param > UINT_MAX)
1404         return false;
1405      *value = (int)res_param;
1406      return true;
1407   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1408      if (res_param == DRM_FORMAT_MOD_INVALID)
1409         return false;
1410      *value = (res_param >> 32) & 0xffffffff;
1411      return true;
1412   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1413      if (res_param == DRM_FORMAT_MOD_INVALID)
1414         return false;
1415      *value = res_param & 0xffffffff;
1416      return true;
1417   default:
1418      return false;
1419   }
1420}
1421
1422static GLboolean
1423dri2_query_image(__DRIimage *image, int attrib, int *value)
1424{
1425   if (dri2_query_image_common(image, attrib, value))
1426      return GL_TRUE;
1427   else if (dri2_query_image_by_resource_param(image, attrib, value))
1428      return GL_TRUE;
1429   else if (dri2_query_image_by_resource_handle(image, attrib, value))
1430      return GL_TRUE;
1431   else
1432      return GL_FALSE;
1433}
1434
1435static __DRIimage *
1436dri2_dup_image(__DRIimage *image, void *loaderPrivate)
1437{
1438   __DRIimage *img;
1439
1440   img = CALLOC_STRUCT(__DRIimageRec);
1441   if (!img)
1442      return NULL;
1443
1444   img->texture = NULL;
1445   pipe_resource_reference(&img->texture, image->texture);
1446   img->level = image->level;
1447   img->layer = image->layer;
1448   img->dri_format = image->dri_format;
1449   img->internal_format = image->internal_format;
1450   /* This should be 0 for sub images, but dup is also used for base images. */
1451   img->dri_components = image->dri_components;
1452   img->use = image->use;
1453   img->in_fence_fd = (image->in_fence_fd > 0) ?
1454         os_dupfd_cloexec(image->in_fence_fd) : -1;
1455   img->loader_private = loaderPrivate;
1456   img->sPriv = image->sPriv;
1457
1458   return img;
1459}
1460
1461static GLboolean
1462dri2_validate_usage(__DRIimage *image, unsigned int use)
1463{
1464   if (!image || !image->texture)
1465      return false;
1466
1467   struct pipe_screen *screen = image->texture->screen;
1468   if (!screen->check_resource_capability)
1469      return true;
1470
1471   /* We don't want to check these:
1472    *   __DRI_IMAGE_USE_SHARE (all images are shareable)
1473    *   __DRI_IMAGE_USE_BACKBUFFER (all images support this)
1474    */
1475   unsigned bind = 0;
1476   if (use & __DRI_IMAGE_USE_SCANOUT)
1477      bind |= PIPE_BIND_SCANOUT;
1478   if (use & __DRI_IMAGE_USE_LINEAR)
1479      bind |= PIPE_BIND_LINEAR;
1480   if (use & __DRI_IMAGE_USE_CURSOR)
1481      bind |= PIPE_BIND_CURSOR;
1482
1483   if (!bind)
1484      return true;
1485
1486   return screen->check_resource_capability(screen, image->texture, bind);
1487}
1488
1489static __DRIimage *
1490dri2_from_names(__DRIscreen *screen, int width, int height, int format,
1491                int *names, int num_names, int *strides, int *offsets,
1492                void *loaderPrivate)
1493{
1494   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1495   __DRIimage *img;
1496   struct winsys_handle whandle;
1497
1498   if (!map)
1499      return NULL;
1500
1501   if (num_names != 1)
1502      return NULL;
1503
1504   memset(&whandle, 0, sizeof(whandle));
1505   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1506   whandle.handle = names[0];
1507   whandle.stride = strides[0];
1508   whandle.offset = offsets[0];
1509   whandle.format = map->pipe_format;
1510   whandle.modifier = DRM_FORMAT_MOD_INVALID;
1511
1512   img = dri2_create_image_from_winsys(screen, width, height, map,
1513                                       1, &whandle, 0, loaderPrivate);
1514   if (img == NULL)
1515      return NULL;
1516
1517   img->dri_components = map->dri_components;
1518   img->dri_fourcc = map->dri_fourcc;
1519   img->dri_format = map->pipe_format;
1520
1521   return img;
1522}
1523
1524static __DRIimage *
1525dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
1526{
1527   __DRIimage *img;
1528
1529   if (plane < 0) {
1530      return NULL;
1531   } else if (plane > 0) {
1532      uint64_t planes;
1533      if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_NPLANES, 0,
1534                                   &planes) ||
1535          plane >= planes) {
1536         return NULL;
1537      }
1538   }
1539
1540   if (image->dri_components == 0) {
1541      uint64_t modifier;
1542      if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_MODIFIER, 0,
1543                                   &modifier) ||
1544          modifier == DRM_FORMAT_MOD_INVALID) {
1545         return NULL;
1546      }
1547   }
1548
1549   img = dri2_dup_image(image, loaderPrivate);
1550   if (img == NULL)
1551      return NULL;
1552
1553   if (img->texture->screen->resource_changed)
1554      img->texture->screen->resource_changed(img->texture->screen,
1555                                             img->texture);
1556
1557   /* set this to 0 for sub images. */
1558   img->dri_components = 0;
1559   img->plane = plane;
1560   return img;
1561}
1562
1563static __DRIimage *
1564dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
1565              int *fds, int num_fds, int *strides, int *offsets,
1566              void *loaderPrivate)
1567{
1568   return dri2_create_image_from_fd(screen, width, height, fourcc,
1569                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
1570                                   strides, offsets, 0, NULL, loaderPrivate);
1571}
1572
1573static __DRIimage *
1574dri2_from_fds2(__DRIscreen *screen, int width, int height, int fourcc,
1575              int *fds, int num_fds, uint32_t flags, int *strides,
1576              int *offsets, void *loaderPrivate)
1577{
1578   unsigned bind = 0;
1579   if (flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG)
1580      bind |= PIPE_BIND_PROTECTED;
1581   if (flags & __DRI_IMAGE_PRIME_LINEAR_BUFFER)
1582      bind |= PIPE_BIND_PRIME_BLIT_DST;
1583
1584   return dri2_create_image_from_fd(screen, width, height, fourcc,
1585                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
1586                                   strides, offsets, bind, NULL, loaderPrivate);
1587}
1588
1589static boolean
1590dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
1591                             uint64_t *modifiers, unsigned int *external_only,
1592                             int *count)
1593{
1594   struct dri_screen *screen = dri_screen(_screen);
1595   struct pipe_screen *pscreen = screen->base.screen;
1596   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1597   enum pipe_format format;
1598
1599   if (!map)
1600      return false;
1601
1602   format = map->pipe_format;
1603
1604   bool native_sampling = pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1605                                                       PIPE_BIND_SAMPLER_VIEW);
1606   if (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1607                                    PIPE_BIND_RENDER_TARGET) ||
1608       native_sampling ||
1609       dri2_yuv_dma_buf_supported(screen, map))  {
1610      if (pscreen->query_dmabuf_modifiers != NULL) {
1611         pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
1612                                         external_only, count);
1613         if (!native_sampling && external_only) {
1614            /* To support it using YUV lowering, we need it to be samplerExternalOES.
1615             */
1616            for (int i = 0; i < *count; i++)
1617               external_only[i] = true;
1618         }
1619      } else {
1620         *count = 0;
1621      }
1622      return true;
1623   }
1624   return false;
1625}
1626
1627static boolean
1628dri2_query_dma_buf_format_modifier_attribs(__DRIscreen *_screen,
1629                                           uint32_t fourcc, uint64_t modifier,
1630                                           int attrib, uint64_t *value)
1631{
1632   struct dri_screen *screen = dri_screen(_screen);
1633   struct pipe_screen *pscreen = screen->base.screen;
1634
1635   if (!pscreen->query_dmabuf_modifiers)
1636      return false;
1637
1638   switch (attrib) {
1639   case __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT: {
1640      uint64_t mod_planes = dri2_get_modifier_num_planes(_screen, modifier,
1641                                                         fourcc);
1642      if (mod_planes > 0)
1643         *value = mod_planes;
1644      return mod_planes > 0;
1645   }
1646   default:
1647      return false;
1648   }
1649}
1650
1651static __DRIimage *
1652dri2_from_dma_bufs(__DRIscreen *screen,
1653                   int width, int height, int fourcc,
1654                   int *fds, int num_fds,
1655                   int *strides, int *offsets,
1656                   enum __DRIYUVColorSpace yuv_color_space,
1657                   enum __DRISampleRange sample_range,
1658                   enum __DRIChromaSiting horizontal_siting,
1659                   enum __DRIChromaSiting vertical_siting,
1660                   unsigned *error,
1661                   void *loaderPrivate)
1662{
1663   __DRIimage *img;
1664
1665   img = dri2_create_image_from_fd(screen, width, height, fourcc,
1666                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
1667                                   strides, offsets, 0, error, loaderPrivate);
1668   if (img == NULL)
1669      return NULL;
1670
1671   img->yuv_color_space = yuv_color_space;
1672   img->sample_range = sample_range;
1673   img->horizontal_siting = horizontal_siting;
1674   img->vertical_siting = vertical_siting;
1675
1676   *error = __DRI_IMAGE_ERROR_SUCCESS;
1677   return img;
1678}
1679
1680static __DRIimage *
1681dri2_from_dma_bufs2(__DRIscreen *screen,
1682                    int width, int height, int fourcc,
1683                    uint64_t modifier, int *fds, int num_fds,
1684                    int *strides, int *offsets,
1685                    enum __DRIYUVColorSpace yuv_color_space,
1686                    enum __DRISampleRange sample_range,
1687                    enum __DRIChromaSiting horizontal_siting,
1688                    enum __DRIChromaSiting vertical_siting,
1689                    unsigned *error,
1690                    void *loaderPrivate)
1691{
1692   __DRIimage *img;
1693
1694   img = dri2_create_image_from_fd(screen, width, height, fourcc,
1695                                   modifier, fds, num_fds, strides, offsets,
1696                                   0, error, loaderPrivate);
1697   if (img == NULL)
1698      return NULL;
1699
1700   img->yuv_color_space = yuv_color_space;
1701   img->sample_range = sample_range;
1702   img->horizontal_siting = horizontal_siting;
1703   img->vertical_siting = vertical_siting;
1704
1705   *error = __DRI_IMAGE_ERROR_SUCCESS;
1706   return img;
1707}
1708
1709static __DRIimage *
1710dri2_from_dma_bufs3(__DRIscreen *screen,
1711                    int width, int height, int fourcc,
1712                    uint64_t modifier, int *fds, int num_fds,
1713                    int *strides, int *offsets,
1714                    enum __DRIYUVColorSpace yuv_color_space,
1715                    enum __DRISampleRange sample_range,
1716                    enum __DRIChromaSiting horizontal_siting,
1717                    enum __DRIChromaSiting vertical_siting,
1718                    uint32_t flags,
1719                    unsigned *error,
1720                    void *loaderPrivate)
1721{
1722   __DRIimage *img;
1723
1724   img = dri2_create_image_from_fd(screen, width, height, fourcc,
1725                                   modifier, fds, num_fds, strides, offsets,
1726                                   (flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG) ?
1727                                      PIPE_BIND_PROTECTED : 0,
1728                                   error, loaderPrivate);
1729   if (img == NULL)
1730      return NULL;
1731
1732   img->yuv_color_space = yuv_color_space;
1733   img->sample_range = sample_range;
1734   img->horizontal_siting = horizontal_siting;
1735   img->vertical_siting = vertical_siting;
1736
1737   *error = __DRI_IMAGE_ERROR_SUCCESS;
1738   return img;
1739}
1740
1741static void
1742dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
1743                int dstx0, int dsty0, int dstwidth, int dstheight,
1744                int srcx0, int srcy0, int srcwidth, int srcheight,
1745                int flush_flag)
1746{
1747   struct dri_context *ctx = dri_context(context);
1748   struct pipe_context *pipe = ctx->st->pipe;
1749   struct pipe_screen *screen;
1750   struct pipe_fence_handle *fence;
1751   struct pipe_blit_info blit;
1752
1753   if (!dst || !src)
1754      return;
1755
1756   handle_in_fence(context, dst);
1757
1758   memset(&blit, 0, sizeof(blit));
1759   blit.dst.resource = dst->texture;
1760   blit.dst.box.x = dstx0;
1761   blit.dst.box.y = dsty0;
1762   blit.dst.box.width = dstwidth;
1763   blit.dst.box.height = dstheight;
1764   blit.dst.box.depth = 1;
1765   blit.dst.format = dst->texture->format;
1766   blit.src.resource = src->texture;
1767   blit.src.box.x = srcx0;
1768   blit.src.box.y = srcy0;
1769   blit.src.box.width = srcwidth;
1770   blit.src.box.height = srcheight;
1771   blit.src.box.depth = 1;
1772   blit.src.format = src->texture->format;
1773   blit.mask = PIPE_MASK_RGBA;
1774   blit.filter = PIPE_TEX_FILTER_NEAREST;
1775
1776   pipe->blit(pipe, &blit);
1777
1778   if (flush_flag == __BLIT_FLAG_FLUSH) {
1779      pipe->flush_resource(pipe, dst->texture);
1780      ctx->st->flush(ctx->st, 0, NULL, NULL, NULL);
1781   } else if (flush_flag == __BLIT_FLAG_FINISH) {
1782      screen = dri_screen(ctx->sPriv)->base.screen;
1783      pipe->flush_resource(pipe, dst->texture);
1784      ctx->st->flush(ctx->st, 0, &fence, NULL, NULL);
1785      (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
1786      screen->fence_reference(screen, &fence, NULL);
1787   }
1788}
1789
1790static void *
1791dri2_map_image(__DRIcontext *context, __DRIimage *image,
1792                int x0, int y0, int width, int height,
1793                unsigned int flags, int *stride, void **data)
1794{
1795   struct dri_context *ctx = dri_context(context);
1796   struct pipe_context *pipe = ctx->st->pipe;
1797   enum pipe_map_flags pipe_access = 0;
1798   struct pipe_transfer *trans;
1799   void *map;
1800
1801   if (!image || !data || *data)
1802      return NULL;
1803
1804   unsigned plane = image->plane;
1805   if (plane >= dri2_get_mapping_by_format(image->dri_format)->nplanes)
1806      return NULL;
1807
1808   handle_in_fence(context, image);
1809
1810   struct pipe_resource *resource = image->texture;
1811   while (plane--)
1812      resource = resource->next;
1813
1814   if (flags & __DRI_IMAGE_TRANSFER_READ)
1815         pipe_access |= PIPE_MAP_READ;
1816   if (flags & __DRI_IMAGE_TRANSFER_WRITE)
1817         pipe_access |= PIPE_MAP_WRITE;
1818
1819   map = pipe_texture_map(pipe, resource, 0, 0, pipe_access, x0, y0,
1820                           width, height, &trans);
1821   if (map) {
1822      *data = trans;
1823      *stride = trans->stride;
1824   }
1825
1826   return map;
1827}
1828
1829static void
1830dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
1831{
1832   struct dri_context *ctx = dri_context(context);
1833   struct pipe_context *pipe = ctx->st->pipe;
1834
1835   pipe_texture_unmap(pipe, (struct pipe_transfer *)data);
1836}
1837
1838static int
1839dri2_get_capabilities(__DRIscreen *_screen)
1840{
1841   struct dri_screen *screen = dri_screen(_screen);
1842
1843   return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0);
1844}
1845
1846/* The extension is modified during runtime if DRI_PRIME is detected */
1847static const __DRIimageExtension dri2ImageExtensionTempl = {
1848    .base = { __DRI_IMAGE, 21 },
1849
1850    .createImageFromName          = dri2_create_image_from_name,
1851    .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1852    .destroyImage                 = dri2_destroy_image,
1853    .createImage                  = dri2_create_image,
1854    .queryImage                   = dri2_query_image,
1855    .dupImage                     = dri2_dup_image,
1856    .validateUsage                = dri2_validate_usage,
1857    .createImageFromNames         = dri2_from_names,
1858    .fromPlanar                   = dri2_from_planar,
1859    .createImageFromTexture       = dri2_create_from_texture,
1860    .createImageFromFds           = NULL,
1861    .createImageFromFds2          = NULL,
1862    .createImageFromDmaBufs       = NULL,
1863    .blitImage                    = dri2_blit_image,
1864    .getCapabilities              = dri2_get_capabilities,
1865    .mapImage                     = dri2_map_image,
1866    .unmapImage                   = dri2_unmap_image,
1867    .createImageWithModifiers     = NULL,
1868    .createImageFromDmaBufs2      = NULL,
1869    .createImageFromDmaBufs3      = NULL,
1870    .queryDmaBufFormats           = NULL,
1871    .queryDmaBufModifiers         = NULL,
1872    .queryDmaBufFormatModifierAttribs = NULL,
1873    .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1874    .createImageWithModifiers2    = NULL,
1875};
1876
1877const __DRIimageExtension driVkImageExtension = {
1878    .base = { __DRI_IMAGE, 20 },
1879
1880    .createImageFromName          = dri2_create_image_from_name,
1881    .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1882    .destroyImage                 = dri2_destroy_image,
1883    .createImage                  = dri2_create_image,
1884    .queryImage                   = dri2_query_image,
1885    .dupImage                     = dri2_dup_image,
1886    .validateUsage                = dri2_validate_usage,
1887    .createImageFromNames         = dri2_from_names,
1888    .fromPlanar                   = dri2_from_planar,
1889    .createImageFromTexture       = dri2_create_from_texture,
1890    .createImageFromFds           = dri2_from_fds,
1891    .createImageFromFds2          = dri2_from_fds2,
1892    .createImageFromDmaBufs       = dri2_from_dma_bufs,
1893    .blitImage                    = dri2_blit_image,
1894    .getCapabilities              = dri2_get_capabilities,
1895    .mapImage                     = dri2_map_image,
1896    .unmapImage                   = dri2_unmap_image,
1897    .createImageWithModifiers     = dri2_create_image_with_modifiers,
1898    .createImageFromDmaBufs2      = dri2_from_dma_bufs2,
1899    .createImageFromDmaBufs3      = dri2_from_dma_bufs3,
1900    .queryDmaBufFormats           = dri2_query_dma_buf_formats,
1901    .queryDmaBufModifiers         = dri2_query_dma_buf_modifiers,
1902    .queryDmaBufFormatModifierAttribs = dri2_query_dma_buf_format_modifier_attribs,
1903    .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1904    .createImageWithModifiers2    = dri2_create_image_with_modifiers2,
1905};
1906
1907const __DRIimageExtension driVkImageExtensionSw = {
1908    .base = { __DRI_IMAGE, 20 },
1909
1910    .createImageFromName          = dri2_create_image_from_name,
1911    .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1912    .destroyImage                 = dri2_destroy_image,
1913    .createImage                  = dri2_create_image,
1914    .queryImage                   = dri2_query_image,
1915    .dupImage                     = dri2_dup_image,
1916    .validateUsage                = dri2_validate_usage,
1917    .createImageFromNames         = dri2_from_names,
1918    .fromPlanar                   = dri2_from_planar,
1919    .createImageFromTexture       = dri2_create_from_texture,
1920    .createImageFromFds           = dri2_from_fds,
1921    .createImageFromFds2          = dri2_from_fds2,
1922    .blitImage                    = dri2_blit_image,
1923    .getCapabilities              = dri2_get_capabilities,
1924    .mapImage                     = dri2_map_image,
1925    .unmapImage                   = dri2_unmap_image,
1926    .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1927};
1928
1929static const __DRIrobustnessExtension dri2Robustness = {
1930   .base = { __DRI2_ROBUSTNESS, 1 }
1931};
1932
1933static int
1934dri2_interop_query_device_info(__DRIcontext *_ctx,
1935                               struct mesa_glinterop_device_info *out)
1936{
1937   struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
1938
1939   /* There is no version 0, thus we do not support it */
1940   if (out->version == 0)
1941      return MESA_GLINTEROP_INVALID_VERSION;
1942
1943   out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
1944   out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
1945   out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
1946   out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
1947
1948   out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
1949   out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
1950
1951   /* Instruct the caller that we support up-to version one of the interface */
1952   out->version = 1;
1953
1954   return MESA_GLINTEROP_SUCCESS;
1955}
1956
1957static int
1958dri2_interop_export_object(__DRIcontext *_ctx,
1959                           struct mesa_glinterop_export_in *in,
1960                           struct mesa_glinterop_export_out *out)
1961{
1962   struct st_context_iface *st = dri_context(_ctx)->st;
1963   struct pipe_screen *screen = st->pipe->screen;
1964   struct gl_context *ctx = ((struct st_context *)st)->ctx;
1965   struct pipe_resource *res = NULL;
1966   struct winsys_handle whandle;
1967   unsigned target, usage;
1968   boolean success;
1969
1970   /* There is no version 0, thus we do not support it */
1971   if (in->version == 0 || out->version == 0)
1972      return MESA_GLINTEROP_INVALID_VERSION;
1973
1974   /* Validate the target. */
1975   switch (in->target) {
1976   case GL_TEXTURE_BUFFER:
1977   case GL_TEXTURE_1D:
1978   case GL_TEXTURE_2D:
1979   case GL_TEXTURE_3D:
1980   case GL_TEXTURE_RECTANGLE:
1981   case GL_TEXTURE_1D_ARRAY:
1982   case GL_TEXTURE_2D_ARRAY:
1983   case GL_TEXTURE_CUBE_MAP_ARRAY:
1984   case GL_TEXTURE_CUBE_MAP:
1985   case GL_TEXTURE_2D_MULTISAMPLE:
1986   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1987   case GL_TEXTURE_EXTERNAL_OES:
1988   case GL_RENDERBUFFER:
1989   case GL_ARRAY_BUFFER:
1990      target = in->target;
1991      break;
1992   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1993   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1994   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1995   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1996   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1997   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1998      target = GL_TEXTURE_CUBE_MAP;
1999      break;
2000   default:
2001      return MESA_GLINTEROP_INVALID_TARGET;
2002   }
2003
2004   /* Validate the simple case of miplevel. */
2005   if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
2006       in->miplevel != 0)
2007      return MESA_GLINTEROP_INVALID_MIP_LEVEL;
2008
2009   /* Validate the OpenGL object and get pipe_resource. */
2010   simple_mtx_lock(&ctx->Shared->Mutex);
2011
2012   if (target == GL_ARRAY_BUFFER) {
2013      /* Buffer objects.
2014       *
2015       * The error checking is based on the documentation of
2016       * clCreateFromGLBuffer from OpenCL 2.0 SDK.
2017       */
2018      struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
2019
2020      /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
2021       *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
2022       *   a GL buffer object but does not have an existing data store or
2023       *   the size of the buffer is 0."
2024       */
2025      if (!buf || buf->Size == 0) {
2026         simple_mtx_unlock(&ctx->Shared->Mutex);
2027         return MESA_GLINTEROP_INVALID_OBJECT;
2028      }
2029
2030      res = buf->buffer;
2031      if (!res) {
2032         /* this shouldn't happen */
2033         simple_mtx_unlock(&ctx->Shared->Mutex);
2034         return MESA_GLINTEROP_INVALID_OBJECT;
2035      }
2036
2037      out->buf_offset = 0;
2038      out->buf_size = buf->Size;
2039
2040      buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
2041   } else if (target == GL_RENDERBUFFER) {
2042      /* Renderbuffers.
2043       *
2044       * The error checking is based on the documentation of
2045       * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
2046       */
2047      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
2048
2049      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2050       *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
2051       *    object or if the width or height of renderbuffer is zero."
2052       */
2053      if (!rb || rb->Width == 0 || rb->Height == 0) {
2054         simple_mtx_unlock(&ctx->Shared->Mutex);
2055         return MESA_GLINTEROP_INVALID_OBJECT;
2056      }
2057
2058      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2059       *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
2060       *    renderbuffer object."
2061       */
2062      if (rb->NumSamples > 1) {
2063         simple_mtx_unlock(&ctx->Shared->Mutex);
2064         return MESA_GLINTEROP_INVALID_OPERATION;
2065      }
2066
2067      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2068       *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
2069       *    required by the OpenCL implementation on the device."
2070       */
2071      res = rb->texture;
2072      if (!res) {
2073         simple_mtx_unlock(&ctx->Shared->Mutex);
2074         return MESA_GLINTEROP_OUT_OF_RESOURCES;
2075      }
2076
2077      out->internal_format = rb->InternalFormat;
2078      out->view_minlevel = 0;
2079      out->view_numlevels = 1;
2080      out->view_minlayer = 0;
2081      out->view_numlayers = 1;
2082   } else {
2083      /* Texture objects.
2084       *
2085       * The error checking is based on the documentation of
2086       * clCreateFromGLTexture from OpenCL 2.0 SDK.
2087       */
2088      struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
2089
2090      if (obj)
2091         _mesa_test_texobj_completeness(ctx, obj);
2092
2093      /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
2094       *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
2095       *    type matches texture_target, if the specified miplevel of texture
2096       *    is not defined, or if the width or height of the specified
2097       *    miplevel is zero or if the GL texture object is incomplete."
2098       */
2099      if (!obj ||
2100          obj->Target != target ||
2101          !obj->_BaseComplete ||
2102          (in->miplevel > 0 && !obj->_MipmapComplete)) {
2103         simple_mtx_unlock(&ctx->Shared->Mutex);
2104         return MESA_GLINTEROP_INVALID_OBJECT;
2105      }
2106
2107      if (target == GL_TEXTURE_BUFFER) {
2108         struct gl_buffer_object *stBuf =
2109            obj->BufferObject;
2110
2111         if (!stBuf || !stBuf->buffer) {
2112            /* this shouldn't happen */
2113            simple_mtx_unlock(&ctx->Shared->Mutex);
2114            return MESA_GLINTEROP_INVALID_OBJECT;
2115         }
2116         res = stBuf->buffer;
2117
2118         out->internal_format = obj->BufferObjectFormat;
2119         out->buf_offset = obj->BufferOffset;
2120         out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
2121                                                 obj->BufferSize;
2122
2123         obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
2124      } else {
2125         /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
2126          *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
2127          *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
2128          *    implementations); or greater than the value of q (for both OpenGL
2129          *    and OpenGL ES). levelbase and q are defined for the texture in
2130          *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
2131          *    specification and section 3.7.10 of the OpenGL ES 2.0."
2132          */
2133         if (in->miplevel < obj->Attrib.BaseLevel || in->miplevel > obj->_MaxLevel) {
2134            simple_mtx_unlock(&ctx->Shared->Mutex);
2135            return MESA_GLINTEROP_INVALID_MIP_LEVEL;
2136         }
2137
2138         if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
2139            simple_mtx_unlock(&ctx->Shared->Mutex);
2140            return MESA_GLINTEROP_OUT_OF_RESOURCES;
2141         }
2142
2143         res = st_get_texobj_resource(obj);
2144         if (!res) {
2145            /* Incomplete texture buffer object? This shouldn't really occur. */
2146            simple_mtx_unlock(&ctx->Shared->Mutex);
2147            return MESA_GLINTEROP_INVALID_OBJECT;
2148         }
2149
2150         out->internal_format = obj->Image[0][0]->InternalFormat;
2151         out->view_minlevel = obj->Attrib.MinLevel;
2152         out->view_numlevels = obj->Attrib.NumLevels;
2153         out->view_minlayer = obj->Attrib.MinLayer;
2154         out->view_numlayers = obj->Attrib.NumLayers;
2155      }
2156   }
2157
2158   /* Get the handle. */
2159   switch (in->access) {
2160   case MESA_GLINTEROP_ACCESS_READ_ONLY:
2161      usage = 0;
2162      break;
2163   case MESA_GLINTEROP_ACCESS_READ_WRITE:
2164   case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
2165      usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
2166      break;
2167   default:
2168      usage = 0;
2169   }
2170
2171   memset(&whandle, 0, sizeof(whandle));
2172   whandle.type = WINSYS_HANDLE_TYPE_FD;
2173
2174   success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
2175                                         usage);
2176   simple_mtx_unlock(&ctx->Shared->Mutex);
2177
2178   if (!success)
2179      return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
2180
2181   out->dmabuf_fd = whandle.handle;
2182   out->out_driver_data_written = 0;
2183
2184   if (res->target == PIPE_BUFFER)
2185      out->buf_offset += whandle.offset;
2186
2187   /* Instruct the caller that we support up-to version one of the interface */
2188   in->version = 1;
2189   out->version = 1;
2190
2191   return MESA_GLINTEROP_SUCCESS;
2192}
2193
2194static const __DRI2interopExtension dri2InteropExtension = {
2195   .base = { __DRI2_INTEROP, 1 },
2196   .query_device_info = dri2_interop_query_device_info,
2197   .export_object = dri2_interop_export_object
2198};
2199
2200/**
2201 * \brief the DRI2bufferDamageExtension set_damage_region method
2202 */
2203static void
2204dri2_set_damage_region(__DRIdrawable *dPriv, unsigned int nrects, int *rects)
2205{
2206   struct dri_drawable *drawable = dri_drawable(dPriv);
2207   struct pipe_box *boxes = NULL;
2208
2209   if (nrects) {
2210      boxes = CALLOC(nrects, sizeof(*boxes));
2211      assert(boxes);
2212
2213      for (unsigned int i = 0; i < nrects; i++) {
2214         int *rect = &rects[i * 4];
2215
2216         u_box_2d(rect[0], rect[1], rect[2], rect[3], &boxes[i]);
2217      }
2218   }
2219
2220   FREE(drawable->damage_rects);
2221   drawable->damage_rects = boxes;
2222   drawable->num_damage_rects = nrects;
2223
2224   /* Only apply the damage region if the BACK_LEFT texture is up-to-date. */
2225   if (drawable->texture_stamp == drawable->dPriv->lastStamp &&
2226       (drawable->texture_mask & (1 << ST_ATTACHMENT_BACK_LEFT))) {
2227      struct pipe_screen *screen = drawable->screen->base.screen;
2228      struct pipe_resource *resource;
2229
2230      if (drawable->stvis.samples > 1)
2231         resource = drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
2232      else
2233         resource = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
2234
2235      screen->set_damage_region(screen, resource,
2236                                drawable->num_damage_rects,
2237                                drawable->damage_rects);
2238   }
2239}
2240
2241static const __DRI2bufferDamageExtension dri2BufferDamageExtensionTempl = {
2242   .base = { __DRI2_BUFFER_DAMAGE, 1 },
2243};
2244
2245/**
2246 * \brief the DRI2ConfigQueryExtension configQueryb method
2247 */
2248static int
2249dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var,
2250                        unsigned char *val)
2251{
2252   struct dri_screen *screen = dri_screen(sPriv);
2253
2254   if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL))
2255      return dri2ConfigQueryExtension.configQueryb(sPriv, var, val);
2256
2257   *val = driQueryOptionb(&screen->dev->option_cache, var);
2258
2259   return 0;
2260}
2261
2262/**
2263 * \brief the DRI2ConfigQueryExtension configQueryi method
2264 */
2265static int
2266dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val)
2267{
2268   struct dri_screen *screen = dri_screen(sPriv);
2269
2270   if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) &&
2271       !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM))
2272      return dri2ConfigQueryExtension.configQueryi(sPriv, var, val);
2273
2274    *val = driQueryOptioni(&screen->dev->option_cache, var);
2275
2276    return 0;
2277}
2278
2279/**
2280 * \brief the DRI2ConfigQueryExtension configQueryf method
2281 */
2282static int
2283dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val)
2284{
2285   struct dri_screen *screen = dri_screen(sPriv);
2286
2287   if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT))
2288      return dri2ConfigQueryExtension.configQueryf(sPriv, var, val);
2289
2290    *val = driQueryOptionf(&screen->dev->option_cache, var);
2291
2292    return 0;
2293}
2294
2295/**
2296 * \brief the DRI2ConfigQueryExtension configQuerys method
2297 */
2298static int
2299dri2GalliumConfigQuerys(__DRIscreen *sPriv, const char *var, char **val)
2300{
2301   struct dri_screen *screen = dri_screen(sPriv);
2302
2303   if (!driCheckOption(&screen->dev->option_cache, var, DRI_STRING))
2304      return dri2ConfigQueryExtension.configQuerys(sPriv, var, val);
2305
2306    *val = driQueryOptionstr(&screen->dev->option_cache, var);
2307
2308    return 0;
2309}
2310
2311/**
2312 * \brief the DRI2ConfigQueryExtension struct.
2313 *
2314 * We first query the driver option cache. Then the dri2 option cache.
2315 */
2316static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = {
2317   .base = { __DRI2_CONFIG_QUERY, 2 },
2318
2319   .configQueryb        = dri2GalliumConfigQueryb,
2320   .configQueryi        = dri2GalliumConfigQueryi,
2321   .configQueryf        = dri2GalliumConfigQueryf,
2322   .configQuerys        = dri2GalliumConfigQuerys,
2323};
2324
2325/**
2326 * \brief the DRI2blobExtension set_cache_funcs method
2327 */
2328static void
2329set_blob_cache_funcs(__DRIscreen *sPriv, __DRIblobCacheSet set,
2330                     __DRIblobCacheGet get)
2331{
2332   struct dri_screen *screen = dri_screen(sPriv);
2333   struct pipe_screen *pscreen = screen->base.screen;
2334
2335   if (!pscreen->get_disk_shader_cache)
2336      return;
2337
2338   struct disk_cache *cache = pscreen->get_disk_shader_cache(pscreen);
2339
2340   if (!cache)
2341      return;
2342
2343   disk_cache_set_callbacks(cache, set, get);
2344}
2345
2346static const __DRI2blobExtension driBlobExtension = {
2347   .base = { __DRI2_BLOB, 1 },
2348   .set_cache_funcs = set_blob_cache_funcs
2349};
2350
2351static const __DRImutableRenderBufferDriverExtension driMutableRenderBufferExtension = {
2352   .base = { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1 },
2353};
2354
2355/*
2356 * Backend function init_screen.
2357 */
2358
2359static const __DRIextension *dri_screen_extensions_base[] = {
2360   &driTexBufferExtension.base,
2361   &dri2FlushExtension.base,
2362   &dri2RendererQueryExtension.base,
2363   &dri2GalliumConfigQueryExtension.base,
2364   &dri2ThrottleExtension.base,
2365   &dri2FenceExtension.base,
2366   &dri2InteropExtension.base,
2367   &driBlobExtension.base,
2368   &driMutableRenderBufferExtension.base,
2369   &dri2FlushControlExtension.base,
2370};
2371
2372/**
2373 * Set up the DRI extension list for this screen based on its underlying
2374 * gallium screen's capabilities.
2375 */
2376static void
2377dri2_init_screen_extensions(struct dri_screen *screen,
2378                            struct pipe_screen *pscreen,
2379                            bool is_kms_screen)
2380{
2381   const __DRIextension **nExt;
2382
2383   STATIC_ASSERT(sizeof(screen->screen_extensions) >=
2384                 sizeof(dri_screen_extensions_base));
2385   memcpy(&screen->screen_extensions, dri_screen_extensions_base,
2386          sizeof(dri_screen_extensions_base));
2387   screen->sPriv->extensions = screen->screen_extensions;
2388
2389   /* Point nExt at the end of the extension list */
2390   nExt = &screen->screen_extensions[ARRAY_SIZE(dri_screen_extensions_base)];
2391
2392   screen->image_extension = dri2ImageExtensionTempl;
2393   if (pscreen->resource_create_with_modifiers) {
2394      screen->image_extension.createImageWithModifiers =
2395         dri2_create_image_with_modifiers;
2396      screen->image_extension.createImageWithModifiers2 =
2397         dri2_create_image_with_modifiers2;
2398   }
2399
2400   if (pscreen->get_param(pscreen, PIPE_CAP_NATIVE_FENCE_FD)) {
2401      screen->image_extension.setInFenceFd = dri2_set_in_fence_fd;
2402   }
2403
2404   if (pscreen->get_param(pscreen, PIPE_CAP_DMABUF)) {
2405      uint64_t cap;
2406
2407      if (drmGetCap(screen->sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
2408          (cap & DRM_PRIME_CAP_IMPORT)) {
2409         screen->image_extension.createImageFromFds = dri2_from_fds;
2410         screen->image_extension.createImageFromFds2 = dri2_from_fds2;
2411         screen->image_extension.createImageFromDmaBufs = dri2_from_dma_bufs;
2412         screen->image_extension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
2413         screen->image_extension.createImageFromDmaBufs3 = dri2_from_dma_bufs3;
2414         screen->image_extension.queryDmaBufFormats =
2415            dri2_query_dma_buf_formats;
2416         screen->image_extension.queryDmaBufModifiers =
2417            dri2_query_dma_buf_modifiers;
2418         if (!is_kms_screen) {
2419            screen->image_extension.queryDmaBufFormatModifierAttribs =
2420               dri2_query_dma_buf_format_modifier_attribs;
2421         }
2422      }
2423   }
2424   *nExt++ = &screen->image_extension.base;
2425
2426   if (!is_kms_screen) {
2427      screen->buffer_damage_extension = dri2BufferDamageExtensionTempl;
2428      if (pscreen->set_damage_region)
2429         screen->buffer_damage_extension.set_damage_region =
2430            dri2_set_damage_region;
2431      *nExt++ = &screen->buffer_damage_extension.base;
2432
2433      if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {
2434         *nExt++ = &dri2Robustness.base;
2435         screen->has_reset_status_query = true;
2436      }
2437   }
2438
2439   /* Ensure the extension list didn't overrun its buffer and is still
2440    * NULL-terminated */
2441   assert(nExt - screen->screen_extensions <=
2442          ARRAY_SIZE(screen->screen_extensions) - 1);
2443   assert(!*nExt);
2444}
2445
2446/**
2447 * This is the driver specific part of the createNewScreen entry point.
2448 *
2449 * Returns the struct gl_config supported by this driver.
2450 */
2451static const __DRIconfig **
2452dri2_init_screen(__DRIscreen * sPriv)
2453{
2454   const __DRIconfig **configs;
2455   struct dri_screen *screen;
2456   struct pipe_screen *pscreen = NULL;
2457
2458   screen = CALLOC_STRUCT(dri_screen);
2459   if (!screen)
2460      return NULL;
2461
2462   screen->sPriv = sPriv;
2463   screen->fd = sPriv->fd;
2464   (void) mtx_init(&screen->opencl_func_mutex, mtx_plain);
2465
2466   sPriv->driverPrivate = (void *)screen;
2467
2468   if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) {
2469      pscreen = pipe_loader_create_screen(screen->dev);
2470      dri_init_options(screen);
2471   }
2472
2473   if (!pscreen)
2474       goto release_pipe;
2475
2476   screen->throttle = pscreen->get_param(pscreen, PIPE_CAP_THROTTLE);
2477
2478   dri2_init_screen_extensions(screen, pscreen, false);
2479
2480   configs = dri_init_screen_helper(screen, pscreen);
2481   if (!configs)
2482      goto destroy_screen;
2483
2484   screen->can_share_buffer = true;
2485   screen->auto_fake_front = dri_with_format(sPriv);
2486   screen->lookup_egl_image = dri2_lookup_egl_image;
2487
2488   const __DRIimageLookupExtension *loader = sPriv->dri2.image;
2489   if (loader &&
2490       loader->base.version >= 2 &&
2491       loader->validateEGLImage &&
2492       loader->lookupEGLImageValidated) {
2493      screen->validate_egl_image = dri2_validate_egl_image;
2494      screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated;
2495   }
2496
2497   return configs;
2498
2499destroy_screen:
2500   dri_destroy_screen_helper(screen);
2501
2502release_pipe:
2503   if (screen->dev)
2504      pipe_loader_release(&screen->dev, 1);
2505
2506   FREE(screen);
2507   return NULL;
2508}
2509
2510/**
2511 * This is the driver specific part of the createNewScreen entry point.
2512 *
2513 * Returns the struct gl_config supported by this driver.
2514 */
2515static const __DRIconfig **
2516dri_swrast_kms_init_screen(__DRIscreen * sPriv)
2517{
2518#if defined(GALLIUM_SOFTPIPE)
2519   const __DRIconfig **configs;
2520   struct dri_screen *screen;
2521   struct pipe_screen *pscreen = NULL;
2522
2523   screen = CALLOC_STRUCT(dri_screen);
2524   if (!screen)
2525      return NULL;
2526
2527   screen->sPriv = sPriv;
2528   screen->fd = sPriv->fd;
2529
2530   sPriv->driverPrivate = (void *)screen;
2531
2532#ifdef HAVE_DRISW_KMS
2533   if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) {
2534      pscreen = pipe_loader_create_screen(screen->dev);
2535      dri_init_options(screen);
2536   }
2537#endif
2538
2539   if (!pscreen)
2540       goto release_pipe;
2541
2542   dri2_init_screen_extensions(screen, pscreen, true);
2543
2544   configs = dri_init_screen_helper(screen, pscreen);
2545   if (!configs)
2546      goto destroy_screen;
2547
2548   screen->can_share_buffer = false;
2549   screen->auto_fake_front = dri_with_format(sPriv);
2550   screen->lookup_egl_image = dri2_lookup_egl_image;
2551
2552   const __DRIimageLookupExtension *loader = sPriv->dri2.image;
2553   if (loader &&
2554       loader->base.version >= 2 &&
2555       loader->validateEGLImage &&
2556       loader->lookupEGLImageValidated) {
2557      screen->validate_egl_image = dri2_validate_egl_image;
2558      screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated;
2559   }
2560
2561   return configs;
2562
2563destroy_screen:
2564   dri_destroy_screen_helper(screen);
2565
2566release_pipe:
2567   if (screen->dev)
2568      pipe_loader_release(&screen->dev, 1);
2569
2570   FREE(screen);
2571#endif // GALLIUM_SOFTPIPE
2572   return NULL;
2573}
2574
2575static boolean
2576dri2_create_buffer(__DRIscreen * sPriv,
2577                   __DRIdrawable * dPriv,
2578                   const struct gl_config * visual, boolean isPixmap)
2579{
2580   struct dri_drawable *drawable = NULL;
2581
2582   if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
2583      return FALSE;
2584
2585   drawable = dPriv->driverPrivate;
2586
2587   drawable->allocate_textures = dri2_allocate_textures;
2588   drawable->flush_frontbuffer = dri2_flush_frontbuffer;
2589   drawable->update_tex_buffer = dri2_update_tex_buffer;
2590   drawable->flush_swapbuffers = dri2_flush_swapbuffers;
2591
2592   return TRUE;
2593}
2594
2595/**
2596 * DRI driver virtual function table.
2597 *
2598 * DRI versions differ in their implementation of init_screen and swap_buffers.
2599 */
2600const struct __DriverAPIRec galliumdrm_driver_api = {
2601   .InitScreen = dri2_init_screen,
2602   .DestroyScreen = dri_destroy_screen,
2603   .CreateBuffer = dri2_create_buffer,
2604   .DestroyBuffer = dri_destroy_buffer,
2605
2606   .AllocateBuffer = dri2_allocate_buffer,
2607   .ReleaseBuffer  = dri2_release_buffer,
2608};
2609
2610static const struct __DRIDriverVtableExtensionRec galliumdrm_vtable = {
2611   .base = { __DRI_DRIVER_VTABLE, 1 },
2612   .vtable = &galliumdrm_driver_api,
2613};
2614
2615/**
2616 * DRI driver virtual function table.
2617 *
2618 * KMS/DRM version of the DriverAPI above sporting a different InitScreen
2619 * hook. The latter is used to explicitly initialise the kms_swrast driver
2620 * rather than selecting the approapriate driver as suggested by the loader.
2621 */
2622const struct __DriverAPIRec dri_swrast_kms_driver_api = {
2623   .InitScreen = dri_swrast_kms_init_screen,
2624   .DestroyScreen = dri_destroy_screen,
2625   .CreateBuffer = dri2_create_buffer,
2626   .DestroyBuffer = dri_destroy_buffer,
2627
2628   .AllocateBuffer = dri2_allocate_buffer,
2629   .ReleaseBuffer  = dri2_release_buffer,
2630};
2631
2632/* This is the table of extensions that the loader will dlsym() for. */
2633const __DRIextension *galliumdrm_driver_extensions[] = {
2634    &driCoreExtension.base,
2635    &driImageDriverExtension.base,
2636    &driDRI2Extension.base,
2637    &gallium_config_options.base,
2638    &galliumdrm_vtable.base,
2639    NULL
2640};
2641
2642static const struct __DRIDriverVtableExtensionRec dri_swrast_kms_vtable = {
2643   .base = { __DRI_DRIVER_VTABLE, 1 },
2644   .vtable = &dri_swrast_kms_driver_api,
2645};
2646
2647const __DRIextension *dri_swrast_kms_driver_extensions[] = {
2648    &driCoreExtension.base,
2649    &driImageDriverExtension.base,
2650    &swkmsDRI2Extension.base,
2651    &gallium_config_options.base,
2652    &dri_swrast_kms_vtable.base,
2653    NULL
2654};
2655
2656/* vim: set sw=3 ts=8 sts=3 expandtab: */
2657