<commit_before>/*
 * Copyright © 2015 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include "private.h"

static int
anv_env_get_int(const char *name)
{
   const char *val = getenv(name);

   if (!val)
      return 0;

   return strtol(val, NULL, 0);
}

static VkResult
fill_physical_device(struct anv_physical_device *device,
                     struct anv_instance *instance,
                     const char *path)
{
   int fd;
   
   fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
   if (fd < 0)
      return vk_error(VK_ERROR_UNAVAILABLE);

   device->instance = instance;
   device->path = path;
   
   device->chipset_id = anv_env_get_int("INTEL_DEVID_OVERRIDE");
   device->no_hw = false;
   if (device->chipset_id) {
      /* INTEL_DEVID_OVERRIDE implies INTEL_NO_HW. */
      device->no_hw = true;
   } else {
      device->chipset_id = anv_gem_get_param(fd, I915_PARAM_CHIPSET_ID);
   }
   if (!device->chipset_id)
      goto fail;

   device->name = brw_get_device_name(device->chipset_id);
   device->info = brw_get_device_info(device->chipset_id, -1);
   if (!device->info)
      goto fail;
   
   if (!anv_gem_get_param(fd, I915_PARAM_HAS_WAIT_TIMEOUT))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_EXECBUF2))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_LLC))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_CONSTANTS))
      goto fail;

   close(fd);
   
   return VK_SUCCESS;
   
 fail:
   close(fd);

   return vk_error(VK_ERROR_UNAVAILABLE);
}

static void *default_alloc(
    void*                                       pUserData,
    size_t                                      size,
    size_t                                      alignment,
    VkSystemAllocType                           allocType)
{
   return malloc(size);
}

static void default_free(
    void*                                       pUserData,
    void*                                       pMem)
{
   free(pMem);
}

static const VkAllocCallbacks default_alloc_callbacks = {
   .pUserData = NULL,
   .pfnAlloc = default_alloc,
   .pfnFree = default_free
};

VkResult anv_CreateInstance(
    const VkInstanceCreateInfo*                 pCreateInfo,
    VkInstance*                                 pInstance)
{
   struct anv_instance *instance;
   const VkAllocCallbacks *alloc_callbacks = &default_alloc_callbacks;
   void *user_data = NULL;
   VkResult result;

   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);

   if (pCreateInfo->pAllocCb) {
      alloc_callbacks = pCreateInfo->pAllocCb;
      user_data = pCreateInfo->pAllocCb->pUserData;
   }
   instance = alloc_callbacks->pfnAlloc(user_data, sizeof(*instance), 8,
                                        VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (!instance)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   instance->pAllocUserData = alloc_callbacks->pUserData;
   instance->pfnAlloc = alloc_callbacks->pfnAlloc;
   instance->pfnFree = alloc_callbacks->pfnFree;
   instance->apiVersion = pCreateInfo->pAppInfo->apiVersion;

   instance->physicalDeviceCount = 0;
   result = fill_physical_device(&instance->physicalDevice,
                                 instance, "/dev/dri/renderD128");
   if (result == VK_SUCCESS)
      instance->physicalDeviceCount++;

   *pInstance = (VkInstance) instance;

   return VK_SUCCESS;
}

VkResult anv_DestroyInstance(
    VkInstance                                  _instance)
{
   struct anv_instance *instance = (struct anv_instance *) _instance;

   instance->pfnFree(instance->pAllocUserData, instance);

   return VK_SUCCESS;
}

VkResult anv_EnumeratePhysicalDevices(
    VkInstance                                  _instance,
    uint32_t*                                   pPhysicalDeviceCount,
    VkPhysicalDevice*                           pPhysicalDevices)
{
   struct anv_instance *instance = (struct anv_instance *) _instance;

   if (*pPhysicalDeviceCount >= 1)
      pPhysicalDevices[0] = (VkPhysicalDevice) &instance->physicalDevice;
   *pPhysicalDeviceCount = instance->physicalDeviceCount;

   return VK_SUCCESS;
}

VkResult anv_GetPhysicalDeviceInfo(
    VkPhysicalDevice                            physicalDevice,
    VkPhysicalDeviceInfoType                    infoType,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   struct anv_physical_device *device = (struct anv_physical_device *) physicalDevice;
   VkPhysicalDeviceProperties *properties;
   VkPhysicalDevicePerformance *performance;
   VkPhysicalDeviceQueueProperties *queue_properties;
   VkPhysicalDeviceMemoryProperties *memory_properties;
   uint64_t ns_per_tick = 80;
   
   switch (infoType) {
   case VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES:
      properties = pData;
      assert(*pDataSize >= sizeof(*properties));
      *pDataSize = sizeof(*properties); /* Assuming we have to return the size of our struct. */

      properties->apiVersion = 1;
      properties->driverVersion = 1;
      properties->vendorId = 0x8086;
      properties->deviceId = device->chipset_id;
      properties->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
      strcpy(properties->deviceName, device->name);
      properties->maxInlineMemoryUpdateSize = 0;
      properties->maxBoundDescriptorSets = 0;
      properties->maxThreadGroupSize = 0;
      properties->timestampFrequency = 1000 * 1000 * 1000 / ns_per_tick;
      properties->multiColorAttachmentClears = 0;
      properties->maxDescriptorSets = 2;
      properties->maxViewports = 16;
      properties->maxColorAttachments = 8;
      return VK_SUCCESS;

   case VK_PHYSICAL_DEVICE_INFO_TYPE_PERFORMANCE:
      performance = pData;
      assert(*pDataSize >= sizeof(*performance));
      *pDataSize = sizeof(*performance); /* Assuming we have to return the size of our struct. */

      performance->maxDeviceClock = 1.0;
      performance->aluPerClock = 1.0;
      performance->texPerClock = 1.0;
      performance->primsPerClock = 1.0;
      performance->pixelsPerClock = 1.0;
      return VK_SUCCESS;
      
   case VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PROPERTIES:
      queue_properties = pData;
      assert(*pDataSize >= sizeof(*queue_properties));
      *pDataSize = sizeof(*queue_properties);

      queue_properties->queueFlags = 0;
      queue_properties->queueCount = 1;
      queue_properties->maxAtomicCounters = 0;
      queue_properties->supportsTimestamps = 0;
      queue_properties->maxMemReferences = 0;
      return VK_SUCCESS;

   case VK_PHYSICAL_DEVICE_INFO_TYPE_MEMORY_PROPERTIES:
      memory_properties = pData;
      assert(*pDataSize >= sizeof(*memory_properties));
      *pDataSize = sizeof(*memory_properties);

      memory_properties->supportsMigration = false;
      memory_properties->supportsPinning = false;
      return VK_SUCCESS;

   default:
      return VK_UNSUPPORTED;
   }

}

void * vkGetProcAddr(
    VkPhysicalDevice                            physicalDevice,
    const char*                                 pName)
{
   return anv_lookup_entrypoint(pName);
}

