1/*
2 * Copyright © 2016 Red Hat.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include "macros.h"
25#include "mtypes.h"
26#include "bufferobj.h"
27#include "context.h"
28#include "enums.h"
29#include "externalobjects.h"
30#include "teximage.h"
31#include "texobj.h"
32#include "glformats.h"
33#include "texstorage.h"
34#include "util/u_memory.h"
35
36#include "pipe/p_context.h"
37#include "pipe/p_screen.h"
38#include "api_exec_decl.h"
39
40#include "state_tracker/st_cb_bitmap.h"
41#include "state_tracker/st_texture.h"
42
43struct st_context;
44
45#include "frontend/drm_driver.h"
46#ifdef HAVE_LIBDRM
47#include "drm-uapi/drm_fourcc.h"
48#endif
49
50static struct gl_memory_object *
51memoryobj_alloc(struct gl_context *ctx, GLuint name)
52{
53   struct gl_memory_object *obj = CALLOC_STRUCT(gl_memory_object);
54   if (!obj)
55      return NULL;
56
57   obj->Name = name;
58   obj->Dedicated = GL_FALSE;
59   return obj;
60}
61
62static void
63import_memoryobj_fd(struct gl_context *ctx,
64                    struct gl_memory_object *obj,
65                    GLuint64 size,
66                    int fd)
67{
68#if !defined(_WIN32)
69   struct pipe_screen *screen = ctx->pipe->screen;
70   struct winsys_handle whandle = {
71      .type = WINSYS_HANDLE_TYPE_FD,
72      .handle = fd,
73#ifdef HAVE_LIBDRM
74      .modifier = DRM_FORMAT_MOD_INVALID,
75#endif
76   };
77
78   obj->memory = screen->memobj_create_from_handle(screen,
79                                                   &whandle,
80                                                   obj->Dedicated);
81
82   /* We own fd, but we no longer need it. So get rid of it */
83   close(fd);
84#endif
85}
86
87static void
88import_memoryobj_win32(struct gl_context *ctx,
89                       struct gl_memory_object *obj,
90                       GLuint64 size,
91                       void *handle,
92                       const void *name)
93{
94   struct pipe_screen *screen = ctx->pipe->screen;
95   struct winsys_handle whandle = {
96      .type = handle ? WINSYS_HANDLE_TYPE_WIN32_HANDLE : WINSYS_HANDLE_TYPE_WIN32_NAME,
97#ifdef _WIN32
98      .handle = handle,
99#else
100      .handle = 0,
101#endif
102#ifdef HAVE_LIBDRM
103      .modifier = DRM_FORMAT_MOD_INVALID,
104#endif
105      .name = name,
106   };
107
108   obj->memory = screen->memobj_create_from_handle(screen,
109                                                   &whandle,
110                                                   obj->Dedicated);
111}
112
113/**
114 * Delete a memory object.
115 * Not removed from hash table here.
116 */
117void
118_mesa_delete_memory_object(struct gl_context *ctx,
119                           struct gl_memory_object *memObj)
120{
121   struct pipe_screen *screen = ctx->pipe->screen;
122   if (memObj->memory)
123      screen->memobj_destroy(screen, memObj->memory);
124   FREE(memObj);
125}
126
127void GLAPIENTRY
128_mesa_DeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObjects)
129{
130   GET_CURRENT_CONTEXT(ctx);
131
132   if (MESA_VERBOSE & (VERBOSE_API)) {
133      _mesa_debug(ctx, "glDeleteMemoryObjectsEXT(%d, %p)\n", n,
134                  memoryObjects);
135   }
136
137   if (!ctx->Extensions.EXT_memory_object) {
138      _mesa_error(ctx, GL_INVALID_OPERATION,
139                  "glDeleteMemoryObjectsEXT(unsupported)");
140      return;
141   }
142
143   if (n < 0) {
144      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteMemoryObjectsEXT(n < 0)");
145      return;
146   }
147
148   if (!memoryObjects)
149      return;
150
151   _mesa_HashLockMutex(ctx->Shared->MemoryObjects);
152   for (GLint i = 0; i < n; i++) {
153      if (memoryObjects[i] > 0) {
154         struct gl_memory_object *delObj
155            = _mesa_lookup_memory_object_locked(ctx, memoryObjects[i]);
156
157         if (delObj) {
158            _mesa_HashRemoveLocked(ctx->Shared->MemoryObjects,
159                                   memoryObjects[i]);
160            _mesa_delete_memory_object(ctx, delObj);
161         }
162      }
163   }
164   _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects);
165}
166
167GLboolean GLAPIENTRY
168_mesa_IsMemoryObjectEXT(GLuint memoryObject)
169{
170   GET_CURRENT_CONTEXT(ctx);
171
172   if (!ctx->Extensions.EXT_memory_object) {
173      _mesa_error(ctx, GL_INVALID_OPERATION,
174                  "glIsMemoryObjectEXT(unsupported)");
175      return GL_FALSE;
176   }
177
178   struct gl_memory_object *obj =
179      _mesa_lookup_memory_object(ctx, memoryObject);
180
181   return obj ? GL_TRUE : GL_FALSE;
182}
183
184void GLAPIENTRY
185_mesa_CreateMemoryObjectsEXT(GLsizei n, GLuint *memoryObjects)
186{
187   GET_CURRENT_CONTEXT(ctx);
188
189   const char *func = "glCreateMemoryObjectsEXT";
190
191   if (MESA_VERBOSE & (VERBOSE_API))
192      _mesa_debug(ctx, "%s(%d, %p)", func, n, memoryObjects);
193
194   if (!ctx->Extensions.EXT_memory_object) {
195      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
196      return;
197   }
198
199   if (n < 0) {
200      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
201      return;
202   }
203
204   if (!memoryObjects)
205      return;
206
207   _mesa_HashLockMutex(ctx->Shared->MemoryObjects);
208   if (_mesa_HashFindFreeKeys(ctx->Shared->MemoryObjects, memoryObjects, n)) {
209      for (GLsizei i = 0; i < n; i++) {
210         struct gl_memory_object *memObj;
211
212         /* allocate memory object */
213         memObj = memoryobj_alloc(ctx, memoryObjects[i]);
214         if (!memObj) {
215            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", func);
216            _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects);
217            return;
218         }
219
220         /* insert into hash table */
221         _mesa_HashInsertLocked(ctx->Shared->MemoryObjects,
222                                memoryObjects[i],
223                                memObj, true);
224      }
225   }
226
227   _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects);
228}
229
230void GLAPIENTRY
231_mesa_MemoryObjectParameterivEXT(GLuint memoryObject,
232                                 GLenum pname,
233                                 const GLint *params)
234{
235   GET_CURRENT_CONTEXT(ctx);
236   struct gl_memory_object *memObj;
237
238   const char *func = "glMemoryObjectParameterivEXT";
239
240   if (!ctx->Extensions.EXT_memory_object) {
241      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
242      return;
243   }
244
245   memObj = _mesa_lookup_memory_object(ctx, memoryObject);
246   if (!memObj)
247      return;
248
249   if (memObj->Immutable) {
250      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(memoryObject is immutable", func);
251      return;
252   }
253
254   switch (pname) {
255   case GL_DEDICATED_MEMORY_OBJECT_EXT:
256      memObj->Dedicated = (GLboolean) params[0];
257      break;
258   case GL_PROTECTED_MEMORY_OBJECT_EXT:
259      /* EXT_protected_textures not supported */
260      goto invalid_pname;
261   default:
262      goto invalid_pname;
263   }
264   return;
265
266invalid_pname:
267   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
268}
269
270void GLAPIENTRY
271_mesa_GetMemoryObjectParameterivEXT(GLuint memoryObject,
272                                    GLenum pname,
273                                    GLint *params)
274{
275   GET_CURRENT_CONTEXT(ctx);
276   struct gl_memory_object *memObj;
277
278   const char *func = "glMemoryObjectParameterivEXT";
279
280   if (!ctx->Extensions.EXT_memory_object) {
281      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
282      return;
283   }
284
285   memObj = _mesa_lookup_memory_object(ctx, memoryObject);
286   if (!memObj)
287      return;
288
289   switch (pname) {
290      case GL_DEDICATED_MEMORY_OBJECT_EXT:
291         *params = (GLint) memObj->Dedicated;
292         break;
293      case GL_PROTECTED_MEMORY_OBJECT_EXT:
294         /* EXT_protected_textures not supported */
295         goto invalid_pname;
296      default:
297         goto invalid_pname;
298   }
299   return;
300
301invalid_pname:
302   _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
303}
304
305static struct gl_memory_object *
306lookup_memory_object_err(struct gl_context *ctx, unsigned memory,
307                         const char* func)
308{
309   if (memory == 0) {
310      _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory=0)", func);
311      return NULL;
312   }
313
314   struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory);
315   if (!memObj)
316      return NULL;
317
318   if (!memObj->Immutable) {
319      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)",
320                  func);
321      return NULL;
322   }
323
324   return memObj;
325}
326
327/**
328 * Helper used by _mesa_TexStorageMem1/2/3DEXT().
329 */
330static void
331texstorage_memory(GLuint dims, GLenum target, GLsizei levels,
332                  GLenum internalFormat, GLsizei width, GLsizei height,
333                  GLsizei depth, GLuint memory, GLuint64 offset,
334                  const char *func)
335{
336   struct gl_texture_object *texObj;
337   struct gl_memory_object *memObj;
338
339   GET_CURRENT_CONTEXT(ctx);
340
341   if (!ctx->Extensions.EXT_memory_object) {
342      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
343      return;
344   }
345
346   if (!_mesa_is_legal_tex_storage_target(ctx, dims, target)) {
347      _mesa_error(ctx, GL_INVALID_ENUM,
348                  "%s(illegal target=%s)",
349                  func, _mesa_enum_to_string(target));
350      return;
351   }
352
353   /* Check the format to make sure it is sized. */
354   if (!_mesa_is_legal_tex_storage_format(ctx, internalFormat)) {
355      _mesa_error(ctx, GL_INVALID_ENUM,
356                  "%s(internalformat = %s)", func,
357                  _mesa_enum_to_string(internalFormat));
358      return;
359   }
360
361   texObj = _mesa_get_current_tex_object(ctx, target);
362   if (!texObj)
363      return;
364
365   memObj = lookup_memory_object_err(ctx, memory, func);
366   if (!memObj)
367      return;
368
369   _mesa_texture_storage_memory(ctx, dims, texObj, memObj, target,
370                                levels, internalFormat,
371                                width, height, depth, offset, false);
372}
373
374static void
375texstorage_memory_ms(GLuint dims, GLenum target, GLsizei samples,
376                     GLenum internalFormat, GLsizei width, GLsizei height,
377                     GLsizei depth, GLboolean fixedSampleLocations,
378                     GLuint memory, GLuint64 offset, const char* func)
379{
380   struct gl_texture_object *texObj;
381   struct gl_memory_object *memObj;
382
383   GET_CURRENT_CONTEXT(ctx);
384
385   if (!ctx->Extensions.EXT_memory_object) {
386      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
387      return;
388   }
389
390   texObj = _mesa_get_current_tex_object(ctx, target);
391   if (!texObj)
392      return;
393
394   memObj = lookup_memory_object_err(ctx, memory, func);
395   if (!memObj)
396      return;
397
398   _mesa_texture_storage_ms_memory(ctx, dims, texObj, memObj, target, samples,
399                                   internalFormat, width, height, depth,
400                                   fixedSampleLocations, offset, func);
401}
402
403/**
404 * Helper used by _mesa_TextureStorageMem1/2/3DEXT().
405 */
406static void
407texturestorage_memory(GLuint dims, GLuint texture, GLsizei levels,
408                      GLenum internalFormat, GLsizei width, GLsizei height,
409                      GLsizei depth, GLuint memory, GLuint64 offset,
410                      const char *func)
411{
412   struct gl_texture_object *texObj;
413   struct gl_memory_object *memObj;
414
415   GET_CURRENT_CONTEXT(ctx);
416
417   if (!ctx->Extensions.EXT_memory_object) {
418      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
419      return;
420   }
421
422   /* Check the format to make sure it is sized. */
423   if (!_mesa_is_legal_tex_storage_format(ctx, internalFormat)) {
424      _mesa_error(ctx, GL_INVALID_ENUM,
425                  "%s(internalformat = %s)", func,
426                  _mesa_enum_to_string(internalFormat));
427      return;
428   }
429
430   texObj = _mesa_lookup_texture(ctx, texture);
431   if (!texObj)
432      return;
433
434   if (!_mesa_is_legal_tex_storage_target(ctx, dims, texObj->Target)) {
435      _mesa_error(ctx, GL_INVALID_OPERATION,
436                  "%s(illegal target=%s)", func,
437                  _mesa_enum_to_string(texObj->Target));
438      return;
439   }
440
441   memObj = lookup_memory_object_err(ctx, memory, func);
442   if (!memObj)
443      return;
444
445   _mesa_texture_storage_memory(ctx, dims, texObj, memObj, texObj->Target,
446                                levels, internalFormat,
447                                width, height, depth, offset, true);
448}
449
450static void
451texturestorage_memory_ms(GLuint dims, GLuint texture, GLsizei samples,
452                         GLenum internalFormat, GLsizei width, GLsizei height,
453                         GLsizei depth, GLboolean fixedSampleLocations,
454                         GLuint memory, GLuint64 offset, const char* func)
455{
456   struct gl_texture_object *texObj;
457   struct gl_memory_object *memObj;
458
459   GET_CURRENT_CONTEXT(ctx);
460
461   if (!ctx->Extensions.EXT_memory_object) {
462      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
463      return;
464   }
465
466   texObj = _mesa_lookup_texture(ctx, texture);
467   if (!texObj)
468      return;
469
470   memObj = lookup_memory_object_err(ctx, memory, func);
471   if (!memObj)
472      return;
473
474   _mesa_texture_storage_ms_memory(ctx, dims, texObj, memObj, texObj->Target,
475                                   samples, internalFormat, width, height,
476                                   depth, fixedSampleLocations, offset, func);
477}
478
479void GLAPIENTRY
480_mesa_TexStorageMem2DEXT(GLenum target,
481                         GLsizei levels,
482                         GLenum internalFormat,
483                         GLsizei width,
484                         GLsizei height,
485                         GLuint memory,
486                         GLuint64 offset)
487{
488   texstorage_memory(2, target, levels, internalFormat, width, height, 1,
489                     memory, offset, "glTexStorageMem2DEXT");
490}
491
492void GLAPIENTRY
493_mesa_TexStorageMem2DMultisampleEXT(GLenum target,
494                                    GLsizei samples,
495                                    GLenum internalFormat,
496                                    GLsizei width,
497                                    GLsizei height,
498                                    GLboolean fixedSampleLocations,
499                                    GLuint memory,
500                                    GLuint64 offset)
501{
502   texstorage_memory_ms(2, target, samples, internalFormat, width, height, 1,
503                        fixedSampleLocations, memory, offset,
504                        "glTexStorageMem2DMultisampleEXT");
505}
506
507void GLAPIENTRY
508_mesa_TexStorageMem3DEXT(GLenum target,
509                         GLsizei levels,
510                         GLenum internalFormat,
511                         GLsizei width,
512                         GLsizei height,
513                         GLsizei depth,
514                         GLuint memory,
515                         GLuint64 offset)
516{
517   texstorage_memory(3, target, levels, internalFormat, width, height, depth,
518                     memory, offset, "glTexStorageMem3DEXT");
519}
520
521void GLAPIENTRY
522_mesa_TexStorageMem3DMultisampleEXT(GLenum target,
523                                    GLsizei samples,
524                                    GLenum internalFormat,
525                                    GLsizei width,
526                                    GLsizei height,
527                                    GLsizei depth,
528                                    GLboolean fixedSampleLocations,
529                                    GLuint memory,
530                                    GLuint64 offset)
531{
532   texstorage_memory_ms(3, target, samples, internalFormat, width, height,
533                        depth, fixedSampleLocations, memory, offset,
534                        "glTexStorageMem3DMultisampleEXT");
535}
536
537void GLAPIENTRY
538_mesa_TextureStorageMem2DEXT(GLuint texture,
539                             GLsizei levels,
540                             GLenum internalFormat,
541                             GLsizei width,
542                             GLsizei height,
543                             GLuint memory,
544                             GLuint64 offset)
545{
546   texturestorage_memory(2, texture, levels, internalFormat, width, height, 1,
547                         memory, offset, "glTexureStorageMem2DEXT");
548}
549
550void GLAPIENTRY
551_mesa_TextureStorageMem2DMultisampleEXT(GLuint texture,
552                                        GLsizei samples,
553                                        GLenum internalFormat,
554                                        GLsizei width,
555                                        GLsizei height,
556                                        GLboolean fixedSampleLocations,
557                                        GLuint memory,
558                                        GLuint64 offset)
559{
560   texturestorage_memory_ms(2, texture, samples, internalFormat, width, height,
561                            1, fixedSampleLocations, memory, offset,
562                            "glTextureStorageMem2DMultisampleEXT");
563}
564
565void GLAPIENTRY
566_mesa_TextureStorageMem3DEXT(GLuint texture,
567                             GLsizei levels,
568                             GLenum internalFormat,
569                             GLsizei width,
570                             GLsizei height,
571                             GLsizei depth,
572                             GLuint memory,
573                             GLuint64 offset)
574{
575   texturestorage_memory(3, texture, levels, internalFormat, width, height,
576                         depth, memory, offset, "glTextureStorageMem3DEXT");
577}
578
579void GLAPIENTRY
580_mesa_TextureStorageMem3DMultisampleEXT(GLuint texture,
581                                        GLsizei samples,
582                                        GLenum internalFormat,
583                                        GLsizei width,
584                                        GLsizei height,
585                                        GLsizei depth,
586                                        GLboolean fixedSampleLocations,
587                                        GLuint memory,
588                                        GLuint64 offset)
589{
590   texturestorage_memory_ms(3, texture, samples, internalFormat, width, height,
591                            depth, fixedSampleLocations, memory, offset,
592                            "glTextureStorageMem3DMultisampleEXT");
593}
594
595void GLAPIENTRY
596_mesa_TexStorageMem1DEXT(GLenum target,
597                         GLsizei levels,
598                         GLenum internalFormat,
599                         GLsizei width,
600                         GLuint memory,
601                         GLuint64 offset)
602{
603   texstorage_memory(1, target, levels, internalFormat, width, 1, 1, memory,
604                     offset, "glTexStorageMem1DEXT");
605}
606
607void GLAPIENTRY
608_mesa_TextureStorageMem1DEXT(GLuint texture,
609                             GLsizei levels,
610                             GLenum internalFormat,
611                             GLsizei width,
612                             GLuint memory,
613                             GLuint64 offset)
614{
615   texturestorage_memory(1, texture, levels, internalFormat, width, 1, 1,
616                         memory, offset, "glTextureStorageMem1DEXT");
617}
618
619static struct gl_semaphore_object *
620semaphoreobj_alloc(struct gl_context *ctx, GLuint name)
621{
622   struct gl_semaphore_object *obj = CALLOC_STRUCT(gl_semaphore_object);
623   if (!obj)
624      return NULL;
625
626   obj->Name = name;
627   return obj;
628}
629
630static void
631import_semaphoreobj_fd(struct gl_context *ctx,
632                          struct gl_semaphore_object *semObj,
633                          int fd)
634{
635   struct pipe_context *pipe = ctx->pipe;
636
637   pipe->create_fence_fd(pipe, &semObj->fence, fd, PIPE_FD_TYPE_SYNCOBJ);
638
639#if !defined(_WIN32)
640   /* We own fd, but we no longer need it. So get rid of it */
641   close(fd);
642#endif
643}
644
645static void
646import_semaphoreobj_win32(struct gl_context *ctx,
647                          struct gl_semaphore_object *semObj,
648                          void *handle,
649                          const void *name,
650                          enum pipe_fd_type type)
651{
652   struct pipe_context *pipe = ctx->pipe;
653   semObj->type = type;
654
655   pipe->screen->create_fence_win32(pipe->screen, &semObj->fence, handle, name, type);
656}
657
658static void
659server_wait_semaphore(struct gl_context *ctx,
660                      struct gl_semaphore_object *semObj,
661                      GLuint numBufferBarriers,
662                      struct gl_buffer_object **bufObjs,
663                      GLuint numTextureBarriers,
664                      struct gl_texture_object **texObjs,
665                      const GLenum *srcLayouts)
666{
667   struct st_context *st = ctx->st;
668   struct pipe_context *pipe = ctx->pipe;
669   struct gl_buffer_object *bufObj;
670   struct gl_texture_object *texObj;
671
672   /* The driver is allowed to flush during fence_server_sync, be prepared */
673   st_flush_bitmap_cache(st);
674   pipe->fence_server_sync(pipe, semObj->fence);
675
676   /**
677    * According to the EXT_external_objects spec, the memory operations must
678    * follow the wait. This is to make sure the flush is executed after the
679    * other party is done modifying the memory.
680    *
681    * Relevant excerpt from section "4.2.3 Waiting for Semaphores":
682    *
683    * Following completion of the semaphore wait operation, memory will also be
684    * made visible in the specified buffer and texture objects.
685    *
686    */
687   for (unsigned i = 0; i < numBufferBarriers; i++) {
688      if (!bufObjs[i])
689         continue;
690
691      bufObj = bufObjs[i];
692      if (bufObj->buffer)
693         pipe->flush_resource(pipe, bufObj->buffer);
694   }
695
696   for (unsigned i = 0; i < numTextureBarriers; i++) {
697      if (!texObjs[i])
698         continue;
699
700      texObj = texObjs[i];
701      if (texObj->pt)
702         pipe->flush_resource(pipe, texObj->pt);
703   }
704}
705
706static void
707server_signal_semaphore(struct gl_context *ctx,
708                        struct gl_semaphore_object *semObj,
709                        GLuint numBufferBarriers,
710                        struct gl_buffer_object **bufObjs,
711                        GLuint numTextureBarriers,
712                        struct gl_texture_object **texObjs,
713                        const GLenum *dstLayouts)
714{
715   struct st_context *st = ctx->st;
716   struct pipe_context *pipe = ctx->pipe;
717   struct gl_buffer_object *bufObj;
718   struct gl_texture_object *texObj;
719
720   for (unsigned i = 0; i < numBufferBarriers; i++) {
721      if (!bufObjs[i])
722         continue;
723
724      bufObj = bufObjs[i];
725      if (bufObj->buffer)
726         pipe->flush_resource(pipe, bufObj->buffer);
727   }
728
729   for (unsigned i = 0; i < numTextureBarriers; i++) {
730      if (!texObjs[i])
731         continue;
732
733      texObj = texObjs[i];
734      if (texObj->pt)
735         pipe->flush_resource(pipe, texObj->pt);
736   }
737
738   /* The driver must flush during fence_server_signal, be prepared */
739   st_flush_bitmap_cache(st);
740   pipe->fence_server_signal(pipe, semObj->fence);
741}
742
743/**
744 * Used as a placeholder for semaphore objects between glGenSemaphoresEXT()
745 * and glImportSemaphoreFdEXT(), so that glIsSemaphoreEXT() can work correctly.
746 */
747static struct gl_semaphore_object DummySemaphoreObject;
748
749/**
750 * Delete a semaphore object.
751 * Not removed from hash table here.
752 */
753void
754_mesa_delete_semaphore_object(struct gl_context *ctx,
755                              struct gl_semaphore_object *semObj)
756{
757   if (semObj != &DummySemaphoreObject)
758      FREE(semObj);
759}
760
761void GLAPIENTRY
762_mesa_GenSemaphoresEXT(GLsizei n, GLuint *semaphores)
763{
764   GET_CURRENT_CONTEXT(ctx);
765
766   const char *func = "glGenSemaphoresEXT";
767
768   if (MESA_VERBOSE & (VERBOSE_API))
769      _mesa_debug(ctx, "%s(%d, %p)", func, n, semaphores);
770
771   if (!ctx->Extensions.EXT_semaphore) {
772      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
773      return;
774   }
775
776   if (n < 0) {
777      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
778      return;
779   }
780
781   if (!semaphores)
782      return;
783
784   _mesa_HashLockMutex(ctx->Shared->SemaphoreObjects);
785   if (_mesa_HashFindFreeKeys(ctx->Shared->SemaphoreObjects, semaphores, n)) {
786      for (GLsizei i = 0; i < n; i++) {
787         _mesa_HashInsertLocked(ctx->Shared->SemaphoreObjects,
788                                semaphores[i], &DummySemaphoreObject, true);
789      }
790   }
791
792   _mesa_HashUnlockMutex(ctx->Shared->SemaphoreObjects);
793}
794
795void GLAPIENTRY
796_mesa_DeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores)
797{
798   GET_CURRENT_CONTEXT(ctx);
799
800   const char *func = "glDeleteSemaphoresEXT";
801
802   if (MESA_VERBOSE & (VERBOSE_API)) {
803      _mesa_debug(ctx, "%s(%d, %p)\n", func, n, semaphores);
804   }
805
806   if (!ctx->Extensions.EXT_semaphore) {
807      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
808      return;
809   }
810
811   if (n < 0) {
812      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
813      return;
814   }
815
816   if (!semaphores)
817      return;
818
819   _mesa_HashLockMutex(ctx->Shared->SemaphoreObjects);
820   for (GLint i = 0; i < n; i++) {
821      if (semaphores[i] > 0) {
822         struct gl_semaphore_object *delObj
823            = _mesa_lookup_semaphore_object_locked(ctx, semaphores[i]);
824
825         if (delObj) {
826            _mesa_HashRemoveLocked(ctx->Shared->SemaphoreObjects,
827                                   semaphores[i]);
828            _mesa_delete_semaphore_object(ctx, delObj);
829         }
830      }
831   }
832   _mesa_HashUnlockMutex(ctx->Shared->SemaphoreObjects);
833}
834
835GLboolean GLAPIENTRY
836_mesa_IsSemaphoreEXT(GLuint semaphore)
837{
838   GET_CURRENT_CONTEXT(ctx);
839
840   if (!ctx->Extensions.EXT_semaphore) {
841      _mesa_error(ctx, GL_INVALID_OPERATION, "glIsSemaphoreEXT(unsupported)");
842      return GL_FALSE;
843   }
844
845   struct gl_semaphore_object *obj =
846      _mesa_lookup_semaphore_object(ctx, semaphore);
847
848   return obj ? GL_TRUE : GL_FALSE;
849}
850
851/**
852 * Helper that outputs the correct error status for parameter
853 * calls where no pnames are defined
854 */
855static void
856semaphore_parameter_stub(const char* func, GLenum pname)
857{
858}
859
860void GLAPIENTRY
861_mesa_SemaphoreParameterui64vEXT(GLuint semaphore,
862                                 GLenum pname,
863                                 const GLuint64 *params)
864{
865   GET_CURRENT_CONTEXT(ctx);
866   const char *func = "glSemaphoreParameterui64vEXT";
867
868   if (!ctx->Extensions.EXT_semaphore) {
869      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
870      return;
871   }
872
873   if (pname != GL_D3D12_FENCE_VALUE_EXT) {
874      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
875      return;
876   }
877
878   struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx,
879                                                                      semaphore);
880   if (!semObj)
881      return;
882
883   if (semObj->type != PIPE_FD_TYPE_TIMELINE_SEMAPHORE) {
884      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a D3D12 fence)", func);
885      return;
886   }
887
888   semObj->timeline_value = params[0];
889   ctx->screen->set_fence_timeline_value(ctx->screen, semObj->fence, params[0]);
890}
891
892void GLAPIENTRY
893_mesa_GetSemaphoreParameterui64vEXT(GLuint semaphore,
894                                    GLenum pname,
895                                    GLuint64 *params)
896{
897   GET_CURRENT_CONTEXT(ctx);
898   const char *func = "glGetSemaphoreParameterui64vEXT";
899
900   if (!ctx->Extensions.EXT_semaphore) {
901      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
902      return;
903   }
904
905   if (pname != GL_D3D12_FENCE_VALUE_EXT) {
906      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
907      return;
908   }
909
910   struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx,
911                                                                      semaphore);
912   if (!semObj)
913      return;
914
915   if (semObj->type != PIPE_FD_TYPE_TIMELINE_SEMAPHORE) {
916      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(Not a D3D12 fence)", func);
917      return;
918   }
919
920   params[0] = semObj->timeline_value;
921}
922
923void GLAPIENTRY
924_mesa_WaitSemaphoreEXT(GLuint semaphore,
925                       GLuint numBufferBarriers,
926                       const GLuint *buffers,
927                       GLuint numTextureBarriers,
928                       const GLuint *textures,
929                       const GLenum *srcLayouts)
930{
931   GET_CURRENT_CONTEXT(ctx);
932   struct gl_semaphore_object *semObj = NULL;
933   struct gl_buffer_object **bufObjs = NULL;
934   struct gl_texture_object **texObjs = NULL;
935
936   const char *func = "glWaitSemaphoreEXT";
937
938   if (!ctx->Extensions.EXT_semaphore) {
939      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
940      return;
941   }
942
943   ASSERT_OUTSIDE_BEGIN_END(ctx);
944
945   semObj = _mesa_lookup_semaphore_object(ctx, semaphore);
946   if (!semObj)
947      return;
948
949   FLUSH_VERTICES(ctx, 0, 0);
950
951   bufObjs = malloc(sizeof(struct gl_buffer_object *) * numBufferBarriers);
952   if (!bufObjs) {
953      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numBufferBarriers=%u)",
954                  func, numBufferBarriers);
955      goto end;
956   }
957
958   for (unsigned i = 0; i < numBufferBarriers; i++) {
959      bufObjs[i] = _mesa_lookup_bufferobj(ctx, buffers[i]);
960   }
961
962   texObjs = malloc(sizeof(struct gl_texture_object *) * numTextureBarriers);
963   if (!texObjs) {
964      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numTextureBarriers=%u)",
965                  func, numTextureBarriers);
966      goto end;
967   }
968
969   for (unsigned i = 0; i < numTextureBarriers; i++) {
970      texObjs[i] = _mesa_lookup_texture(ctx, textures[i]);
971   }
972
973   server_wait_semaphore(ctx, semObj,
974                         numBufferBarriers, bufObjs,
975                         numTextureBarriers, texObjs,
976                         srcLayouts);
977
978end:
979   free(bufObjs);
980   free(texObjs);
981}
982
983void GLAPIENTRY
984_mesa_SignalSemaphoreEXT(GLuint semaphore,
985                         GLuint numBufferBarriers,
986                         const GLuint *buffers,
987                         GLuint numTextureBarriers,
988                         const GLuint *textures,
989                         const GLenum *dstLayouts)
990{
991   GET_CURRENT_CONTEXT(ctx);
992   struct gl_semaphore_object *semObj = NULL;
993   struct gl_buffer_object **bufObjs = NULL;
994   struct gl_texture_object **texObjs = NULL;
995
996   const char *func = "glSignalSemaphoreEXT";
997
998   if (!ctx->Extensions.EXT_semaphore) {
999      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1000      return;
1001   }
1002
1003   ASSERT_OUTSIDE_BEGIN_END(ctx);
1004
1005   semObj = _mesa_lookup_semaphore_object(ctx, semaphore);
1006   if (!semObj)
1007      return;
1008
1009   FLUSH_VERTICES(ctx, 0, 0);
1010
1011   bufObjs = malloc(sizeof(struct gl_buffer_object *) * numBufferBarriers);
1012   if (!bufObjs) {
1013      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numBufferBarriers=%u)",
1014                  func, numBufferBarriers);
1015      goto end;
1016   }
1017
1018   for (unsigned i = 0; i < numBufferBarriers; i++) {
1019      bufObjs[i] = _mesa_lookup_bufferobj(ctx, buffers[i]);
1020   }
1021
1022   texObjs = malloc(sizeof(struct gl_texture_object *) * numTextureBarriers);
1023   if (!texObjs) {
1024      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numTextureBarriers=%u)",
1025                  func, numTextureBarriers);
1026      goto end;
1027   }
1028
1029   for (unsigned i = 0; i < numTextureBarriers; i++) {
1030      texObjs[i] = _mesa_lookup_texture(ctx, textures[i]);
1031   }
1032
1033   server_signal_semaphore(ctx, semObj,
1034                           numBufferBarriers, bufObjs,
1035                           numTextureBarriers, texObjs,
1036                           dstLayouts);
1037
1038end:
1039   free(bufObjs);
1040   free(texObjs);
1041}
1042
1043void GLAPIENTRY
1044_mesa_ImportMemoryFdEXT(GLuint memory,
1045                        GLuint64 size,
1046                        GLenum handleType,
1047                        GLint fd)
1048{
1049   GET_CURRENT_CONTEXT(ctx);
1050
1051   const char *func = "glImportMemoryFdEXT";
1052
1053   if (!ctx->Extensions.EXT_memory_object_fd) {
1054      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1055      return;
1056   }
1057
1058   if (handleType != GL_HANDLE_TYPE_OPAQUE_FD_EXT) {
1059      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1060      return;
1061   }
1062
1063   struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory);
1064   if (!memObj)
1065      return;
1066
1067   import_memoryobj_fd(ctx, memObj, size, fd);
1068   memObj->Immutable = GL_TRUE;
1069}
1070
1071void GLAPIENTRY
1072_mesa_ImportMemoryWin32HandleEXT(GLuint memory,
1073                                 GLuint64 size,
1074                                 GLenum handleType,
1075                                 void *handle)
1076{
1077   GET_CURRENT_CONTEXT(ctx);
1078
1079   const char *func = "glImportMemoryWin32HandleEXT";
1080
1081   if (!ctx->Extensions.EXT_memory_object_win32) {
1082      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1083      return;
1084   }
1085
1086   if (handleType != GL_HANDLE_TYPE_OPAQUE_WIN32_EXT &&
1087       handleType != GL_HANDLE_TYPE_D3D11_IMAGE_EXT &&
1088       handleType != GL_HANDLE_TYPE_D3D12_RESOURCE_EXT &&
1089       handleType != GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT) {
1090      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1091      return;
1092   }
1093
1094   struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory);
1095   if (!memObj)
1096      return;
1097
1098   import_memoryobj_win32(ctx, memObj, size, handle, NULL);
1099   memObj->Immutable = GL_TRUE;
1100}
1101
1102void GLAPIENTRY
1103_mesa_ImportMemoryWin32NameEXT(GLuint memory,
1104                                 GLuint64 size,
1105                                 GLenum handleType,
1106                                 const void *name)
1107{
1108   GET_CURRENT_CONTEXT(ctx);
1109
1110   const char *func = "glImportMemoryWin32NameEXT";
1111
1112   if (!ctx->Extensions.EXT_memory_object_win32) {
1113      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1114      return;
1115   }
1116
1117   if (handleType != GL_HANDLE_TYPE_OPAQUE_WIN32_EXT &&
1118       handleType != GL_HANDLE_TYPE_D3D11_IMAGE_EXT &&
1119       handleType != GL_HANDLE_TYPE_D3D12_RESOURCE_EXT &&
1120       handleType != GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT) {
1121      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1122      return;
1123   }
1124
1125   struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory);
1126   if (!memObj)
1127      return;
1128
1129   import_memoryobj_win32(ctx, memObj, size, NULL, name);
1130   memObj->Immutable = GL_TRUE;
1131}
1132
1133void GLAPIENTRY
1134_mesa_ImportSemaphoreFdEXT(GLuint semaphore,
1135                           GLenum handleType,
1136                           GLint fd)
1137{
1138   GET_CURRENT_CONTEXT(ctx);
1139
1140   const char *func = "glImportSemaphoreFdEXT";
1141
1142   if (!ctx->Extensions.EXT_semaphore_fd) {
1143      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1144      return;
1145   }
1146
1147   if (handleType != GL_HANDLE_TYPE_OPAQUE_FD_EXT) {
1148      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1149      return;
1150   }
1151
1152   struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx,
1153                                                                      semaphore);
1154   if (!semObj)
1155      return;
1156
1157   if (semObj == &DummySemaphoreObject) {
1158      semObj = semaphoreobj_alloc(ctx, semaphore);
1159      if (!semObj) {
1160         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1161         return;
1162      }
1163      _mesa_HashInsert(ctx->Shared->SemaphoreObjects, semaphore, semObj, true);
1164   }
1165
1166   import_semaphoreobj_fd(ctx, semObj, fd);
1167}
1168
1169void GLAPIENTRY
1170_mesa_ImportSemaphoreWin32HandleEXT(GLuint semaphore,
1171                           GLenum handleType,
1172                           void *handle)
1173{
1174   GET_CURRENT_CONTEXT(ctx);
1175
1176   const char *func = "glImportSemaphoreWin32HandleEXT";
1177
1178   if (!ctx->Extensions.EXT_semaphore_win32) {
1179      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1180      return;
1181   }
1182
1183   if (handleType != GL_HANDLE_TYPE_OPAQUE_WIN32_EXT &&
1184       handleType != GL_HANDLE_TYPE_D3D12_FENCE_EXT) {
1185      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1186      return;
1187   }
1188
1189   if (handleType == GL_HANDLE_TYPE_D3D12_FENCE_EXT &&
1190       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TIMELINE_SEMAPHORE_IMPORT)) {
1191      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1192   }
1193
1194   struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx,
1195                                                                      semaphore);
1196   if (!semObj)
1197      return;
1198
1199   if (semObj == &DummySemaphoreObject) {
1200      semObj = semaphoreobj_alloc(ctx, semaphore);
1201      if (!semObj) {
1202         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1203         return;
1204      }
1205      _mesa_HashInsert(ctx->Shared->SemaphoreObjects, semaphore, semObj, true);
1206   }
1207
1208   enum pipe_fd_type type = handleType == GL_HANDLE_TYPE_D3D12_FENCE_EXT ?
1209      PIPE_FD_TYPE_TIMELINE_SEMAPHORE : PIPE_FD_TYPE_SYNCOBJ;
1210   import_semaphoreobj_win32(ctx, semObj, handle, NULL, type);
1211}
1212
1213void GLAPIENTRY
1214_mesa_ImportSemaphoreWin32NameEXT(GLuint semaphore,
1215                                  GLenum handleType,
1216                                  const void *name)
1217{
1218   GET_CURRENT_CONTEXT(ctx);
1219
1220   const char *func = "glImportSemaphoreWin32HandleEXT";
1221
1222   if (!ctx->Extensions.EXT_semaphore_win32) {
1223      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
1224      return;
1225   }
1226
1227   if (handleType != GL_HANDLE_TYPE_OPAQUE_WIN32_EXT &&
1228       handleType != GL_HANDLE_TYPE_D3D12_FENCE_EXT) {
1229      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1230      return;
1231   }
1232
1233   if (handleType == GL_HANDLE_TYPE_D3D12_FENCE_EXT &&
1234       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TIMELINE_SEMAPHORE_IMPORT)) {
1235      _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType);
1236   }
1237
1238   struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx,
1239                                                                      semaphore);
1240   if (!semObj)
1241      return;
1242
1243   if (semObj == &DummySemaphoreObject) {
1244      semObj = semaphoreobj_alloc(ctx, semaphore);
1245      if (!semObj) {
1246         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1247         return;
1248      }
1249      _mesa_HashInsert(ctx->Shared->SemaphoreObjects, semaphore, semObj, true);
1250   }
1251
1252   enum pipe_fd_type type = handleType == GL_HANDLE_TYPE_D3D12_FENCE_EXT ?
1253      PIPE_FD_TYPE_TIMELINE_SEMAPHORE : PIPE_FD_TYPE_SYNCOBJ;
1254   import_semaphoreobj_win32(ctx, semObj, NULL, name, type);
1255}
1256