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/u_memory.h"
34#include "util/u_inlines.h"
35#include "util/u_format.h"
36#include "util/u_debug.h"
37#include "state_tracker/drm_driver.h"
38#include "state_tracker/st_cb_bufferobjects.h"
39#include "state_tracker/st_cb_fbo.h"
40#include "state_tracker/st_cb_texture.h"
41#include "state_tracker/st_texture.h"
42#include "state_tracker/st_context.h"
43#include "pipe-loader/pipe_loader.h"
44#include "main/bufferobj.h"
45#include "main/texobj.h"
46
47#include "dri_util.h"
48
49#include "dri_helpers.h"
50#include "dri_drawable.h"
51#include "dri_query_renderer.h"
52
53#include "drm-uapi/drm_fourcc.h"
54
55struct dri2_buffer
56{
57   __DRIbuffer base;
58   struct pipe_resource *resource;
59};
60
61static inline struct dri2_buffer *
62dri2_buffer(__DRIbuffer * driBufferPriv)
63{
64   return (struct dri2_buffer *) driBufferPriv;
65}
66
67struct dri2_format_mapping {
68   int dri_fourcc;
69   int dri_format;
70   int dri_components;
71   enum pipe_format pipe_format;
72};
73
74static const struct dri2_format_mapping dri2_format_table[] = {
75      { __DRI_IMAGE_FOURCC_ARGB2101010,   __DRI_IMAGE_FORMAT_ARGB2101010,
76        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B10G10R10A2_UNORM },
77      { __DRI_IMAGE_FOURCC_XRGB2101010,   __DRI_IMAGE_FORMAT_XRGB2101010,
78        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B10G10R10X2_UNORM },
79      { __DRI_IMAGE_FOURCC_ABGR2101010,   __DRI_IMAGE_FORMAT_ABGR2101010,
80        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_R10G10B10A2_UNORM },
81      { __DRI_IMAGE_FOURCC_XBGR2101010,   __DRI_IMAGE_FORMAT_XBGR2101010,
82        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_R10G10B10X2_UNORM },
83      { __DRI_IMAGE_FOURCC_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
84        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM },
85      { __DRI_IMAGE_FOURCC_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
86        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM },
87      { __DRI_IMAGE_FOURCC_SARGB8888,     __DRI_IMAGE_FORMAT_SARGB8,
88        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_SRGB },
89      { __DRI_IMAGE_FOURCC_XRGB8888,      __DRI_IMAGE_FORMAT_XRGB8888,
90        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_BGRX8888_UNORM },
91      { __DRI_IMAGE_FOURCC_XBGR8888,      __DRI_IMAGE_FORMAT_XBGR8888,
92        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_RGBX8888_UNORM },
93      { __DRI_IMAGE_FOURCC_ARGB1555,      __DRI_IMAGE_FORMAT_ARGB1555,
94        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B5G5R5A1_UNORM },
95      { __DRI_IMAGE_FOURCC_RGB565,        __DRI_IMAGE_FORMAT_RGB565,
96        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B5G6R5_UNORM },
97      { __DRI_IMAGE_FOURCC_R8,            __DRI_IMAGE_FORMAT_R8,
98        __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R8_UNORM },
99      { __DRI_IMAGE_FOURCC_R16,           __DRI_IMAGE_FORMAT_R16,
100        __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R16_UNORM },
101      { __DRI_IMAGE_FOURCC_GR88,          __DRI_IMAGE_FORMAT_GR88,
102        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM },
103      { __DRI_IMAGE_FOURCC_GR1616,        __DRI_IMAGE_FORMAT_GR88,
104        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG1616_UNORM },
105      { __DRI_IMAGE_FOURCC_YUV420,        __DRI_IMAGE_FORMAT_NONE,
106        __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV },
107      { __DRI_IMAGE_FOURCC_YVU420,        __DRI_IMAGE_FORMAT_NONE,
108        __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_YV12 },
109      { __DRI_IMAGE_FOURCC_NV12,          __DRI_IMAGE_FORMAT_NONE,
110        __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_NV12 },
111      { __DRI_IMAGE_FOURCC_YUYV,          __DRI_IMAGE_FORMAT_YUYV,
112        __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_YUYV },
113      { __DRI_IMAGE_FOURCC_UYVY,          __DRI_IMAGE_FORMAT_UYVY,
114        __DRI_IMAGE_COMPONENTS_Y_UXVX,    PIPE_FORMAT_UYVY },
115};
116
117static const struct dri2_format_mapping *
118dri2_get_mapping_by_fourcc(int fourcc) {
119   for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
120      if (dri2_format_table[i].dri_fourcc == fourcc)
121               return &dri2_format_table[i];
122   }
123
124   return NULL;
125}
126
127static const struct dri2_format_mapping *
128dri2_get_mapping_by_format(int format) {
129   for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
130      if (dri2_format_table[i].dri_format == format)
131               return &dri2_format_table[i];
132   }
133
134   return NULL;
135}
136
137/**
138 * DRI2 flush extension.
139 */
140static void
141dri2_flush_drawable(__DRIdrawable *dPriv)
142{
143   dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1);
144}
145
146static void
147dri2_invalidate_drawable(__DRIdrawable *dPriv)
148{
149   struct dri_drawable *drawable = dri_drawable(dPriv);
150
151   dri2InvalidateDrawable(dPriv);
152   drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
153   drawable->texture_mask = 0;
154
155   p_atomic_inc(&drawable->base.stamp);
156}
157
158static const __DRI2flushExtension dri2FlushExtension = {
159    .base = { __DRI2_FLUSH, 4 },
160
161    .flush                = dri2_flush_drawable,
162    .invalidate           = dri2_invalidate_drawable,
163    .flush_with_flags     = dri_flush,
164};
165
166/**
167 * Retrieve __DRIbuffer from the DRI loader.
168 */
169static __DRIbuffer *
170dri2_drawable_get_buffers(struct dri_drawable *drawable,
171                          const enum st_attachment_type *atts,
172                          unsigned *count)
173{
174   __DRIdrawable *dri_drawable = drawable->dPriv;
175   const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
176   boolean with_format;
177   __DRIbuffer *buffers;
178   int num_buffers;
179   unsigned attachments[10];
180   unsigned num_attachments, i;
181
182   assert(loader);
183   with_format = dri_with_format(drawable->sPriv);
184
185   num_attachments = 0;
186
187   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
188   if (!with_format)
189      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
190
191   for (i = 0; i < *count; i++) {
192      enum pipe_format format;
193      unsigned bind;
194      int att, depth;
195
196      dri_drawable_get_format(drawable, atts[i], &format, &bind);
197      if (format == PIPE_FORMAT_NONE)
198         continue;
199
200      switch (atts[i]) {
201      case ST_ATTACHMENT_FRONT_LEFT:
202         /* already added */
203         if (!with_format)
204            continue;
205         att = __DRI_BUFFER_FRONT_LEFT;
206         break;
207      case ST_ATTACHMENT_BACK_LEFT:
208         att = __DRI_BUFFER_BACK_LEFT;
209         break;
210      case ST_ATTACHMENT_FRONT_RIGHT:
211         att = __DRI_BUFFER_FRONT_RIGHT;
212         break;
213      case ST_ATTACHMENT_BACK_RIGHT:
214         att = __DRI_BUFFER_BACK_RIGHT;
215         break;
216      default:
217         continue;
218      }
219
220      /*
221       * In this switch statement we must support all formats that
222       * may occur as the stvis->color_format.
223       */
224      switch(format) {
225      case PIPE_FORMAT_B10G10R10A2_UNORM:
226      case PIPE_FORMAT_R10G10B10A2_UNORM:
227      case PIPE_FORMAT_BGRA8888_UNORM:
228      case PIPE_FORMAT_RGBA8888_UNORM:
229	 depth = 32;
230	 break;
231      case PIPE_FORMAT_R10G10B10X2_UNORM:
232      case PIPE_FORMAT_B10G10R10X2_UNORM:
233         depth = 30;
234         break;
235      case PIPE_FORMAT_BGRX8888_UNORM:
236      case PIPE_FORMAT_RGBX8888_UNORM:
237	 depth = 24;
238	 break;
239      case PIPE_FORMAT_B5G6R5_UNORM:
240	 depth = 16;
241	 break;
242      default:
243	 depth = util_format_get_blocksizebits(format);
244	 assert(!"Unexpected format in dri2_drawable_get_buffers()");
245      }
246
247      attachments[num_attachments++] = att;
248      if (with_format) {
249         attachments[num_attachments++] = depth;
250      }
251   }
252
253   if (with_format) {
254      num_attachments /= 2;
255      buffers = loader->getBuffersWithFormat(dri_drawable,
256            &dri_drawable->w, &dri_drawable->h,
257            attachments, num_attachments,
258            &num_buffers, dri_drawable->loaderPrivate);
259   }
260   else {
261      buffers = loader->getBuffers(dri_drawable,
262            &dri_drawable->w, &dri_drawable->h,
263            attachments, num_attachments,
264            &num_buffers, dri_drawable->loaderPrivate);
265   }
266
267   if (buffers)
268      *count = num_buffers;
269
270   return buffers;
271}
272
273static bool
274dri_image_drawable_get_buffers(struct dri_drawable *drawable,
275                               struct __DRIimageList *images,
276                               const enum st_attachment_type *statts,
277                               unsigned statts_count)
278{
279   __DRIdrawable *dPriv = drawable->dPriv;
280   __DRIscreen *sPriv = drawable->sPriv;
281   unsigned int image_format = __DRI_IMAGE_FORMAT_NONE;
282   enum pipe_format pf;
283   uint32_t buffer_mask = 0;
284   unsigned i, bind;
285
286   for (i = 0; i < statts_count; i++) {
287      dri_drawable_get_format(drawable, statts[i], &pf, &bind);
288      if (pf == PIPE_FORMAT_NONE)
289         continue;
290
291      switch (statts[i]) {
292      case ST_ATTACHMENT_FRONT_LEFT:
293         buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
294         break;
295      case ST_ATTACHMENT_BACK_LEFT:
296         buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
297         break;
298      default:
299         continue;
300      }
301
302      switch (pf) {
303      case PIPE_FORMAT_B5G5R5A1_UNORM:
304         image_format = __DRI_IMAGE_FORMAT_ARGB1555;
305         break;
306      case PIPE_FORMAT_B5G6R5_UNORM:
307         image_format = __DRI_IMAGE_FORMAT_RGB565;
308         break;
309      case PIPE_FORMAT_BGRX8888_UNORM:
310         image_format = __DRI_IMAGE_FORMAT_XRGB8888;
311         break;
312      case PIPE_FORMAT_BGRA8888_UNORM:
313         image_format = __DRI_IMAGE_FORMAT_ARGB8888;
314         break;
315      case PIPE_FORMAT_RGBX8888_UNORM:
316         image_format = __DRI_IMAGE_FORMAT_XBGR8888;
317         break;
318      case PIPE_FORMAT_RGBA8888_UNORM:
319         image_format = __DRI_IMAGE_FORMAT_ABGR8888;
320         break;
321      case PIPE_FORMAT_B10G10R10X2_UNORM:
322         image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
323         break;
324      case PIPE_FORMAT_B10G10R10A2_UNORM:
325         image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
326         break;
327      case PIPE_FORMAT_R10G10B10X2_UNORM:
328         image_format = __DRI_IMAGE_FORMAT_XBGR2101010;
329         break;
330      case PIPE_FORMAT_R10G10B10A2_UNORM:
331         image_format = __DRI_IMAGE_FORMAT_ABGR2101010;
332         break;
333      default:
334         image_format = __DRI_IMAGE_FORMAT_NONE;
335         break;
336      }
337   }
338
339   return (*sPriv->image.loader->getBuffers) (dPriv, image_format,
340                                       (uint32_t *) &drawable->base.stamp,
341                                       dPriv->loaderPrivate, buffer_mask,
342                                       images);
343}
344
345static __DRIbuffer *
346dri2_allocate_buffer(__DRIscreen *sPriv,
347                     unsigned attachment, unsigned format,
348                     int width, int height)
349{
350   struct dri_screen *screen = dri_screen(sPriv);
351   struct dri2_buffer *buffer;
352   struct pipe_resource templ;
353   enum pipe_format pf;
354   unsigned bind = 0;
355   struct winsys_handle whandle;
356
357   switch (attachment) {
358      case __DRI_BUFFER_FRONT_LEFT:
359      case __DRI_BUFFER_FAKE_FRONT_LEFT:
360         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
361         break;
362      case __DRI_BUFFER_BACK_LEFT:
363         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
364         break;
365      case __DRI_BUFFER_DEPTH:
366      case __DRI_BUFFER_DEPTH_STENCIL:
367      case __DRI_BUFFER_STENCIL:
368            bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
369         break;
370   }
371
372   /* because we get the handle and stride */
373   bind |= PIPE_BIND_SHARED;
374
375   switch (format) {
376      case 32:
377         pf = PIPE_FORMAT_BGRA8888_UNORM;
378         break;
379      case 30:
380         pf = PIPE_FORMAT_B10G10R10X2_UNORM;
381         break;
382      case 24:
383         pf = PIPE_FORMAT_BGRX8888_UNORM;
384         break;
385      case 16:
386         pf = PIPE_FORMAT_Z16_UNORM;
387         break;
388      default:
389         return NULL;
390   }
391
392   buffer = CALLOC_STRUCT(dri2_buffer);
393   if (!buffer)
394      return NULL;
395
396   memset(&templ, 0, sizeof(templ));
397   templ.bind = bind;
398   templ.format = pf;
399   templ.target = PIPE_TEXTURE_2D;
400   templ.last_level = 0;
401   templ.width0 = width;
402   templ.height0 = height;
403   templ.depth0 = 1;
404   templ.array_size = 1;
405
406   buffer->resource =
407      screen->base.screen->resource_create(screen->base.screen, &templ);
408   if (!buffer->resource) {
409      FREE(buffer);
410      return NULL;
411   }
412
413   memset(&whandle, 0, sizeof(whandle));
414   if (screen->can_share_buffer)
415      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
416   else
417      whandle.type = WINSYS_HANDLE_TYPE_KMS;
418
419   screen->base.screen->resource_get_handle(screen->base.screen, NULL,
420         buffer->resource, &whandle,
421         PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
422
423   buffer->base.attachment = attachment;
424   buffer->base.name = whandle.handle;
425   buffer->base.cpp = util_format_get_blocksize(pf);
426   buffer->base.pitch = whandle.stride;
427
428   return &buffer->base;
429}
430
431static void
432dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
433{
434   struct dri2_buffer *buffer = dri2_buffer(bPriv);
435
436   pipe_resource_reference(&buffer->resource, NULL);
437   FREE(buffer);
438}
439
440/*
441 * Backend functions for st_framebuffer interface.
442 */
443
444static void
445dri2_allocate_textures(struct dri_context *ctx,
446                       struct dri_drawable *drawable,
447                       const enum st_attachment_type *statts,
448                       unsigned statts_count)
449{
450   __DRIscreen *sPriv = drawable->sPriv;
451   __DRIdrawable *dri_drawable = drawable->dPriv;
452   struct dri_screen *screen = dri_screen(sPriv);
453   struct pipe_resource templ;
454   boolean alloc_depthstencil = FALSE;
455   unsigned i, j, bind;
456   const __DRIimageLoaderExtension *image = sPriv->image.loader;
457   /* Image specific variables */
458   struct __DRIimageList images;
459   /* Dri2 specific variables */
460   __DRIbuffer *buffers = NULL;
461   struct winsys_handle whandle;
462   unsigned num_buffers = statts_count;
463
464   /* First get the buffers from the loader */
465   if (image) {
466      if (!dri_image_drawable_get_buffers(drawable, &images,
467                                          statts, statts_count))
468         return;
469   }
470   else {
471      buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
472      if (!buffers || (drawable->old_num == num_buffers &&
473                       drawable->old_w == dri_drawable->w &&
474                       drawable->old_h == dri_drawable->h &&
475                       memcmp(drawable->old, buffers,
476                              sizeof(__DRIbuffer) * num_buffers) == 0))
477         return;
478   }
479
480   /* Second clean useless resources*/
481
482   /* See if we need a depth-stencil buffer. */
483   for (i = 0; i < statts_count; i++) {
484      if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
485         alloc_depthstencil = TRUE;
486         break;
487      }
488   }
489
490   /* Delete the resources we won't need. */
491   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
492      /* Don't delete the depth-stencil buffer, we can reuse it. */
493      if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil)
494         continue;
495
496      /* Flush the texture before unreferencing, so that other clients can
497       * see what the driver has rendered.
498       */
499      if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) {
500         struct pipe_context *pipe = ctx->st->pipe;
501         pipe->flush_resource(pipe, drawable->textures[i]);
502      }
503
504      pipe_resource_reference(&drawable->textures[i], NULL);
505   }
506
507   if (drawable->stvis.samples > 1) {
508      for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
509         boolean del = TRUE;
510
511         /* Don't delete MSAA resources for the attachments which are enabled,
512          * we can reuse them. */
513         for (j = 0; j < statts_count; j++) {
514            if (i == statts[j]) {
515               del = FALSE;
516               break;
517            }
518         }
519
520         if (del) {
521            pipe_resource_reference(&drawable->msaa_textures[i], NULL);
522         }
523      }
524   }
525
526   /* Third use the buffers retrieved to fill the drawable info */
527
528   memset(&templ, 0, sizeof(templ));
529   templ.target = screen->target;
530   templ.last_level = 0;
531   templ.depth0 = 1;
532   templ.array_size = 1;
533
534   if (image) {
535      if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
536         struct pipe_resource **buf =
537            &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
538         struct pipe_resource *texture = images.front->texture;
539
540         dri_drawable->w = texture->width0;
541         dri_drawable->h = texture->height0;
542
543         pipe_resource_reference(buf, texture);
544      }
545
546      if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
547         struct pipe_resource **buf =
548            &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
549         struct pipe_resource *texture = images.back->texture;
550
551         dri_drawable->w = texture->width0;
552         dri_drawable->h = texture->height0;
553
554         pipe_resource_reference(buf, texture);
555      }
556
557      /* Note: if there is both a back and a front buffer,
558       * then they have the same size.
559       */
560      templ.width0 = dri_drawable->w;
561      templ.height0 = dri_drawable->h;
562   }
563   else {
564      memset(&whandle, 0, sizeof(whandle));
565
566      /* Process DRI-provided buffers and get pipe_resources. */
567      for (i = 0; i < num_buffers; i++) {
568         __DRIbuffer *buf = &buffers[i];
569         enum st_attachment_type statt;
570         enum pipe_format format;
571
572         switch (buf->attachment) {
573         case __DRI_BUFFER_FRONT_LEFT:
574            if (!screen->auto_fake_front) {
575               continue; /* invalid attachment */
576            }
577            /* fallthrough */
578         case __DRI_BUFFER_FAKE_FRONT_LEFT:
579            statt = ST_ATTACHMENT_FRONT_LEFT;
580            break;
581         case __DRI_BUFFER_BACK_LEFT:
582            statt = ST_ATTACHMENT_BACK_LEFT;
583            break;
584         default:
585            continue; /* invalid attachment */
586         }
587
588         dri_drawable_get_format(drawable, statt, &format, &bind);
589         if (format == PIPE_FORMAT_NONE)
590            continue;
591
592         /* dri2_drawable_get_buffers has already filled dri_drawable->w
593          * and dri_drawable->h */
594         templ.width0 = dri_drawable->w;
595         templ.height0 = dri_drawable->h;
596         templ.format = format;
597         templ.bind = bind;
598         whandle.handle = buf->name;
599         whandle.stride = buf->pitch;
600         whandle.offset = 0;
601         whandle.modifier = DRM_FORMAT_MOD_INVALID;
602         if (screen->can_share_buffer)
603            whandle.type = WINSYS_HANDLE_TYPE_SHARED;
604         else
605            whandle.type = WINSYS_HANDLE_TYPE_KMS;
606         drawable->textures[statt] =
607            screen->base.screen->resource_from_handle(screen->base.screen,
608                  &templ, &whandle,
609                  PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
610         assert(drawable->textures[statt]);
611      }
612   }
613
614   /* Allocate private MSAA colorbuffers. */
615   if (drawable->stvis.samples > 1) {
616      for (i = 0; i < statts_count; i++) {
617         enum st_attachment_type statt = statts[i];
618
619         if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
620            continue;
621
622         if (drawable->textures[statt]) {
623            templ.format = drawable->textures[statt]->format;
624            templ.bind = drawable->textures[statt]->bind &
625                         ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
626            templ.nr_samples = drawable->stvis.samples;
627            templ.nr_storage_samples = drawable->stvis.samples;
628
629            /* Try to reuse the resource.
630             * (the other resource parameters should be constant)
631             */
632            if (!drawable->msaa_textures[statt] ||
633                drawable->msaa_textures[statt]->width0 != templ.width0 ||
634                drawable->msaa_textures[statt]->height0 != templ.height0) {
635               /* Allocate a new one. */
636               pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
637
638               drawable->msaa_textures[statt] =
639                  screen->base.screen->resource_create(screen->base.screen,
640                                                       &templ);
641               assert(drawable->msaa_textures[statt]);
642
643               /* If there are any MSAA resources, we should initialize them
644                * such that they contain the same data as the single-sample
645                * resources we just got from the X server.
646                *
647                * The reason for this is that the state tracker (and
648                * therefore the app) can access the MSAA resources only.
649                * The single-sample resources are not exposed
650                * to the state tracker.
651                *
652                */
653               dri_pipe_blit(ctx->st->pipe,
654                             drawable->msaa_textures[statt],
655                             drawable->textures[statt]);
656            }
657         }
658         else {
659            pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
660         }
661      }
662   }
663
664   /* Allocate a private depth-stencil buffer. */
665   if (alloc_depthstencil) {
666      enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
667      struct pipe_resource **zsbuf;
668      enum pipe_format format;
669      unsigned bind;
670
671      dri_drawable_get_format(drawable, statt, &format, &bind);
672
673      if (format) {
674         templ.format = format;
675         templ.bind = bind & ~PIPE_BIND_SHARED;
676
677         if (drawable->stvis.samples > 1) {
678            templ.nr_samples = drawable->stvis.samples;
679            templ.nr_storage_samples = drawable->stvis.samples;
680            zsbuf = &drawable->msaa_textures[statt];
681         }
682         else {
683            templ.nr_samples = 0;
684            templ.nr_storage_samples = 0;
685            zsbuf = &drawable->textures[statt];
686         }
687
688         /* Try to reuse the resource.
689          * (the other resource parameters should be constant)
690          */
691         if (!*zsbuf ||
692             (*zsbuf)->width0 != templ.width0 ||
693             (*zsbuf)->height0 != templ.height0) {
694            /* Allocate a new one. */
695            pipe_resource_reference(zsbuf, NULL);
696            *zsbuf = screen->base.screen->resource_create(screen->base.screen,
697                                                          &templ);
698            assert(*zsbuf);
699         }
700      }
701      else {
702         pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
703         pipe_resource_reference(&drawable->textures[statt], NULL);
704      }
705   }
706
707   /* For DRI2, we may get the same buffers again from the server.
708    * To prevent useless imports of gem names, drawable->old* is used
709    * to bypass the import if we get the same buffers. This doesn't apply
710    * to DRI3/Wayland, users of image.loader, since the buffer is managed
711    * by the client (no import), and the back buffer is going to change
712    * at every redraw.
713    */
714   if (!image) {
715      drawable->old_num = num_buffers;
716      drawable->old_w = dri_drawable->w;
717      drawable->old_h = dri_drawable->h;
718      memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
719   }
720}
721
722static void
723dri2_flush_frontbuffer(struct dri_context *ctx,
724                       struct dri_drawable *drawable,
725                       enum st_attachment_type statt)
726{
727   __DRIdrawable *dri_drawable = drawable->dPriv;
728   const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
729   const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
730   struct pipe_context *pipe = ctx->st->pipe;
731
732   if (statt != ST_ATTACHMENT_FRONT_LEFT)
733      return;
734
735   if (drawable->stvis.samples > 1) {
736      /* Resolve the front buffer. */
737      dri_pipe_blit(ctx->st->pipe,
738                    drawable->textures[ST_ATTACHMENT_FRONT_LEFT],
739                    drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]);
740   }
741
742   if (drawable->textures[ST_ATTACHMENT_FRONT_LEFT]) {
743      pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_FRONT_LEFT]);
744   }
745
746   pipe->flush(pipe, NULL, 0);
747
748   if (image) {
749      image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
750   }
751   else if (loader->flushFrontBuffer) {
752      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
753   }
754}
755
756/**
757 * The struct dri_drawable flush_swapbuffers callback
758 */
759static void
760dri2_flush_swapbuffers(struct dri_context *ctx,
761                       struct dri_drawable *drawable)
762{
763   __DRIdrawable *dri_drawable = drawable->dPriv;
764   const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
765
766   if (image && image->base.version >= 3 && image->flushSwapBuffers) {
767      image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate);
768   }
769}
770
771static void
772dri2_update_tex_buffer(struct dri_drawable *drawable,
773                       struct dri_context *ctx,
774                       struct pipe_resource *res)
775{
776   /* no-op */
777}
778
779static __DRIimage *
780dri2_create_image_from_winsys(__DRIscreen *_screen,
781                              int width, int height, enum pipe_format pf,
782                              int num_handles, struct winsys_handle *whandle,
783                              void *loaderPrivate)
784{
785   struct dri_screen *screen = dri_screen(_screen);
786   struct pipe_screen *pscreen = screen->base.screen;
787   __DRIimage *img;
788   struct pipe_resource templ;
789   unsigned tex_usage = 0;
790   int i;
791
792   if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
793                                    PIPE_BIND_RENDER_TARGET))
794      tex_usage |= PIPE_BIND_RENDER_TARGET;
795   if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
796                                    PIPE_BIND_SAMPLER_VIEW))
797      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
798
799   if (!tex_usage && util_format_is_yuv(pf)) {
800      /* YUV format sampling can be emulated by the Mesa state tracker by
801       * using multiple R8/RG88 samplers. So try to rewrite the pipe format.
802       */
803      pf = PIPE_FORMAT_R8_UNORM;
804
805      if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
806                                       PIPE_BIND_SAMPLER_VIEW))
807         tex_usage |= PIPE_BIND_SAMPLER_VIEW;
808   }
809
810   if (!tex_usage)
811      return NULL;
812
813   img = CALLOC_STRUCT(__DRIimageRec);
814   if (!img)
815      return NULL;
816
817   memset(&templ, 0, sizeof(templ));
818   templ.bind = tex_usage;
819   templ.target = screen->target;
820   templ.last_level = 0;
821   templ.depth0 = 1;
822   templ.array_size = 1;
823
824   for (i = num_handles - 1; i >= 0; i--) {
825      struct pipe_resource *tex;
826
827      /* TODO: something a lot less ugly */
828      switch (i) {
829      case 0:
830         templ.width0 = width;
831         templ.height0 = height;
832         templ.format = pf;
833         break;
834      case 1:
835         templ.width0 = width / 2;
836         templ.height0 = height / 2;
837         templ.format = (num_handles == 2) ?
838               PIPE_FORMAT_RG88_UNORM :   /* NV12, etc */
839               PIPE_FORMAT_R8_UNORM;      /* I420, etc */
840         break;
841      case 2:
842         templ.width0 = width / 2;
843         templ.height0 = height / 2;
844         templ.format = PIPE_FORMAT_R8_UNORM;
845         break;
846      default:
847         unreachable("too many planes!");
848      }
849
850      tex = pscreen->resource_from_handle(pscreen,
851            &templ, &whandle[i], PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
852      if (!tex) {
853         pipe_resource_reference(&img->texture, NULL);
854         FREE(img);
855         return NULL;
856      }
857
858      tex->next = img->texture;
859      img->texture = tex;
860   }
861
862   img->level = 0;
863   img->layer = 0;
864   img->use = 0;
865   img->loader_private = loaderPrivate;
866
867   return img;
868}
869
870static __DRIimage *
871dri2_create_image_from_name(__DRIscreen *_screen,
872                            int width, int height, int format,
873                            int name, int pitch, void *loaderPrivate)
874{
875   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
876   struct winsys_handle whandle;
877   __DRIimage *img;
878
879   if (!map)
880      return NULL;
881
882   memset(&whandle, 0, sizeof(whandle));
883   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
884   whandle.handle = name;
885   whandle.modifier = DRM_FORMAT_MOD_INVALID;
886
887   whandle.stride = pitch * util_format_get_blocksize(map->pipe_format);
888
889   img = dri2_create_image_from_winsys(_screen, width, height, map->pipe_format,
890                                       1, &whandle, loaderPrivate);
891
892   if (!img)
893      return NULL;
894
895   img->dri_components = map->dri_components;
896   img->dri_fourcc = map->dri_fourcc;
897   img->dri_format = map->dri_format;
898
899   return img;
900}
901
902static __DRIimage *
903dri2_create_image_from_fd(__DRIscreen *_screen,
904                          int width, int height, int fourcc,
905                          uint64_t modifier, int *fds, int num_fds,
906                          int *strides, int *offsets, unsigned *error,
907                          void *loaderPrivate)
908{
909   struct winsys_handle whandles[3];
910   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
911   __DRIimage *img = NULL;
912   unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
913   int expected_num_fds, i;
914
915   if (!map) {
916      err = __DRI_IMAGE_ERROR_BAD_MATCH;
917      goto exit;
918   }
919
920   switch (fourcc) {
921   case __DRI_IMAGE_FOURCC_YUV420:
922   case __DRI_IMAGE_FOURCC_YVU420:
923      expected_num_fds = 3;
924      break;
925   case __DRI_IMAGE_FOURCC_NV12:
926      expected_num_fds = 2;
927      break;
928   default:
929      expected_num_fds = 1;
930      break;
931   }
932
933   if (num_fds != expected_num_fds) {
934      err = __DRI_IMAGE_ERROR_BAD_MATCH;
935      goto exit;
936   }
937
938   memset(whandles, 0, sizeof(whandles));
939
940   for (i = 0; i < num_fds; i++) {
941      if (fds[i] < 0) {
942         err = __DRI_IMAGE_ERROR_BAD_ALLOC;
943         goto exit;
944      }
945
946      whandles[i].type = WINSYS_HANDLE_TYPE_FD;
947      whandles[i].handle = (unsigned)fds[i];
948      whandles[i].stride = (unsigned)strides[i];
949      whandles[i].offset = (unsigned)offsets[i];
950      whandles[i].modifier = modifier;
951   }
952
953   if (fourcc == __DRI_IMAGE_FOURCC_YVU420) {
954      /* convert to YUV420 by swapping 2nd and 3rd planes: */
955      struct winsys_handle tmp = whandles[1];
956      whandles[1] = whandles[2];
957      whandles[2] = tmp;
958      fourcc = __DRI_IMAGE_FOURCC_YUV420;
959      map = dri2_get_mapping_by_fourcc(fourcc);
960   }
961
962   img = dri2_create_image_from_winsys(_screen, width, height, map->pipe_format,
963                                       num_fds, whandles, loaderPrivate);
964   if(img == NULL) {
965      err = __DRI_IMAGE_ERROR_BAD_ALLOC;
966      goto exit;
967   }
968
969   img->dri_components = map->dri_components;
970   img->dri_fourcc = fourcc;
971   img->dri_format = map->dri_format;
972
973exit:
974   if (error)
975      *error = err;
976
977   return img;
978}
979
980static __DRIimage *
981dri2_create_image_common(__DRIscreen *_screen,
982                         int width, int height,
983                         int format, unsigned int use,
984                         const uint64_t *modifiers,
985                         const unsigned count,
986                         void *loaderPrivate)
987{
988   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
989   struct dri_screen *screen = dri_screen(_screen);
990   __DRIimage *img;
991   struct pipe_resource templ;
992   unsigned tex_usage;
993
994   if (!map)
995      return NULL;
996
997   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
998
999   if (use & __DRI_IMAGE_USE_SCANOUT)
1000      tex_usage |= PIPE_BIND_SCANOUT;
1001   if (use & __DRI_IMAGE_USE_SHARE)
1002      tex_usage |= PIPE_BIND_SHARED;
1003   if (use & __DRI_IMAGE_USE_LINEAR)
1004      tex_usage |= PIPE_BIND_LINEAR;
1005   if (use & __DRI_IMAGE_USE_CURSOR) {
1006      if (width != 64 || height != 64)
1007         return NULL;
1008      tex_usage |= PIPE_BIND_CURSOR;
1009   }
1010
1011   img = CALLOC_STRUCT(__DRIimageRec);
1012   if (!img)
1013      return NULL;
1014
1015   memset(&templ, 0, sizeof(templ));
1016   templ.bind = tex_usage;
1017   templ.format = map->pipe_format;
1018   templ.target = PIPE_TEXTURE_2D;
1019   templ.last_level = 0;
1020   templ.width0 = width;
1021   templ.height0 = height;
1022   templ.depth0 = 1;
1023   templ.array_size = 1;
1024
1025   if (modifiers)
1026      img->texture =
1027         screen->base.screen
1028            ->resource_create_with_modifiers(screen->base.screen,
1029                                             &templ,
1030                                             modifiers,
1031                                             count);
1032   else
1033      img->texture =
1034         screen->base.screen->resource_create(screen->base.screen, &templ);
1035   if (!img->texture) {
1036      FREE(img);
1037      return NULL;
1038   }
1039
1040   img->level = 0;
1041   img->layer = 0;
1042   img->dri_format = format;
1043   img->dri_fourcc = map->dri_fourcc;
1044   img->dri_components = 0;
1045   img->use = use;
1046
1047   img->loader_private = loaderPrivate;
1048   return img;
1049}
1050
1051static __DRIimage *
1052dri2_create_image(__DRIscreen *_screen,
1053                   int width, int height, int format,
1054                   unsigned int use, void *loaderPrivate)
1055{
1056   return dri2_create_image_common(_screen, width, height, format, use,
1057                                   NULL /* modifiers */, 0 /* count */,
1058                                   loaderPrivate);
1059}
1060
1061static __DRIimage *
1062dri2_create_image_with_modifiers(__DRIscreen *dri_screen,
1063                                 int width, int height, int format,
1064                                 const uint64_t *modifiers,
1065                                 const unsigned count,
1066                                 void *loaderPrivate)
1067{
1068   return dri2_create_image_common(dri_screen, width, height, format,
1069                                   __DRI_IMAGE_USE_SHARE, modifiers, count,
1070                                   loaderPrivate);
1071}
1072
1073static GLboolean
1074dri2_query_image(__DRIimage *image, int attrib, int *value)
1075{
1076   struct winsys_handle whandle;
1077   unsigned usage;
1078
1079   if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1080      usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1081   else
1082      usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1083
1084   memset(&whandle, 0, sizeof(whandle));
1085
1086   switch (attrib) {
1087   case __DRI_IMAGE_ATTRIB_STRIDE:
1088      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1089      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1090            NULL, image->texture, &whandle, usage))
1091         return GL_FALSE;
1092      *value = whandle.stride;
1093      return GL_TRUE;
1094   case __DRI_IMAGE_ATTRIB_OFFSET:
1095      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1096      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1097            NULL, image->texture, &whandle, usage))
1098         return GL_FALSE;
1099      *value = whandle.offset;
1100      return GL_TRUE;
1101   case __DRI_IMAGE_ATTRIB_HANDLE:
1102      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1103      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1104         NULL, image->texture, &whandle, usage))
1105         return GL_FALSE;
1106      *value = whandle.handle;
1107      return GL_TRUE;
1108   case __DRI_IMAGE_ATTRIB_NAME:
1109      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1110      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1111         NULL, image->texture, &whandle, usage))
1112         return GL_FALSE;
1113      *value = whandle.handle;
1114      return GL_TRUE;
1115   case __DRI_IMAGE_ATTRIB_FD:
1116      whandle.type= WINSYS_HANDLE_TYPE_FD;
1117      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1118            NULL, image->texture, &whandle, usage))
1119         return GL_FALSE;
1120
1121      *value = whandle.handle;
1122      return GL_TRUE;
1123   case __DRI_IMAGE_ATTRIB_FORMAT:
1124      *value = image->dri_format;
1125      return GL_TRUE;
1126   case __DRI_IMAGE_ATTRIB_WIDTH:
1127      *value = image->texture->width0;
1128      return GL_TRUE;
1129   case __DRI_IMAGE_ATTRIB_HEIGHT:
1130      *value = image->texture->height0;
1131      return GL_TRUE;
1132   case __DRI_IMAGE_ATTRIB_COMPONENTS:
1133      if (image->dri_components == 0)
1134         return GL_FALSE;
1135      *value = image->dri_components;
1136      return GL_TRUE;
1137   case __DRI_IMAGE_ATTRIB_FOURCC:
1138      if (image->dri_fourcc) {
1139         *value = image->dri_fourcc;
1140      } else {
1141         const struct dri2_format_mapping *map;
1142
1143         map = dri2_get_mapping_by_format(image->dri_format);
1144         if (!map)
1145            return GL_FALSE;
1146
1147         *value = map->dri_fourcc;
1148      }
1149      return GL_TRUE;
1150   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1151      *value = 1;
1152      return GL_TRUE;
1153   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1154      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1155      whandle.modifier = DRM_FORMAT_MOD_INVALID;
1156      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1157            NULL, image->texture, &whandle, usage))
1158         return GL_FALSE;
1159      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1160         return GL_FALSE;
1161      *value = (whandle.modifier >> 32) & 0xffffffff;
1162      return GL_TRUE;
1163   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1164      whandle.type = WINSYS_HANDLE_TYPE_KMS;
1165      whandle.modifier = DRM_FORMAT_MOD_INVALID;
1166      if (!image->texture->screen->resource_get_handle(image->texture->screen,
1167            NULL, image->texture, &whandle, usage))
1168         return GL_FALSE;
1169      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1170         return GL_FALSE;
1171      *value = whandle.modifier & 0xffffffff;
1172      return GL_TRUE;
1173   default:
1174      return GL_FALSE;
1175   }
1176}
1177
1178static __DRIimage *
1179dri2_dup_image(__DRIimage *image, void *loaderPrivate)
1180{
1181   __DRIimage *img;
1182
1183   img = CALLOC_STRUCT(__DRIimageRec);
1184   if (!img)
1185      return NULL;
1186
1187   img->texture = NULL;
1188   pipe_resource_reference(&img->texture, image->texture);
1189   img->level = image->level;
1190   img->layer = image->layer;
1191   img->dri_format = image->dri_format;
1192   /* This should be 0 for sub images, but dup is also used for base images. */
1193   img->dri_components = image->dri_components;
1194   img->loader_private = loaderPrivate;
1195
1196   return img;
1197}
1198
1199static GLboolean
1200dri2_validate_usage(__DRIimage *image, unsigned int use)
1201{
1202   if (!image || !image->texture)
1203      return false;
1204
1205   struct pipe_screen *screen = image->texture->screen;
1206   if (!screen->check_resource_capability)
1207      return true;
1208
1209   /* We don't want to check these:
1210    *   __DRI_IMAGE_USE_SHARE (all images are shareable)
1211    *   __DRI_IMAGE_USE_BACKBUFFER (all images support this)
1212    */
1213   unsigned bind = 0;
1214   if (use & __DRI_IMAGE_USE_SCANOUT)
1215      bind |= PIPE_BIND_SCANOUT;
1216   if (use & __DRI_IMAGE_USE_LINEAR)
1217      bind |= PIPE_BIND_LINEAR;
1218   if (use & __DRI_IMAGE_USE_CURSOR)
1219      bind |= PIPE_BIND_CURSOR;
1220
1221   if (!bind)
1222      return true;
1223
1224   return screen->check_resource_capability(screen, image->texture, bind);
1225}
1226
1227static __DRIimage *
1228dri2_from_names(__DRIscreen *screen, int width, int height, int format,
1229                int *names, int num_names, int *strides, int *offsets,
1230                void *loaderPrivate)
1231{
1232   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1233   __DRIimage *img;
1234   struct winsys_handle whandle;
1235
1236   if (!map)
1237      return NULL;
1238
1239   if (num_names != 1)
1240      return NULL;
1241
1242   memset(&whandle, 0, sizeof(whandle));
1243   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1244   whandle.handle = names[0];
1245   whandle.stride = strides[0];
1246   whandle.offset = offsets[0];
1247   whandle.modifier = DRM_FORMAT_MOD_INVALID;
1248
1249   img = dri2_create_image_from_winsys(screen, width, height, map->pipe_format,
1250                                       1, &whandle, loaderPrivate);
1251   if (img == NULL)
1252      return NULL;
1253
1254   img->dri_components = map->dri_components;
1255   img->dri_fourcc = map->dri_fourcc;
1256   img->dri_format = map->pipe_format;
1257
1258   return img;
1259}
1260
1261static __DRIimage *
1262dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
1263{
1264   __DRIimage *img;
1265
1266   if (plane != 0)
1267      return NULL;
1268
1269   if (image->dri_components == 0)
1270      return NULL;
1271
1272   img = dri2_dup_image(image, loaderPrivate);
1273   if (img == NULL)
1274      return NULL;
1275
1276   if (img->texture->screen->resource_changed)
1277      img->texture->screen->resource_changed(img->texture->screen,
1278                                             img->texture);
1279
1280   /* set this to 0 for sub images. */
1281   img->dri_components = 0;
1282   return img;
1283}
1284
1285static __DRIimage *
1286dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
1287              int *fds, int num_fds, int *strides, int *offsets,
1288              void *loaderPrivate)
1289{
1290   return dri2_create_image_from_fd(screen, width, height, fourcc,
1291                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
1292                                   strides, offsets, NULL, loaderPrivate);
1293}
1294
1295static boolean
1296dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats,
1297                           int *count)
1298{
1299   struct dri_screen *screen = dri_screen(_screen);
1300   struct pipe_screen *pscreen = screen->base.screen;
1301   int i, j;
1302
1303   for (i = 0, j = 0; (i < ARRAY_SIZE(dri2_format_table)) &&
1304         (j < max || max == 0); i++) {
1305      const struct dri2_format_mapping *map = &dri2_format_table[i];
1306
1307      /* The sRGB format is not a real FourCC as defined by drm_fourcc.h, so we
1308       * must not leak it out to clients.
1309       */
1310      if (dri2_format_table[i].dri_fourcc == __DRI_IMAGE_FOURCC_SARGB8888)
1311         continue;
1312
1313      if (pscreen->is_format_supported(pscreen, map->pipe_format,
1314                                       screen->target, 0, 0,
1315                                       PIPE_BIND_RENDER_TARGET) ||
1316          pscreen->is_format_supported(pscreen, map->pipe_format,
1317                                       screen->target, 0, 0,
1318                                       PIPE_BIND_SAMPLER_VIEW)) {
1319         if (j < max)
1320            formats[j] = map->dri_fourcc;
1321         j++;
1322      }
1323   }
1324   *count = j;
1325   return true;
1326}
1327
1328static boolean
1329dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
1330                             uint64_t *modifiers, unsigned int *external_only,
1331                             int *count)
1332{
1333   struct dri_screen *screen = dri_screen(_screen);
1334   struct pipe_screen *pscreen = screen->base.screen;
1335   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1336   enum pipe_format format;
1337
1338   if (!map)
1339      return false;
1340
1341   format = map->pipe_format;
1342
1343   if (pscreen->query_dmabuf_modifiers != NULL &&
1344       (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1345                                     PIPE_BIND_RENDER_TARGET) ||
1346        pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1347                                     PIPE_BIND_SAMPLER_VIEW))) {
1348      pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
1349                                      external_only, count);
1350      return true;
1351   }
1352   return false;
1353}
1354
1355static __DRIimage *
1356dri2_from_dma_bufs(__DRIscreen *screen,
1357                   int width, int height, int fourcc,
1358                   int *fds, int num_fds,
1359                   int *strides, int *offsets,
1360                   enum __DRIYUVColorSpace yuv_color_space,
1361                   enum __DRISampleRange sample_range,
1362                   enum __DRIChromaSiting horizontal_siting,
1363                   enum __DRIChromaSiting vertical_siting,
1364                   unsigned *error,
1365                   void *loaderPrivate)
1366{
1367   __DRIimage *img;
1368
1369   img = dri2_create_image_from_fd(screen, width, height, fourcc,
1370                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
1371                                   strides, offsets, error, loaderPrivate);
1372   if (img == NULL)
1373      return NULL;
1374
1375   img->yuv_color_space = yuv_color_space;
1376   img->sample_range = sample_range;
1377   img->horizontal_siting = horizontal_siting;
1378   img->vertical_siting = vertical_siting;
1379
1380   *error = __DRI_IMAGE_ERROR_SUCCESS;
1381   return img;
1382}
1383
1384static __DRIimage *
1385dri2_from_dma_bufs2(__DRIscreen *screen,
1386                    int width, int height, int fourcc,
1387                    uint64_t modifier, int *fds, int num_fds,
1388                    int *strides, int *offsets,
1389                    enum __DRIYUVColorSpace yuv_color_space,
1390                    enum __DRISampleRange sample_range,
1391                    enum __DRIChromaSiting horizontal_siting,
1392                    enum __DRIChromaSiting vertical_siting,
1393                    unsigned *error,
1394                    void *loaderPrivate)
1395{
1396   __DRIimage *img;
1397
1398   img = dri2_create_image_from_fd(screen, width, height, fourcc,
1399                                   modifier, fds, num_fds, strides, offsets,
1400                                   error, loaderPrivate);
1401   if (img == NULL)
1402      return NULL;
1403
1404   img->yuv_color_space = yuv_color_space;
1405   img->sample_range = sample_range;
1406   img->horizontal_siting = horizontal_siting;
1407   img->vertical_siting = vertical_siting;
1408
1409   *error = __DRI_IMAGE_ERROR_SUCCESS;
1410   return img;
1411}
1412
1413static void
1414dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
1415                int dstx0, int dsty0, int dstwidth, int dstheight,
1416                int srcx0, int srcy0, int srcwidth, int srcheight,
1417                int flush_flag)
1418{
1419   struct dri_context *ctx = dri_context(context);
1420   struct pipe_context *pipe = ctx->st->pipe;
1421   struct pipe_screen *screen;
1422   struct pipe_fence_handle *fence;
1423   struct pipe_blit_info blit;
1424
1425   if (!dst || !src)
1426      return;
1427
1428   memset(&blit, 0, sizeof(blit));
1429   blit.dst.resource = dst->texture;
1430   blit.dst.box.x = dstx0;
1431   blit.dst.box.y = dsty0;
1432   blit.dst.box.width = dstwidth;
1433   blit.dst.box.height = dstheight;
1434   blit.dst.box.depth = 1;
1435   blit.dst.format = dst->texture->format;
1436   blit.src.resource = src->texture;
1437   blit.src.box.x = srcx0;
1438   blit.src.box.y = srcy0;
1439   blit.src.box.width = srcwidth;
1440   blit.src.box.height = srcheight;
1441   blit.src.box.depth = 1;
1442   blit.src.format = src->texture->format;
1443   blit.mask = PIPE_MASK_RGBA;
1444   blit.filter = PIPE_TEX_FILTER_NEAREST;
1445
1446   pipe->blit(pipe, &blit);
1447
1448   if (flush_flag == __BLIT_FLAG_FLUSH) {
1449      pipe->flush_resource(pipe, dst->texture);
1450      ctx->st->flush(ctx->st, 0, NULL);
1451   } else if (flush_flag == __BLIT_FLAG_FINISH) {
1452      screen = dri_screen(ctx->sPriv)->base.screen;
1453      pipe->flush_resource(pipe, dst->texture);
1454      ctx->st->flush(ctx->st, 0, &fence);
1455      (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
1456      screen->fence_reference(screen, &fence, NULL);
1457   }
1458}
1459
1460static void *
1461dri2_map_image(__DRIcontext *context, __DRIimage *image,
1462                int x0, int y0, int width, int height,
1463                unsigned int flags, int *stride, void **data)
1464{
1465   struct dri_context *ctx = dri_context(context);
1466   struct pipe_context *pipe = ctx->st->pipe;
1467   enum pipe_transfer_usage pipe_access = 0;
1468   struct pipe_transfer *trans;
1469   void *map;
1470
1471   if (!image || !data || *data)
1472      return NULL;
1473
1474   if (flags & __DRI_IMAGE_TRANSFER_READ)
1475         pipe_access |= PIPE_TRANSFER_READ;
1476   if (flags & __DRI_IMAGE_TRANSFER_WRITE)
1477         pipe_access |= PIPE_TRANSFER_WRITE;
1478
1479   map = pipe_transfer_map(pipe, image->texture,
1480                           0, 0, pipe_access, x0, y0, width, height,
1481                           &trans);
1482   if (map) {
1483      *data = trans;
1484      *stride = trans->stride;
1485   }
1486
1487   return map;
1488}
1489
1490static void
1491dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
1492{
1493   struct dri_context *ctx = dri_context(context);
1494   struct pipe_context *pipe = ctx->st->pipe;
1495
1496   pipe_transfer_unmap(pipe, (struct pipe_transfer *)data);
1497}
1498
1499static int
1500dri2_get_capabilities(__DRIscreen *_screen)
1501{
1502   struct dri_screen *screen = dri_screen(_screen);
1503
1504   return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0);
1505}
1506
1507/* The extension is modified during runtime if DRI_PRIME is detected */
1508static __DRIimageExtension dri2ImageExtension = {
1509    .base = { __DRI_IMAGE, 17 },
1510
1511    .createImageFromName          = dri2_create_image_from_name,
1512    .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1513    .destroyImage                 = dri2_destroy_image,
1514    .createImage                  = dri2_create_image,
1515    .queryImage                   = dri2_query_image,
1516    .dupImage                     = dri2_dup_image,
1517    .validateUsage                = dri2_validate_usage,
1518    .createImageFromNames         = dri2_from_names,
1519    .fromPlanar                   = dri2_from_planar,
1520    .createImageFromTexture       = dri2_create_from_texture,
1521    .createImageFromFds           = NULL,
1522    .createImageFromDmaBufs       = NULL,
1523    .blitImage                    = dri2_blit_image,
1524    .getCapabilities              = dri2_get_capabilities,
1525    .mapImage                     = dri2_map_image,
1526    .unmapImage                   = dri2_unmap_image,
1527    .createImageWithModifiers     = NULL,
1528    .createImageFromDmaBufs2      = NULL,
1529    .queryDmaBufFormats           = NULL,
1530    .queryDmaBufModifiers         = NULL,
1531    .queryDmaBufFormatModifierAttribs = NULL,
1532    .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1533};
1534
1535static const __DRIrobustnessExtension dri2Robustness = {
1536   .base = { __DRI2_ROBUSTNESS, 1 }
1537};
1538
1539static int
1540dri2_interop_query_device_info(__DRIcontext *_ctx,
1541                               struct mesa_glinterop_device_info *out)
1542{
1543   struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
1544
1545   /* There is no version 0, thus we do not support it */
1546   if (out->version == 0)
1547      return MESA_GLINTEROP_INVALID_VERSION;
1548
1549   out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
1550   out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
1551   out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
1552   out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
1553
1554   out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
1555   out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
1556
1557   /* Instruct the caller that we support up-to version one of the interface */
1558   out->version = 1;
1559
1560   return MESA_GLINTEROP_SUCCESS;
1561}
1562
1563static int
1564dri2_interop_export_object(__DRIcontext *_ctx,
1565                           struct mesa_glinterop_export_in *in,
1566                           struct mesa_glinterop_export_out *out)
1567{
1568   struct st_context_iface *st = dri_context(_ctx)->st;
1569   struct pipe_screen *screen = st->pipe->screen;
1570   struct gl_context *ctx = ((struct st_context *)st)->ctx;
1571   struct pipe_resource *res = NULL;
1572   struct winsys_handle whandle;
1573   unsigned target, usage;
1574   boolean success;
1575
1576   /* There is no version 0, thus we do not support it */
1577   if (in->version == 0 || out->version == 0)
1578      return MESA_GLINTEROP_INVALID_VERSION;
1579
1580   /* Validate the target. */
1581   switch (in->target) {
1582   case GL_TEXTURE_BUFFER:
1583   case GL_TEXTURE_1D:
1584   case GL_TEXTURE_2D:
1585   case GL_TEXTURE_3D:
1586   case GL_TEXTURE_RECTANGLE:
1587   case GL_TEXTURE_1D_ARRAY:
1588   case GL_TEXTURE_2D_ARRAY:
1589   case GL_TEXTURE_CUBE_MAP_ARRAY:
1590   case GL_TEXTURE_CUBE_MAP:
1591   case GL_TEXTURE_2D_MULTISAMPLE:
1592   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1593   case GL_TEXTURE_EXTERNAL_OES:
1594   case GL_RENDERBUFFER:
1595   case GL_ARRAY_BUFFER:
1596      target = in->target;
1597      break;
1598   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1599   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1600   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1601   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1602   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1603   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1604      target = GL_TEXTURE_CUBE_MAP;
1605      break;
1606   default:
1607      return MESA_GLINTEROP_INVALID_TARGET;
1608   }
1609
1610   /* Validate the simple case of miplevel. */
1611   if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
1612       in->miplevel != 0)
1613      return MESA_GLINTEROP_INVALID_MIP_LEVEL;
1614
1615   /* Validate the OpenGL object and get pipe_resource. */
1616   simple_mtx_lock(&ctx->Shared->Mutex);
1617
1618   if (target == GL_ARRAY_BUFFER) {
1619      /* Buffer objects.
1620       *
1621       * The error checking is based on the documentation of
1622       * clCreateFromGLBuffer from OpenCL 2.0 SDK.
1623       */
1624      struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
1625
1626      /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
1627       *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
1628       *   a GL buffer object but does not have an existing data store or
1629       *   the size of the buffer is 0."
1630       */
1631      if (!buf || buf->Size == 0) {
1632         simple_mtx_unlock(&ctx->Shared->Mutex);
1633         return MESA_GLINTEROP_INVALID_OBJECT;
1634      }
1635
1636      res = st_buffer_object(buf)->buffer;
1637      if (!res) {
1638         /* this shouldn't happen */
1639         simple_mtx_unlock(&ctx->Shared->Mutex);
1640         return MESA_GLINTEROP_INVALID_OBJECT;
1641      }
1642
1643      out->buf_offset = 0;
1644      out->buf_size = buf->Size;
1645
1646      buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
1647   } else if (target == GL_RENDERBUFFER) {
1648      /* Renderbuffers.
1649       *
1650       * The error checking is based on the documentation of
1651       * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
1652       */
1653      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
1654
1655      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1656       *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
1657       *    object or if the width or height of renderbuffer is zero."
1658       */
1659      if (!rb || rb->Width == 0 || rb->Height == 0) {
1660         simple_mtx_unlock(&ctx->Shared->Mutex);
1661         return MESA_GLINTEROP_INVALID_OBJECT;
1662      }
1663
1664      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1665       *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
1666       *    renderbuffer object."
1667       */
1668      if (rb->NumSamples > 1) {
1669         simple_mtx_unlock(&ctx->Shared->Mutex);
1670         return MESA_GLINTEROP_INVALID_OPERATION;
1671      }
1672
1673      /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1674       *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
1675       *    required by the OpenCL implementation on the device."
1676       */
1677      res = st_renderbuffer(rb)->texture;
1678      if (!res) {
1679         simple_mtx_unlock(&ctx->Shared->Mutex);
1680         return MESA_GLINTEROP_OUT_OF_RESOURCES;
1681      }
1682
1683      out->internal_format = rb->InternalFormat;
1684      out->view_minlevel = 0;
1685      out->view_numlevels = 1;
1686      out->view_minlayer = 0;
1687      out->view_numlayers = 1;
1688   } else {
1689      /* Texture objects.
1690       *
1691       * The error checking is based on the documentation of
1692       * clCreateFromGLTexture from OpenCL 2.0 SDK.
1693       */
1694      struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
1695
1696      if (obj)
1697         _mesa_test_texobj_completeness(ctx, obj);
1698
1699      /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
1700       *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
1701       *    type matches texture_target, if the specified miplevel of texture
1702       *    is not defined, or if the width or height of the specified
1703       *    miplevel is zero or if the GL texture object is incomplete."
1704       */
1705      if (!obj ||
1706          obj->Target != target ||
1707          !obj->_BaseComplete ||
1708          (in->miplevel > 0 && !obj->_MipmapComplete)) {
1709         simple_mtx_unlock(&ctx->Shared->Mutex);
1710         return MESA_GLINTEROP_INVALID_OBJECT;
1711      }
1712
1713      if (target == GL_TEXTURE_BUFFER) {
1714         struct st_buffer_object *stBuf =
1715            st_buffer_object(obj->BufferObject);
1716
1717         if (!stBuf || !stBuf->buffer) {
1718            /* this shouldn't happen */
1719            simple_mtx_unlock(&ctx->Shared->Mutex);
1720            return MESA_GLINTEROP_INVALID_OBJECT;
1721         }
1722         res = stBuf->buffer;
1723
1724         out->internal_format = obj->BufferObjectFormat;
1725         out->buf_offset = obj->BufferOffset;
1726         out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
1727                                                 obj->BufferSize;
1728
1729         obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
1730      } else {
1731         /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
1732          *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
1733          *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
1734          *    implementations); or greater than the value of q (for both OpenGL
1735          *    and OpenGL ES). levelbase and q are defined for the texture in
1736          *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
1737          *    specification and section 3.7.10 of the OpenGL ES 2.0."
1738          */
1739         if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) {
1740            simple_mtx_unlock(&ctx->Shared->Mutex);
1741            return MESA_GLINTEROP_INVALID_MIP_LEVEL;
1742         }
1743
1744         if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
1745            simple_mtx_unlock(&ctx->Shared->Mutex);
1746            return MESA_GLINTEROP_OUT_OF_RESOURCES;
1747         }
1748
1749         res = st_get_texobj_resource(obj);
1750         if (!res) {
1751            /* Incomplete texture buffer object? This shouldn't really occur. */
1752            simple_mtx_unlock(&ctx->Shared->Mutex);
1753            return MESA_GLINTEROP_INVALID_OBJECT;
1754         }
1755
1756         out->internal_format = obj->Image[0][0]->InternalFormat;
1757         out->view_minlevel = obj->MinLevel;
1758         out->view_numlevels = obj->NumLevels;
1759         out->view_minlayer = obj->MinLayer;
1760         out->view_numlayers = obj->NumLayers;
1761      }
1762   }
1763
1764   /* Get the handle. */
1765   switch (in->access) {
1766   case MESA_GLINTEROP_ACCESS_READ_ONLY:
1767      usage = 0;
1768      break;
1769   case MESA_GLINTEROP_ACCESS_READ_WRITE:
1770   case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
1771      usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
1772      break;
1773   default:
1774      usage = 0;
1775   }
1776
1777   memset(&whandle, 0, sizeof(whandle));
1778   whandle.type = WINSYS_HANDLE_TYPE_FD;
1779
1780   success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
1781                                         usage);
1782   simple_mtx_unlock(&ctx->Shared->Mutex);
1783
1784   if (!success)
1785      return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
1786
1787   out->dmabuf_fd = whandle.handle;
1788   out->out_driver_data_written = 0;
1789
1790   if (res->target == PIPE_BUFFER)
1791      out->buf_offset += whandle.offset;
1792
1793   /* Instruct the caller that we support up-to version one of the interface */
1794   in->version = 1;
1795   out->version = 1;
1796
1797   return MESA_GLINTEROP_SUCCESS;
1798}
1799
1800static const __DRI2interopExtension dri2InteropExtension = {
1801   .base = { __DRI2_INTEROP, 1 },
1802   .query_device_info = dri2_interop_query_device_info,
1803   .export_object = dri2_interop_export_object
1804};
1805
1806/**
1807 * \brief the DRI2ConfigQueryExtension configQueryb method
1808 */
1809static int
1810dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var,
1811                        unsigned char *val)
1812{
1813   struct dri_screen *screen = dri_screen(sPriv);
1814
1815   if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL))
1816      return dri2ConfigQueryExtension.configQueryb(sPriv, var, val);
1817
1818   *val = driQueryOptionb(&screen->dev->option_cache, var);
1819
1820   return 0;
1821}
1822
1823/**
1824 * \brief the DRI2ConfigQueryExtension configQueryi method
1825 */
1826static int
1827dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val)
1828{
1829   struct dri_screen *screen = dri_screen(sPriv);
1830
1831   if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) &&
1832       !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM))
1833      return dri2ConfigQueryExtension.configQueryi(sPriv, var, val);
1834
1835    *val = driQueryOptioni(&screen->dev->option_cache, var);
1836
1837    return 0;
1838}
1839
1840/**
1841 * \brief the DRI2ConfigQueryExtension configQueryf method
1842 */
1843static int
1844dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val)
1845{
1846   struct dri_screen *screen = dri_screen(sPriv);
1847
1848   if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT))
1849      return dri2ConfigQueryExtension.configQueryf(sPriv, var, val);
1850
1851    *val = driQueryOptionf(&screen->dev->option_cache, var);
1852
1853    return 0;
1854}
1855
1856/**
1857 * \brief the DRI2ConfigQueryExtension struct.
1858 *
1859 * We first query the driver option cache. Then the dri2 option cache.
1860 */
1861static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = {
1862   .base = { __DRI2_CONFIG_QUERY, 1 },
1863
1864   .configQueryb        = dri2GalliumConfigQueryb,
1865   .configQueryi        = dri2GalliumConfigQueryi,
1866   .configQueryf        = dri2GalliumConfigQueryf,
1867};
1868
1869/*
1870 * Backend function init_screen.
1871 */
1872
1873static const __DRIextension *dri_screen_extensions[] = {
1874   &driTexBufferExtension.base,
1875   &dri2FlushExtension.base,
1876   &dri2ImageExtension.base,
1877   &dri2RendererQueryExtension.base,
1878   &dri2GalliumConfigQueryExtension.base,
1879   &dri2ThrottleExtension.base,
1880   &dri2FenceExtension.base,
1881   &dri2InteropExtension.base,
1882   &dri2NoErrorExtension.base,
1883   NULL
1884};
1885
1886static const __DRIextension *dri_robust_screen_extensions[] = {
1887   &driTexBufferExtension.base,
1888   &dri2FlushExtension.base,
1889   &dri2ImageExtension.base,
1890   &dri2RendererQueryExtension.base,
1891   &dri2GalliumConfigQueryExtension.base,
1892   &dri2ThrottleExtension.base,
1893   &dri2FenceExtension.base,
1894   &dri2InteropExtension.base,
1895   &dri2Robustness.base,
1896   &dri2NoErrorExtension.base,
1897   NULL
1898};
1899
1900/**
1901 * This is the driver specific part of the createNewScreen entry point.
1902 *
1903 * Returns the struct gl_config supported by this driver.
1904 */
1905static const __DRIconfig **
1906dri2_init_screen(__DRIscreen * sPriv)
1907{
1908   const __DRIconfig **configs;
1909   struct dri_screen *screen;
1910   struct pipe_screen *pscreen = NULL;
1911
1912   screen = CALLOC_STRUCT(dri_screen);
1913   if (!screen)
1914      return NULL;
1915
1916   screen->sPriv = sPriv;
1917   screen->fd = sPriv->fd;
1918   (void) mtx_init(&screen->opencl_func_mutex, mtx_plain);
1919
1920   sPriv->driverPrivate = (void *)screen;
1921
1922   if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) {
1923      dri_init_options(screen);
1924
1925      pscreen = pipe_loader_create_screen(screen->dev);
1926   }
1927
1928   if (!pscreen)
1929       goto release_pipe;
1930
1931   screen->default_throttle_frames =
1932      pscreen->get_param(pscreen, PIPE_CAP_MAX_FRAMES_IN_FLIGHT);
1933
1934   if (pscreen->resource_create_with_modifiers)
1935      dri2ImageExtension.createImageWithModifiers =
1936         dri2_create_image_with_modifiers;
1937
1938   if (pscreen->get_param(pscreen, PIPE_CAP_DMABUF)) {
1939      uint64_t cap;
1940
1941      if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
1942          (cap & DRM_PRIME_CAP_IMPORT)) {
1943         dri2ImageExtension.createImageFromFds = dri2_from_fds;
1944         dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
1945         dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
1946         if (pscreen->query_dmabuf_modifiers) {
1947            dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats;
1948            dri2ImageExtension.queryDmaBufModifiers =
1949                                       dri2_query_dma_buf_modifiers;
1950         }
1951      }
1952   }
1953
1954   if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {
1955      sPriv->extensions = dri_robust_screen_extensions;
1956      screen->has_reset_status_query = true;
1957   }
1958   else
1959      sPriv->extensions = dri_screen_extensions;
1960
1961   configs = dri_init_screen_helper(screen, pscreen);
1962   if (!configs)
1963      goto destroy_screen;
1964
1965   screen->can_share_buffer = true;
1966   screen->auto_fake_front = dri_with_format(sPriv);
1967   screen->broken_invalidate = !sPriv->dri2.useInvalidate;
1968   screen->lookup_egl_image = dri2_lookup_egl_image;
1969
1970   return configs;
1971
1972destroy_screen:
1973   dri_destroy_screen_helper(screen);
1974
1975release_pipe:
1976   if (screen->dev)
1977      pipe_loader_release(&screen->dev, 1);
1978
1979   FREE(screen);
1980   return NULL;
1981}
1982
1983/**
1984 * This is the driver specific part of the createNewScreen entry point.
1985 *
1986 * Returns the struct gl_config supported by this driver.
1987 */
1988static const __DRIconfig **
1989dri_kms_init_screen(__DRIscreen * sPriv)
1990{
1991#if defined(GALLIUM_SOFTPIPE)
1992   const __DRIconfig **configs;
1993   struct dri_screen *screen;
1994   struct pipe_screen *pscreen = NULL;
1995   uint64_t cap;
1996
1997   screen = CALLOC_STRUCT(dri_screen);
1998   if (!screen)
1999      return NULL;
2000
2001   screen->sPriv = sPriv;
2002   screen->fd = sPriv->fd;
2003
2004   sPriv->driverPrivate = (void *)screen;
2005
2006   if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) {
2007      dri_init_options(screen);
2008      pscreen = pipe_loader_create_screen(screen->dev);
2009   }
2010
2011   if (!pscreen)
2012       goto release_pipe;
2013
2014   if (pscreen->resource_create_with_modifiers)
2015      dri2ImageExtension.createImageWithModifiers =
2016         dri2_create_image_with_modifiers;
2017
2018   if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
2019          (cap & DRM_PRIME_CAP_IMPORT)) {
2020      dri2ImageExtension.createImageFromFds = dri2_from_fds;
2021      dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
2022      dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
2023      if (pscreen->query_dmabuf_modifiers) {
2024         dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats;
2025         dri2ImageExtension.queryDmaBufModifiers = dri2_query_dma_buf_modifiers;
2026      }
2027   }
2028
2029   sPriv->extensions = dri_screen_extensions;
2030
2031   configs = dri_init_screen_helper(screen, pscreen);
2032   if (!configs)
2033      goto destroy_screen;
2034
2035   screen->can_share_buffer = false;
2036   screen->auto_fake_front = dri_with_format(sPriv);
2037   screen->broken_invalidate = !sPriv->dri2.useInvalidate;
2038   screen->lookup_egl_image = dri2_lookup_egl_image;
2039
2040   return configs;
2041
2042destroy_screen:
2043   dri_destroy_screen_helper(screen);
2044
2045release_pipe:
2046   if (screen->dev)
2047      pipe_loader_release(&screen->dev, 1);
2048
2049   FREE(screen);
2050#endif // GALLIUM_SOFTPIPE
2051   return NULL;
2052}
2053
2054static boolean
2055dri2_create_buffer(__DRIscreen * sPriv,
2056                   __DRIdrawable * dPriv,
2057                   const struct gl_config * visual, boolean isPixmap)
2058{
2059   struct dri_drawable *drawable = NULL;
2060
2061   if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
2062      return FALSE;
2063
2064   drawable = dPriv->driverPrivate;
2065
2066   drawable->allocate_textures = dri2_allocate_textures;
2067   drawable->flush_frontbuffer = dri2_flush_frontbuffer;
2068   drawable->update_tex_buffer = dri2_update_tex_buffer;
2069   drawable->flush_swapbuffers = dri2_flush_swapbuffers;
2070
2071   return TRUE;
2072}
2073
2074/**
2075 * DRI driver virtual function table.
2076 *
2077 * DRI versions differ in their implementation of init_screen and swap_buffers.
2078 */
2079const struct __DriverAPIRec galliumdrm_driver_api = {
2080   .InitScreen = dri2_init_screen,
2081   .DestroyScreen = dri_destroy_screen,
2082   .CreateContext = dri_create_context,
2083   .DestroyContext = dri_destroy_context,
2084   .CreateBuffer = dri2_create_buffer,
2085   .DestroyBuffer = dri_destroy_buffer,
2086   .MakeCurrent = dri_make_current,
2087   .UnbindContext = dri_unbind_context,
2088
2089   .AllocateBuffer = dri2_allocate_buffer,
2090   .ReleaseBuffer  = dri2_release_buffer,
2091};
2092
2093/**
2094 * DRI driver virtual function table.
2095 *
2096 * KMS/DRM version of the DriverAPI above sporting a different InitScreen
2097 * hook. The latter is used to explicitly initialise the kms_swrast driver
2098 * rather than selecting the approapriate driver as suggested by the loader.
2099 */
2100const struct __DriverAPIRec dri_kms_driver_api = {
2101   .InitScreen = dri_kms_init_screen,
2102   .DestroyScreen = dri_destroy_screen,
2103   .CreateContext = dri_create_context,
2104   .DestroyContext = dri_destroy_context,
2105   .CreateBuffer = dri2_create_buffer,
2106   .DestroyBuffer = dri_destroy_buffer,
2107   .MakeCurrent = dri_make_current,
2108   .UnbindContext = dri_unbind_context,
2109
2110   .AllocateBuffer = dri2_allocate_buffer,
2111   .ReleaseBuffer  = dri2_release_buffer,
2112};
2113
2114/* This is the table of extensions that the loader will dlsym() for. */
2115const __DRIextension *galliumdrm_driver_extensions[] = {
2116    &driCoreExtension.base,
2117    &driImageDriverExtension.base,
2118    &driDRI2Extension.base,
2119    &gallium_config_options.base,
2120    NULL
2121};
2122
2123/* vim: set sw=3 ts=8 sts=3 expandtab: */
2124