static void
parse_debug_flags(struct anv_device *device)
{
   const char *debug, *p, *end;

   debug = getenv("INTEL_DEBUG");
   device->dump_aub = false;
   if (debug) {
      for (p = debug; *p; p = end + 1) {
         end = strchrnul(p, ',');
         if (end - p == 3 && memcmp(p, "aub", 3) == 0)
            device->dump_aub = true;
         if (end - p == 5 && memcmp(p, "no_hw", 5) == 0)
            device->no_hw = true;
         if (*end == '\0')
            break;
      }
   }
}

VkResult anv_CreateDevice(
    VkPhysicalDevice                            _physicalDevice,
    const VkDeviceCreateInfo*                   pCreateInfo,
    VkDevice*                                   pDevice)
{
   struct anv_physical_device *physicalDevice =
      (struct anv_physical_device *) _physicalDevice;
   struct anv_instance *instance = physicalDevice->instance;
   struct anv_device *device;

   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);

   device = instance->pfnAlloc(instance->pAllocUserData,
                               sizeof(*device), 8,
                               VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (!device)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   device->no_hw = physicalDevice->no_hw;
   parse_debug_flags(device);

   device->instance = physicalDevice->instance;
   device->fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
   if (device->fd == -1)
      goto fail_device;
      
   device->context_id = anv_gem_create_context(device);
   if (device->context_id == -1)
      goto fail_fd;

   anv_block_pool_init(&device->dynamic_state_block_pool, device, 2048);

   anv_state_pool_init(&device->dynamic_state_pool,
                       &device->dynamic_state_block_pool);

   anv_block_pool_init(&device->instruction_block_pool, device, 2048);
   anv_block_pool_init(&device->surface_state_block_pool, device, 2048);

   anv_state_pool_init(&device->surface_state_pool,
                       &device->surface_state_block_pool);

   device->compiler = anv_compiler_create(device->fd);
   device->aub_writer = NULL;

   device->info = *physicalDevice->info;

   pthread_mutex_init(&device->mutex, NULL);

   anv_device_init_meta(device);

   *pDevice = (VkDevice) device;

   return VK_SUCCESS;

 fail_fd:
   close(device->fd);
 fail_device:
   anv_device_free(device, device);

   return vk_error(VK_ERROR_UNAVAILABLE);
}

VkResult anv_DestroyDevice(
    VkDevice                                    _device)
{
   struct anv_device *device = (struct anv_device *) _device;

   anv_compiler_destroy(device->compiler);

   anv_block_pool_finish(&device->dynamic_state_block_pool);
   anv_block_pool_finish(&device->instruction_block_pool);
   anv_block_pool_finish(&device->surface_state_block_pool);

   close(device->fd);

   if (device->aub_writer)
      anv_aub_writer_destroy(device->aub_writer);

   anv_device_free(device, device);

   return VK_SUCCESS;
}

VkResult anv_GetGlobalExtensionInfo(
    VkExtensionInfoType                         infoType,
    uint32_t                                    extensionIndex,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   uint32_t *count;

   switch (infoType) {
   case VK_EXTENSION_INFO_TYPE_COUNT:
      count = pData;
      assert(*pDataSize == 4);
      *count = 0;
      return VK_SUCCESS;
      
   case VK_EXTENSION_INFO_TYPE_PROPERTIES:
      return vk_error(VK_ERROR_INVALID_EXTENSION);
      
   default:
      return VK_UNSUPPORTED;
   }
}

VkResult anv_GetPhysicalDeviceExtensionInfo(
    VkPhysicalDevice                            physicalDevice,
    VkExtensionInfoType                         infoType,
    uint32_t                                    extensionIndex,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   uint32_t *count;

   switch (infoType) {
   case VK_EXTENSION_INFO_TYPE_COUNT:
      count = pData;
      assert(*pDataSize == 4);
      *count = 0;
      return VK_SUCCESS;
      
   case VK_EXTENSION_INFO_TYPE_PROPERTIES:
      return vk_error(VK_ERROR_INVALID_EXTENSION);
      
   default:
      return VK_UNSUPPORTED;
   }
}

VkResult anv_EnumerateLayers(
    VkPhysicalDevice                            physicalDevice,
    size_t                                      maxStringSize,
    size_t*                                     pLayerCount,
    char* const*                                pOutLayers,
    void*                                       pReserved)
{
   *pLayerCount = 0;

   return VK_SUCCESS;
}

VkResult anv_GetDeviceQueue(
    VkDevice                                    _device,
    uint32_t                                    queueNodeIndex,
    uint32_t                                    queueIndex,
    VkQueue*                                    pQueue)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_queue *queue;

   /* FIXME: Should allocate these at device create time. */

   queue = anv_device_alloc(device, sizeof(*queue), 8,
                            VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (queue == NULL)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   queue->device = device;
   queue->pool = &device->surface_state_pool;

   queue->completed_serial = anv_state_pool_alloc(queue->pool, 4, 4);
   *(uint32_t *)queue->completed_serial.map = 0;
   queue->next_serial = 1;

   *pQueue = (VkQueue) queue;

   return VK_SUCCESS;
}

static const uint32_t BATCH_SIZE = 8192;

VkResult
anv_batch_init(struct anv_batch *batch, struct anv_device *device)
{
   VkResult result;

   result = anv_bo_init_new(&batch->bo, device, BATCH_SIZE);
   if (result != VK_SUCCESS)
      return result;

   batch->bo.map =
      anv_gem_mmap(device, batch->bo.gem_handle, 0, BATCH_SIZE);
   if (batch->bo.map == NULL) {
      anv_gem_close(device, batch->bo.gem_handle);
      return vk_error(VK_ERROR_MEMORY_MAP_FAILED);
   }

   batch->cmd_relocs.num_relocs = 0;
   batch->surf_relocs.num_relocs = 0;
   batch->next = batch->bo.map;

   return VK_SUCCESS;
}

void
anv_batch_finish(struct anv_batch *batch, struct anv_device *device)
{
   anv_gem_munmap(batch->bo.map, BATCH_SIZE);
   anv_gem_close(device, batch->bo.gem_handle);
}

void
anv_batch_reset(struct anv_batch *batch)
{
   batch->next = batch->bo.map;
   batch->cmd_relocs.num_relocs = 0;
   batch->surf_relocs.num_relocs = 0;
}

void *
anv_batch_emit_dwords(struct anv_batch *batch, int num_dwords)
{
   void *p = batch->next;

   batch->next += num_dwords * 4;

   return p;
}

static void
anv_reloc_list_append(struct anv_reloc_list *list,
                      struct anv_reloc_list *other, uint32_t offset)
{
   uint32_t i, count;

   count = list->num_relocs;
   memcpy(&list->relocs[count], &other->relocs[0],
          other->num_relocs * sizeof(other->relocs[0]));
   memcpy(&list->reloc_bos[count], &other->reloc_bos[0],
          other->num_relocs * sizeof(other->reloc_bos[0]));
   for (i = 0; i < other->num_relocs; i++)
      list->relocs[i + count].offset += offset;

   count += other->num_relocs;
}

static uint64_t
anv_reloc_list_add(struct anv_reloc_list *list,
                   uint32_t offset,
                   struct anv_bo *target_bo, uint32_t delta)
{
   struct drm_i915_gem_relocation_entry *entry;
   int index;

   assert(list->num_relocs < ANV_BATCH_MAX_RELOCS);

   /* XXX: Can we use I915_EXEC_HANDLE_LUT? */
   index = list->num_relocs++;
   list->reloc_bos[index] = target_bo;
   entry = &list->relocs[index];
   entry->target_handle = target_bo->gem_handle;
   entry->delta = delta;
   entry->offset = offset;
   entry->presumed_offset = target_bo->offset;
   entry->read_domains = 0;
   entry->write_domain = 0;

   return target_bo->offset + delta;
}

void
anv_batch_emit_batch(struct anv_batch *batch, struct anv_batch *other)
{
   uint32_t size, offset;

   size = other->next - other->bo.map;
   memcpy(batch->next, other->bo.map, size);

   offset = batch->next - batch->bo.map;
   anv_reloc_list_append(&batch->cmd_relocs, &other->cmd_relocs, offset);
   anv_reloc_list_append(&batch->surf_relocs, &other->surf_relocs, offset);

   batch->next += size;
}

uint64_t
anv_batch_emit_reloc(struct anv_batch *batch,
                     void *location, struct anv_bo *bo, uint32_t delta)
{
   return anv_reloc_list_add(&batch->cmd_relocs,
                             location - batch->bo.map, bo, delta);
}

VkResult anv_QueueSubmit(
    VkQueue                                     _queue,
    uint32_t                                    cmdBufferCount,
    const VkCmdBuffer*                          pCmdBuffers,
    VkFence                                     fence)
{
   struct anv_queue *queue = (struct anv_queue *) _queue;
   struct anv_device *device = queue->device;
   int ret;

   for (uint32_t i = 0; i < cmdBufferCount; i++) {
      struct anv_cmd_buffer *cmd_buffer =
         (struct anv_cmd_buffer *) pCmdBuffers[i];

      if (device->dump_aub)
         anv_cmd_buffer_dump(cmd_buffer);

      if (!device->no_hw) {
         ret = anv_gem_execbuffer(device, &cmd_buffer->execbuf);
         if (ret != 0)
            return vk_error(VK_ERROR_UNKNOWN);

         for (uint32_t i = 0; i < cmd_buffer->bo_count; i++)
            cmd_buffer->exec2_bos[i]->offset = cmd_buffer->exec2_objects[i].offset;
      } else {
         *(uint32_t *)queue->completed_serial.map = cmd_buffer->serial;
      }
   }

   return VK_SUCCESS;
}

VkResult anv_QueueAddMemReferences(
    VkQueue                                     queue,
    uint32_t                                    count,
    const VkDeviceMemory*                       pMems)
{
   return VK_SUCCESS;
}

VkResult anv_QueueRemoveMemReferences(
    VkQueue                                     queue,
    uint32_t                                    count,
    const VkDeviceMemory*                       pMems)
{
   return VK_SUCCESS;
}

VkResult anv_QueueWaitIdle(
    VkQueue                                     _queue)
{
   struct anv_queue *queue = (struct anv_queue *) _queue;

   return vkDeviceWaitIdle((VkDevice) queue->device);
}

VkResult anv_DeviceWaitIdle(
    VkDevice                                    _device)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_state state;
   struct anv_batch batch;
   struct drm_i915_gem_execbuffer2 execbuf;
   struct drm_i915_gem_exec_object2 exec2_objects[1];
   struct anv_bo *bo = NULL;
   VkResult result;
   int64_t timeout;
   int ret;

   state = anv_state_pool_alloc(&device->dynamic_state_pool, 32, 32);
   bo = &device->dynamic_state_pool.block_pool->bo;
   batch.next = state.map;
   anv_batch_emit(&batch, GEN8_MI_BATCH_BUFFER_END);
   anv_batch_emit(&batch, GEN8_MI_NOOP);

   exec2_objects[0].handle = bo->gem_handle;
   exec2_objects[0].relocation_count = 0;
   exec2_objects[0].relocs_ptr = 0;
   exec2_objects[0].alignment = 0;
   exec2_objects[0].offset = bo->offset;
   exec2_objects[0].flags = 0;
   exec2_objects[0].rsvd1 = 0;
   exec2_objects[0].rsvd2 = 0;

   execbuf.buffers_ptr = (uintptr_t) exec2_objects;
   execbuf.buffer_count = 1;
   execbuf.batch_start_offset = state.offset;
   execbuf.batch_len = batch.next - state.map;
   execbuf.cliprects_ptr = 0;
   execbuf.num_cliprects = 0;
   execbuf.DR1 = 0;
   execbuf.DR4 = 0;

   execbuf.flags =
      I915_EXEC_HANDLE_LUT | I915_EXEC_NO_RELOC | I915_EXEC_RENDER;
   execbuf.rsvd1 = device->context_id;
   execbuf.rsvd2 = 0;

   if (!device->no_hw) {
      ret = anv_gem_execbuffer(device, &execbuf);
      if (ret != 0) {
         result = vk_error(VK_ERROR_UNKNOWN);
         goto fail;
      }

      timeout = INT64_MAX;
      ret = anv_gem_wait(device, bo->gem_handle, &timeout);
      if (ret != 0) {
         result = vk_error(VK_ERROR_UNKNOWN);
         goto fail;
      }
   }

   anv_state_pool_free(&device->dynamic_state_pool, state);

   return VK_SUCCESS;

 fail:
   anv_state_pool_free(&device->dynamic_state_pool, state);

   return result;
}

void *
anv_device_alloc(struct anv_device *            device,
                 size_t                         size,
                 size_t                         alignment,
                 VkSystemAllocType              allocType)
{
   return device->instance->pfnAlloc(device->instance->pAllocUserData,
                                     size,
                                     alignment,
                                     allocType);
}

void
anv_device_free(struct anv_device *             device,
                void *                          mem)
{
   return device->instance->pfnFree(device->instance->pAllocUserData,
                                    mem);
}

VkResult
anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size)
{
   bo->gem_handle = anv_gem_create(device, size);
   if (!bo->gem_handle)
      return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);

   bo->map = NULL;
   bo->index = 0;
   bo->offset = 0;
   bo->size = size;

   return VK_SUCCESS;
}

VkResult anv_AllocMemory(
    VkDevice                                    _device,
    const VkMemoryAllocInfo*                    pAllocInfo,
    VkDeviceMemory*                             pMem)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem;
   VkResult result;

   assert(pAllocInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO);

   mem = anv_device_alloc(device, sizeof(*mem), 8,
                          VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (mem == NULL)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   result = anv_bo_init_new(&mem->bo, device, pAllocInfo->allocationSize);
   if (result != VK_SUCCESS)
      goto fail;

   *pMem = (VkDeviceMemory) mem;

   return VK_SUCCESS;   

 fail:
   anv_device_free(device, mem);

   return result;
}

VkResult anv_FreeMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   if (mem->bo.map)
      anv_gem_munmap(mem->bo.map, mem->bo.size);

   if (mem->bo.gem_handle != 0)
      anv_gem_close(device, mem->bo.gem_handle);

   anv_device_free(device, mem);

   return VK_SUCCESS;
}

VkResult anv_SetMemoryPriority(
    VkDevice                                    device,
    VkDeviceMemory                              mem,
    VkMemoryPriority                            priority)
{
   return VK_SUCCESS;
}

VkResult anv_MapMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem,
    VkDeviceSize                                offset,
    VkDeviceSize                                size,
    VkMemoryMapFlags                            flags,
    void**                                      ppData)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   /* FIXME: Is this supposed to be thread safe? Since vkUnmapMemory() only
    * takes a VkDeviceMemory pointer, it seems like only one map of the memory
    * at a time is valid. We could just mmap up front and return an offset
    * pointer here, but that may exhaust virtual memory on 32 bit
    * userspace. */

   mem->map = anv_gem_mmap(device, mem->bo.gem_handle, offset, size);
   mem->map_size = size;

   *ppData = mem->map;
   
   return VK_SUCCESS;
}

VkResult anv_UnmapMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem)
{
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   anv_gem_munmap(mem->map, mem->map_size);

   return VK_SUCCESS;
}

VkResult anv_FlushMappedMemory(
    VkDevice                                    device,
    VkDeviceMemory                              mem,
    VkDeviceSize                                offset,
    VkDeviceSize                                size)
{
   /* clflush here for !llc platforms */

   return VK_SUCCESS;
}

VkResult anv_PinSystemMemory(
    VkDevice                                    device,
    const void*                                 pSysMem,
    size_t                                      memSize,
    VkDeviceMemory*                             pMem)
{
   return VK_SUCCESS;
}

VkResult anv_GetMultiDeviceCompatibility(
    VkPhysicalDevice                            physicalDevice0,
    VkPhysicalDevice                            physicalDevice1,
    VkPhysicalDeviceCompatibilityInfo*          pInfo)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenSharedMemory(
    VkDevice                                    device,
    const VkMemoryOpenInfo*                     pOpenInfo,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenSharedSemaphore(
    VkDevice                                    device,
    const VkSemaphoreOpenInfo*                  pOpenInfo,
    VkSemaphore*                                pSemaphore)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenPeerMemory(
    VkDevice                                    device,
    const VkPeerMemoryOpenInfo*                 pOpenInfo,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenPeerImage(
    VkDevice                                    device,
    const VkPeerImageOpenInfo*                  pOpenInfo,
    VkImage*                                    pImage,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

static VkResult
anv_instance_destructor(struct anv_device *     device,
                        VkObject                object)
{
   return vkDestroyInstance(object);
}

static VkResult
anv_noop_destructor(struct anv_device *         device,
                    VkObject                    object)
{
   return VK_SUCCESS;
}

static VkResult
anv_device_destructor(struct anv_device *       device,
                      VkObject                  object)
{
   return vkDestroyDevice(object);
}

static VkResult
anv_cmd_buffer_destructor(struct anv_device *   device,
                          VkObject              object)
{
   struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) object;
   
   anv_state_stream_finish(&cmd_buffer->surface_state_stream);
   anv_state_stream_finish(&cmd_buffer->dynamic_state_stream);
   anv_batch_finish(&cmd_buffer->batch, device);
   anv_device_free(device, cmd_buffer->exec2_objects);
   anv_device_free(device, cmd_buffer->exec2_bos);
   anv_device_free(device, cmd_buffer);

   return VK_SUCCESS;
}

static VkResult
anv_pipeline_destructor(struct anv_device *   device,
                        VkObject              object)
{
   struct anv_pipeline *pipeline = (struct anv_pipeline *) object;

   return anv_pipeline_destroy(pipeline);
}

static VkResult
anv_free_destructor(struct anv_device *         device,
                    VkObject                    object)
{
   anv_device_free(device, (void *) object);

   return VK_SUCCESS;
}

static VkResult (*anv_object_destructors[])(struct anv_device *device,
                                            VkObject object) = {
   [VK_OBJECT_TYPE_INSTANCE] =        anv_instance_destructor,
   [VK_OBJECT_TYPE_PHYSICAL_DEVICE] = anv_noop_destructor,
   [VK_OBJECT_TYPE_DEVICE] =          anv_device_destructor,
   [VK_OBJECT_TYPE_QUEUE] =           anv_noop_destructor,
   [VK_OBJECT_TYPE_COMMAND_BUFFER] =  anv_cmd_buffer_destructor,
   [VK_OBJECT_TYPE_PIPELINE] =        anv_pipeline_destructor,
   [VK_OBJECT_TYPE_SHADER] =          anv_free_destructor,
   [VK_OBJECT_TYPE_BUFFER] =          anv_free_destructor,
   [VK_OBJECT_TYPE_IMAGE] =           anv_free_destructor,
   [VK_OBJECT_TYPE_RENDER_PASS] =     anv_free_destructor
};

VkResult anv_DestroyObject(
    VkDevice                                    _device,
    VkObjectType                                objType,
    VkObject                                    object)
{
   struct anv_device *device = (struct anv_device *) _device;

   assert(objType < ARRAY_SIZE(anv_object_destructors) &&
          anv_object_destructors[objType] != NULL);
      
   return anv_object_destructors[objType](device, object);
}

static void
fill_memory_requirements(
    VkObjectType                                objType,
    VkObject                                    object,
    VkMemoryRequirements *                      memory_requirements)
{
   struct anv_buffer *buffer;
   struct anv_image *image;

   memory_requirements->memPropsAllowed =
      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
      VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT |
      /* VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT | */
      VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT |
      VK_MEMORY_PROPERTY_PREFER_HOST_LOCAL |
      VK_MEMORY_PROPERTY_SHAREABLE_BIT;

   memory_requirements->memPropsRequired = 0;

   switch (objType) {
   case VK_OBJECT_TYPE_BUFFER:
      buffer = (struct anv_buffer *) object;
      memory_requirements->size = buffer->size;
      memory_requirements->alignment = 16;
      break;
   case VK_OBJECT_TYPE_IMAGE:
      image = (struct anv_image *) object;
      memory_requirements->size = image->size;
      memory_requirements->alignment = image->alignment;
      break;
   default:
      memory_requirements->size = 0;
      break;
   }
}

VkResult anv_GetObjectInfo(
    VkDevice                                    _device,
    VkObjectType                                objType,
    VkObject                                    object,
    VkObjectInfoType                            infoType,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   VkMemoryRequirements memory_requirements;

   switch (infoType) {
   case VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS:
      fill_memory_requirements(objType, object, &memory_requirements);
      memcpy(pData, &memory_requirements,
             MIN2(*pDataSize, sizeof(memory_requirements)));
      *pDataSize = sizeof(memory_requirements);
      return VK_SUCCESS;

   case VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT:
   default:
      return VK_UNSUPPORTED;
   }

}<commit_msg>vk: Change pData/pDataSize semantics<commit_after>/*
 * Copyright © 2015 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include "private.h"

static int
anv_env_get_int(const char *name)
{
   const char *val = getenv(name);

   if (!val)
      return 0;

   return strtol(val, NULL, 0);
}

static VkResult
fill_physical_device(struct anv_physical_device *device,
                     struct anv_instance *instance,
                     const char *path)
{
   int fd;
   
   fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
   if (fd < 0)
      return vk_error(VK_ERROR_UNAVAILABLE);

   device->instance = instance;
   device->path = path;
   
   device->chipset_id = anv_env_get_int("INTEL_DEVID_OVERRIDE");
   device->no_hw = false;
   if (device->chipset_id) {
      /* INTEL_DEVID_OVERRIDE implies INTEL_NO_HW. */
      device->no_hw = true;
   } else {
      device->chipset_id = anv_gem_get_param(fd, I915_PARAM_CHIPSET_ID);
   }
   if (!device->chipset_id)
      goto fail;

   device->name = brw_get_device_name(device->chipset_id);
   device->info = brw_get_device_info(device->chipset_id, -1);
   if (!device->info)
      goto fail;
   
   if (!anv_gem_get_param(fd, I915_PARAM_HAS_WAIT_TIMEOUT))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_EXECBUF2))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_LLC))
      goto fail;

   if (!anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_CONSTANTS))
      goto fail;

   close(fd);
   
   return VK_SUCCESS;
   
 fail:
   close(fd);

   return vk_error(VK_ERROR_UNAVAILABLE);
}

static void *default_alloc(
    void*                                       pUserData,
    size_t                                      size,
    size_t                                      alignment,
    VkSystemAllocType                           allocType)
{
   return malloc(size);
}

static void default_free(
    void*                                       pUserData,
    void*                                       pMem)
{
   free(pMem);
}

static const VkAllocCallbacks default_alloc_callbacks = {
   .pUserData = NULL,
   .pfnAlloc = default_alloc,
   .pfnFree = default_free
};

VkResult anv_CreateInstance(
    const VkInstanceCreateInfo*                 pCreateInfo,
    VkInstance*                                 pInstance)
{
   struct anv_instance *instance;
   const VkAllocCallbacks *alloc_callbacks = &default_alloc_callbacks;
   void *user_data = NULL;
   VkResult result;

   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);

   if (pCreateInfo->pAllocCb) {
      alloc_callbacks = pCreateInfo->pAllocCb;
      user_data = pCreateInfo->pAllocCb->pUserData;
   }
   instance = alloc_callbacks->pfnAlloc(user_data, sizeof(*instance), 8,
                                        VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (!instance)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   instance->pAllocUserData = alloc_callbacks->pUserData;
   instance->pfnAlloc = alloc_callbacks->pfnAlloc;
   instance->pfnFree = alloc_callbacks->pfnFree;
   instance->apiVersion = pCreateInfo->pAppInfo->apiVersion;

   instance->physicalDeviceCount = 0;
   result = fill_physical_device(&instance->physicalDevice,
                                 instance, "/dev/dri/renderD128");
   if (result == VK_SUCCESS)
      instance->physicalDeviceCount++;

   *pInstance = (VkInstance) instance;

   return VK_SUCCESS;
}

VkResult anv_DestroyInstance(
    VkInstance                                  _instance)
{
   struct anv_instance *instance = (struct anv_instance *) _instance;

   instance->pfnFree(instance->pAllocUserData, instance);

   return VK_SUCCESS;
}

VkResult anv_EnumeratePhysicalDevices(
    VkInstance                                  _instance,
    uint32_t*                                   pPhysicalDeviceCount,
    VkPhysicalDevice*                           pPhysicalDevices)
{
   struct anv_instance *instance = (struct anv_instance *) _instance;

   if (*pPhysicalDeviceCount >= 1)
      pPhysicalDevices[0] = (VkPhysicalDevice) &instance->physicalDevice;
   *pPhysicalDeviceCount = instance->physicalDeviceCount;

   return VK_SUCCESS;
}

VkResult anv_GetPhysicalDeviceInfo(
    VkPhysicalDevice                            physicalDevice,
    VkPhysicalDeviceInfoType                    infoType,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   struct anv_physical_device *device = (struct anv_physical_device *) physicalDevice;
   VkPhysicalDeviceProperties *properties;
   VkPhysicalDevicePerformance *performance;
   VkPhysicalDeviceQueueProperties *queue_properties;
   VkPhysicalDeviceMemoryProperties *memory_properties;
   uint64_t ns_per_tick = 80;
   
   switch (infoType) {
   case VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES:
      properties = pData;

      *pDataSize = sizeof(*properties);
      if (pData == NULL)
         return VK_SUCCESS;

      properties->apiVersion = 1;
      properties->driverVersion = 1;
      properties->vendorId = 0x8086;
      properties->deviceId = device->chipset_id;
      properties->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
      strcpy(properties->deviceName, device->name);
      properties->maxInlineMemoryUpdateSize = 0;
      properties->maxBoundDescriptorSets = 0;
      properties->maxThreadGroupSize = 0;
      properties->timestampFrequency = 1000 * 1000 * 1000 / ns_per_tick;
      properties->multiColorAttachmentClears = 0;
      properties->maxDescriptorSets = 2;
      properties->maxViewports = 16;
      properties->maxColorAttachments = 8;
      return VK_SUCCESS;

   case VK_PHYSICAL_DEVICE_INFO_TYPE_PERFORMANCE:
      performance = pData;

      *pDataSize = sizeof(*performance);
      if (pData == NULL)
         return VK_SUCCESS;

      performance->maxDeviceClock = 1.0;
      performance->aluPerClock = 1.0;
      performance->texPerClock = 1.0;
      performance->primsPerClock = 1.0;
      performance->pixelsPerClock = 1.0;
      return VK_SUCCESS;
      
   case VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PROPERTIES:
      queue_properties = pData;

      *pDataSize = sizeof(*queue_properties);
      if (pData == NULL)
         return VK_SUCCESS;

      queue_properties->queueFlags = 0;
      queue_properties->queueCount = 1;
      queue_properties->maxAtomicCounters = 0;
      queue_properties->supportsTimestamps = 0;
      queue_properties->maxMemReferences = 0;
      return VK_SUCCESS;

   case VK_PHYSICAL_DEVICE_INFO_TYPE_MEMORY_PROPERTIES:
      memory_properties = pData;

      *pDataSize = sizeof(*memory_properties);
      if (pData == NULL)
         return VK_SUCCESS;

      memory_properties->supportsMigration = false;
      memory_properties->supportsPinning = false;
      return VK_SUCCESS;

   default:
      return VK_UNSUPPORTED;
   }

}

void * vkGetProcAddr(
    VkPhysicalDevice                            physicalDevice,
    const char*                                 pName)
{
   return anv_lookup_entrypoint(pName);
}

static void
parse_debug_flags(struct anv_device *device)
{
   const char *debug, *p, *end;

   debug = getenv("INTEL_DEBUG");
   device->dump_aub = false;
   if (debug) {
      for (p = debug; *p; p = end + 1) {
         end = strchrnul(p, ',');
         if (end - p == 3 && memcmp(p, "aub", 3) == 0)
            device->dump_aub = true;
         if (end - p == 5 && memcmp(p, "no_hw", 5) == 0)
            device->no_hw = true;
         if (*end == '\0')
            break;
      }
   }
}

VkResult anv_CreateDevice(
    VkPhysicalDevice                            _physicalDevice,
    const VkDeviceCreateInfo*                   pCreateInfo,
    VkDevice*                                   pDevice)
{
   struct anv_physical_device *physicalDevice =
      (struct anv_physical_device *) _physicalDevice;
   struct anv_instance *instance = physicalDevice->instance;
   struct anv_device *device;

   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);

   device = instance->pfnAlloc(instance->pAllocUserData,
                               sizeof(*device), 8,
                               VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (!device)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   device->no_hw = physicalDevice->no_hw;
   parse_debug_flags(device);

   device->instance = physicalDevice->instance;
   device->fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
   if (device->fd == -1)
      goto fail_device;
      
   device->context_id = anv_gem_create_context(device);
   if (device->context_id == -1)
      goto fail_fd;

   anv_block_pool_init(&device->dynamic_state_block_pool, device, 2048);

   anv_state_pool_init(&device->dynamic_state_pool,
                       &device->dynamic_state_block_pool);

   anv_block_pool_init(&device->instruction_block_pool, device, 2048);
   anv_block_pool_init(&device->surface_state_block_pool, device, 2048);

   anv_state_pool_init(&device->surface_state_pool,
                       &device->surface_state_block_pool);

   device->compiler = anv_compiler_create(device->fd);
   device->aub_writer = NULL;

   device->info = *physicalDevice->info;

   pthread_mutex_init(&device->mutex, NULL);

   anv_device_init_meta(device);

   *pDevice = (VkDevice) device;

   return VK_SUCCESS;

 fail_fd:
   close(device->fd);
 fail_device:
   anv_device_free(device, device);

   return vk_error(VK_ERROR_UNAVAILABLE);
}

VkResult anv_DestroyDevice(
    VkDevice                                    _device)
{
   struct anv_device *device = (struct anv_device *) _device;

   anv_compiler_destroy(device->compiler);

   anv_block_pool_finish(&device->dynamic_state_block_pool);
   anv_block_pool_finish(&device->instruction_block_pool);
   anv_block_pool_finish(&device->surface_state_block_pool);

   close(device->fd);

   if (device->aub_writer)
      anv_aub_writer_destroy(device->aub_writer);

   anv_device_free(device, device);

   return VK_SUCCESS;
}

VkResult anv_GetGlobalExtensionInfo(
    VkExtensionInfoType                         infoType,
    uint32_t                                    extensionIndex,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   uint32_t *count;

   switch (infoType) {
   case VK_EXTENSION_INFO_TYPE_COUNT:
      count = pData;
      assert(*pDataSize == 4);
      *count = 0;
      return VK_SUCCESS;
      
   case VK_EXTENSION_INFO_TYPE_PROPERTIES:
      return vk_error(VK_ERROR_INVALID_EXTENSION);
      
   default:
      return VK_UNSUPPORTED;
   }
}

VkResult anv_GetPhysicalDeviceExtensionInfo(
    VkPhysicalDevice                            physicalDevice,
    VkExtensionInfoType                         infoType,
    uint32_t                                    extensionIndex,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   uint32_t *count;

   switch (infoType) {
   case VK_EXTENSION_INFO_TYPE_COUNT:
      *pDataSize = 4;
      if (pData == NULL)
         return VK_SUCCESS;

      count = pData;
      *count = 0;
      return VK_SUCCESS;
      
   case VK_EXTENSION_INFO_TYPE_PROPERTIES:
      return vk_error(VK_ERROR_INVALID_EXTENSION);
      
   default:
      return VK_UNSUPPORTED;
   }
}

VkResult anv_EnumerateLayers(
    VkPhysicalDevice                            physicalDevice,
    size_t                                      maxStringSize,
    size_t*                                     pLayerCount,
    char* const*                                pOutLayers,
    void*                                       pReserved)
{
   *pLayerCount = 0;

   return VK_SUCCESS;
}

VkResult anv_GetDeviceQueue(
    VkDevice                                    _device,
    uint32_t                                    queueNodeIndex,
    uint32_t                                    queueIndex,
    VkQueue*                                    pQueue)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_queue *queue;

   /* FIXME: Should allocate these at device create time. */

   queue = anv_device_alloc(device, sizeof(*queue), 8,
                            VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (queue == NULL)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   queue->device = device;
   queue->pool = &device->surface_state_pool;

   queue->completed_serial = anv_state_pool_alloc(queue->pool, 4, 4);
   *(uint32_t *)queue->completed_serial.map = 0;
   queue->next_serial = 1;

   *pQueue = (VkQueue) queue;

   return VK_SUCCESS;
}

static const uint32_t BATCH_SIZE = 8192;

VkResult
anv_batch_init(struct anv_batch *batch, struct anv_device *device)
{
   VkResult result;

   result = anv_bo_init_new(&batch->bo, device, BATCH_SIZE);
   if (result != VK_SUCCESS)
      return result;

   batch->bo.map =
      anv_gem_mmap(device, batch->bo.gem_handle, 0, BATCH_SIZE);
   if (batch->bo.map == NULL) {
      anv_gem_close(device, batch->bo.gem_handle);
      return vk_error(VK_ERROR_MEMORY_MAP_FAILED);
   }

   batch->cmd_relocs.num_relocs = 0;
   batch->surf_relocs.num_relocs = 0;
   batch->next = batch->bo.map;

   return VK_SUCCESS;
}

void
anv_batch_finish(struct anv_batch *batch, struct anv_device *device)
{
   anv_gem_munmap(batch->bo.map, BATCH_SIZE);
   anv_gem_close(device, batch->bo.gem_handle);
}

void
anv_batch_reset(struct anv_batch *batch)
{
   batch->next = batch->bo.map;
   batch->cmd_relocs.num_relocs = 0;
   batch->surf_relocs.num_relocs = 0;
}

void *
anv_batch_emit_dwords(struct anv_batch *batch, int num_dwords)
{
   void *p = batch->next;

   batch->next += num_dwords * 4;

   return p;
}

static void
anv_reloc_list_append(struct anv_reloc_list *list,
                      struct anv_reloc_list *other, uint32_t offset)
{
   uint32_t i, count;

   count = list->num_relocs;
   memcpy(&list->relocs[count], &other->relocs[0],
          other->num_relocs * sizeof(other->relocs[0]));
   memcpy(&list->reloc_bos[count], &other->reloc_bos[0],
          other->num_relocs * sizeof(other->reloc_bos[0]));
   for (i = 0; i < other->num_relocs; i++)
      list->relocs[i + count].offset += offset;

   count += other->num_relocs;
}

static uint64_t
anv_reloc_list_add(struct anv_reloc_list *list,
                   uint32_t offset,
                   struct anv_bo *target_bo, uint32_t delta)
{
   struct drm_i915_gem_relocation_entry *entry;
   int index;

   assert(list->num_relocs < ANV_BATCH_MAX_RELOCS);

   /* XXX: Can we use I915_EXEC_HANDLE_LUT? */
   index = list->num_relocs++;
   list->reloc_bos[index] = target_bo;
   entry = &list->relocs[index];
   entry->target_handle = target_bo->gem_handle;
   entry->delta = delta;
   entry->offset = offset;
   entry->presumed_offset = target_bo->offset;
   entry->read_domains = 0;
   entry->write_domain = 0;

   return target_bo->offset + delta;
}

void
anv_batch_emit_batch(struct anv_batch *batch, struct anv_batch *other)
{
   uint32_t size, offset;

   size = other->next - other->bo.map;
   memcpy(batch->next, other->bo.map, size);

   offset = batch->next - batch->bo.map;
   anv_reloc_list_append(&batch->cmd_relocs, &other->cmd_relocs, offset);
   anv_reloc_list_append(&batch->surf_relocs, &other->surf_relocs, offset);

   batch->next += size;
}

uint64_t
anv_batch_emit_reloc(struct anv_batch *batch,
                     void *location, struct anv_bo *bo, uint32_t delta)
{
   return anv_reloc_list_add(&batch->cmd_relocs,
                             location - batch->bo.map, bo, delta);
}

VkResult anv_QueueSubmit(
    VkQueue                                     _queue,
    uint32_t                                    cmdBufferCount,
    const VkCmdBuffer*                          pCmdBuffers,
    VkFence                                     fence)
{
   struct anv_queue *queue = (struct anv_queue *) _queue;
   struct anv_device *device = queue->device;
   int ret;

   for (uint32_t i = 0; i < cmdBufferCount; i++) {
      struct anv_cmd_buffer *cmd_buffer =
         (struct anv_cmd_buffer *) pCmdBuffers[i];

      if (device->dump_aub)
         anv_cmd_buffer_dump(cmd_buffer);

      if (!device->no_hw) {
         ret = anv_gem_execbuffer(device, &cmd_buffer->execbuf);
         if (ret != 0)
            return vk_error(VK_ERROR_UNKNOWN);

         for (uint32_t i = 0; i < cmd_buffer->bo_count; i++)
            cmd_buffer->exec2_bos[i]->offset = cmd_buffer->exec2_objects[i].offset;
      } else {
         *(uint32_t *)queue->completed_serial.map = cmd_buffer->serial;
      }
   }

   return VK_SUCCESS;
}

VkResult anv_QueueAddMemReferences(
    VkQueue                                     queue,
    uint32_t                                    count,
    const VkDeviceMemory*                       pMems)
{
   return VK_SUCCESS;
}

VkResult anv_QueueRemoveMemReferences(
    VkQueue                                     queue,
    uint32_t                                    count,
    const VkDeviceMemory*                       pMems)
{
   return VK_SUCCESS;
}

VkResult anv_QueueWaitIdle(
    VkQueue                                     _queue)
{
   struct anv_queue *queue = (struct anv_queue *) _queue;

   return vkDeviceWaitIdle((VkDevice) queue->device);
}

VkResult anv_DeviceWaitIdle(
    VkDevice                                    _device)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_state state;
   struct anv_batch batch;
   struct drm_i915_gem_execbuffer2 execbuf;
   struct drm_i915_gem_exec_object2 exec2_objects[1];
   struct anv_bo *bo = NULL;
   VkResult result;
   int64_t timeout;
   int ret;

   state = anv_state_pool_alloc(&device->dynamic_state_pool, 32, 32);
   bo = &device->dynamic_state_pool.block_pool->bo;
   batch.next = state.map;
   anv_batch_emit(&batch, GEN8_MI_BATCH_BUFFER_END);
   anv_batch_emit(&batch, GEN8_MI_NOOP);

   exec2_objects[0].handle = bo->gem_handle;
   exec2_objects[0].relocation_count = 0;
   exec2_objects[0].relocs_ptr = 0;
   exec2_objects[0].alignment = 0;
   exec2_objects[0].offset = bo->offset;
   exec2_objects[0].flags = 0;
   exec2_objects[0].rsvd1 = 0;
   exec2_objects[0].rsvd2 = 0;

   execbuf.buffers_ptr = (uintptr_t) exec2_objects;
   execbuf.buffer_count = 1;
   execbuf.batch_start_offset = state.offset;
   execbuf.batch_len = batch.next - state.map;
   execbuf.cliprects_ptr = 0;
   execbuf.num_cliprects = 0;
   execbuf.DR1 = 0;
   execbuf.DR4 = 0;

   execbuf.flags =
      I915_EXEC_HANDLE_LUT | I915_EXEC_NO_RELOC | I915_EXEC_RENDER;
   execbuf.rsvd1 = device->context_id;
   execbuf.rsvd2 = 0;

   if (!device->no_hw) {
      ret = anv_gem_execbuffer(device, &execbuf);
      if (ret != 0) {
         result = vk_error(VK_ERROR_UNKNOWN);
         goto fail;
      }

      timeout = INT64_MAX;
      ret = anv_gem_wait(device, bo->gem_handle, &timeout);
      if (ret != 0) {
         result = vk_error(VK_ERROR_UNKNOWN);
         goto fail;
      }
   }

   anv_state_pool_free(&device->dynamic_state_pool, state);

   return VK_SUCCESS;

 fail:
   anv_state_pool_free(&device->dynamic_state_pool, state);

   return result;
}

void *
anv_device_alloc(struct anv_device *            device,
                 size_t                         size,
                 size_t                         alignment,
                 VkSystemAllocType              allocType)
{
   return device->instance->pfnAlloc(device->instance->pAllocUserData,
                                     size,
                                     alignment,
                                     allocType);
}

void
anv_device_free(struct anv_device *             device,
                void *                          mem)
{
   return device->instance->pfnFree(device->instance->pAllocUserData,
                                    mem);
}

VkResult
anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size)
{
   bo->gem_handle = anv_gem_create(device, size);
   if (!bo->gem_handle)
      return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);

   bo->map = NULL;
   bo->index = 0;
   bo->offset = 0;
   bo->size = size;

   return VK_SUCCESS;
}

VkResult anv_AllocMemory(
    VkDevice                                    _device,
    const VkMemoryAllocInfo*                    pAllocInfo,
    VkDeviceMemory*                             pMem)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem;
   VkResult result;

   assert(pAllocInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO);

   mem = anv_device_alloc(device, sizeof(*mem), 8,
                          VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
   if (mem == NULL)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   result = anv_bo_init_new(&mem->bo, device, pAllocInfo->allocationSize);
   if (result != VK_SUCCESS)
      goto fail;

   *pMem = (VkDeviceMemory) mem;

   return VK_SUCCESS;   

 fail:
   anv_device_free(device, mem);

   return result;
}

VkResult anv_FreeMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   if (mem->bo.map)
      anv_gem_munmap(mem->bo.map, mem->bo.size);

   if (mem->bo.gem_handle != 0)
      anv_gem_close(device, mem->bo.gem_handle);

   anv_device_free(device, mem);

   return VK_SUCCESS;
}

VkResult anv_SetMemoryPriority(
    VkDevice                                    device,
    VkDeviceMemory                              mem,
    VkMemoryPriority                            priority)
{
   return VK_SUCCESS;
}

VkResult anv_MapMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem,
    VkDeviceSize                                offset,
    VkDeviceSize                                size,
    VkMemoryMapFlags                            flags,
    void**                                      ppData)
{
   struct anv_device *device = (struct anv_device *) _device;
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   /* FIXME: Is this supposed to be thread safe? Since vkUnmapMemory() only
    * takes a VkDeviceMemory pointer, it seems like only one map of the memory
    * at a time is valid. We could just mmap up front and return an offset
    * pointer here, but that may exhaust virtual memory on 32 bit
    * userspace. */

   mem->map = anv_gem_mmap(device, mem->bo.gem_handle, offset, size);
   mem->map_size = size;

   *ppData = mem->map;
   
   return VK_SUCCESS;
}

VkResult anv_UnmapMemory(
    VkDevice                                    _device,
    VkDeviceMemory                              _mem)
{
   struct anv_device_memory *mem = (struct anv_device_memory *) _mem;

   anv_gem_munmap(mem->map, mem->map_size);

   return VK_SUCCESS;
}

VkResult anv_FlushMappedMemory(
    VkDevice                                    device,
    VkDeviceMemory                              mem,
    VkDeviceSize                                offset,
    VkDeviceSize                                size)
{
   /* clflush here for !llc platforms */

   return VK_SUCCESS;
}

VkResult anv_PinSystemMemory(
    VkDevice                                    device,
    const void*                                 pSysMem,
    size_t                                      memSize,
    VkDeviceMemory*                             pMem)
{
   return VK_SUCCESS;
}

VkResult anv_GetMultiDeviceCompatibility(
    VkPhysicalDevice                            physicalDevice0,
    VkPhysicalDevice                            physicalDevice1,
    VkPhysicalDeviceCompatibilityInfo*          pInfo)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenSharedMemory(
    VkDevice                                    device,
    const VkMemoryOpenInfo*                     pOpenInfo,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenSharedSemaphore(
    VkDevice                                    device,
    const VkSemaphoreOpenInfo*                  pOpenInfo,
    VkSemaphore*                                pSemaphore)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenPeerMemory(
    VkDevice                                    device,
    const VkPeerMemoryOpenInfo*                 pOpenInfo,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

VkResult anv_OpenPeerImage(
    VkDevice                                    device,
    const VkPeerImageOpenInfo*                  pOpenInfo,
    VkImage*                                    pImage,
    VkDeviceMemory*                             pMem)
{
   return VK_UNSUPPORTED;
}

static VkResult
anv_instance_destructor(struct anv_device *     device,
                        VkObject                object)
{
   return vkDestroyInstance(object);
}

static VkResult
anv_noop_destructor(struct anv_device *         device,
                    VkObject                    object)
{
   return VK_SUCCESS;
}

static VkResult
anv_device_destructor(struct anv_device *       device,
                      VkObject                  object)
{
   return vkDestroyDevice(object);
}

static VkResult
anv_cmd_buffer_destructor(struct anv_device *   device,
                          VkObject              object)
{
   struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) object;
   
   anv_state_stream_finish(&cmd_buffer->surface_state_stream);
   anv_state_stream_finish(&cmd_buffer->dynamic_state_stream);
   anv_batch_finish(&cmd_buffer->batch, device);
   anv_device_free(device, cmd_buffer->exec2_objects);
   anv_device_free(device, cmd_buffer->exec2_bos);
   anv_device_free(device, cmd_buffer);

   return VK_SUCCESS;
}

static VkResult
anv_pipeline_destructor(struct anv_device *   device,
                        VkObject              object)
{
   struct anv_pipeline *pipeline = (struct anv_pipeline *) object;

   return anv_pipeline_destroy(pipeline);
}

static VkResult
anv_free_destructor(struct anv_device *         device,
                    VkObject                    object)
{
   anv_device_free(device, (void *) object);

   return VK_SUCCESS;
}

static VkResult (*anv_object_destructors[])(struct anv_device *device,
                                            VkObject object) = {
   [VK_OBJECT_TYPE_INSTANCE] =        anv_instance_destructor,
   [VK_OBJECT_TYPE_PHYSICAL_DEVICE] = anv_noop_destructor,
   [VK_OBJECT_TYPE_DEVICE] =          anv_device_destructor,
   [VK_OBJECT_TYPE_QUEUE] =           anv_noop_destructor,
   [VK_OBJECT_TYPE_COMMAND_BUFFER] =  anv_cmd_buffer_destructor,
   [VK_OBJECT_TYPE_PIPELINE] =        anv_pipeline_destructor,
   [VK_OBJECT_TYPE_SHADER] =          anv_free_destructor,
   [VK_OBJECT_TYPE_BUFFER] =          anv_free_destructor,
   [VK_OBJECT_TYPE_IMAGE] =           anv_free_destructor,
   [VK_OBJECT_TYPE_RENDER_PASS] =     anv_free_destructor
};

VkResult anv_DestroyObject(
    VkDevice                                    _device,
    VkObjectType                                objType,
    VkObject                                    object)
{
   struct anv_device *device = (struct anv_device *) _device;

   assert(objType < ARRAY_SIZE(anv_object_destructors) &&
          anv_object_destructors[objType] != NULL);
      
   return anv_object_destructors[objType](device, object);
}

static void
fill_memory_requirements(
    VkObjectType                                objType,
    VkObject                                    object,
    VkMemoryRequirements *                      memory_requirements)
{
   struct anv_buffer *buffer;
   struct anv_image *image;

   memory_requirements->memPropsAllowed =
      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
      VK_MEMORY_PROPERTY_HOST_DEVICE_COHERENT_BIT |
      /* VK_MEMORY_PROPERTY_HOST_UNCACHED_BIT | */
      VK_MEMORY_PROPERTY_HOST_WRITE_COMBINED_BIT |
      VK_MEMORY_PROPERTY_PREFER_HOST_LOCAL |
      VK_MEMORY_PROPERTY_SHAREABLE_BIT;

   memory_requirements->memPropsRequired = 0;

   switch (objType) {
   case VK_OBJECT_TYPE_BUFFER:
      buffer = (struct anv_buffer *) object;
      memory_requirements->size = buffer->size;
      memory_requirements->alignment = 16;
      break;
   case VK_OBJECT_TYPE_IMAGE:
      image = (struct anv_image *) object;
      memory_requirements->size = image->size;
      memory_requirements->alignment = image->alignment;
      break;
   default:
      memory_requirements->size = 0;
      break;
   }
}

VkResult anv_GetObjectInfo(
    VkDevice                                    _device,
    VkObjectType                                objType,
    VkObject                                    object,
    VkObjectInfoType                            infoType,
    size_t*                                     pDataSize,
    void*                                       pData)
{
   VkMemoryRequirements memory_requirements;

   switch (infoType) {
   case VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS:
      *pDataSize = sizeof(memory_requirements);
      if (pData == NULL)
         return VK_SUCCESS;

      fill_memory_requirements(objType, object, &memory_requirements);
      memcpy(pData, &memory_requirements,
             MIN2(*pDataSize, sizeof(memory_requirements)));
      *pDataSize = sizeof(memory_requirements);
      return VK_SUCCESS;

   case VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT:
   default:
      return VK_UNSUPPORTED;
   }

}
{'fraction_non_alphanumeric': 0.083998168977243, 'fraction_numerical': 0.008926235940360972, 'mean_word_length': 2.167736923873641, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 469, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 134, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7349421', 'n_tokens_mistral': 19989, 'n_tokens_neox': 19033, 'n_words': 3663}