summaryrefslogtreecommitdiffstats
path: root/src/vulkan/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vulkan/device.c')
-rw-r--r--src/vulkan/device.c2634
1 files changed, 2634 insertions, 0 deletions
diff --git a/src/vulkan/device.c b/src/vulkan/device.c
new file mode 100644
index 00000000000..09b21e50c7c
--- /dev/null
+++ b/src/vulkan/device.c
@@ -0,0 +1,2634 @@
+/*
+ * 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 VKAPI vkCreateInstance(
+ 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 VKAPI vkDestroyInstance(
+ VkInstance _instance)
+{
+ struct anv_instance *instance = (struct anv_instance *) _instance;
+
+ instance->pfnFree(instance->pAllocUserData, instance);
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkEnumeratePhysicalDevices(
+ 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 VKAPI vkGetPhysicalDeviceInfo(
+ 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 NULL;
+}
+
+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 VKAPI vkCreateDevice(
+ 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->dyn_state_block_pool, device, 2048);
+
+ anv_state_pool_init(&device->dyn_state_pool,
+ &device->dyn_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);
+
+ *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 VKAPI vkDestroyDevice(
+ VkDevice _device)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+
+ anv_compiler_destroy(device->compiler);
+
+ anv_block_pool_finish(&device->dyn_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 VKAPI vkGetGlobalExtensionInfo(
+ 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 VKAPI vkGetPhysicalDeviceExtensionInfo(
+ 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 VKAPI vkEnumerateLayers(
+ VkPhysicalDevice physicalDevice,
+ size_t maxStringSize,
+ size_t* pLayerCount,
+ char* const* pOutLayers,
+ void* pReserved)
+{
+ *pLayerCount = 0;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkGetDeviceQueue(
+ 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 VKAPI vkQueueSubmit(
+ VkQueue _queue,
+ uint32_t cmdBufferCount,
+ const VkCmdBuffer* pCmdBuffers,
+ VkFence fence)
+{
+ struct anv_queue *queue = (struct anv_queue *) _queue;
+ struct anv_device *device = queue->device;
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) pCmdBuffers[0];
+ int ret;
+
+ assert(cmdBufferCount == 1);
+
+ 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)
+ goto fail;
+
+ 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;
+
+ fail:
+ pthread_mutex_unlock(&device->mutex);
+
+ return vk_error(VK_ERROR_UNKNOWN);
+}
+
+VkResult VKAPI vkQueueAddMemReferences(
+ VkQueue queue,
+ uint32_t count,
+ const VkDeviceMemory* pMems)
+{
+ return VK_SUCCESS;
+}
+
+VkResult vkQueueRemoveMemReferences(
+ VkQueue queue,
+ uint32_t count,
+ const VkDeviceMemory* pMems)
+{
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkQueueWaitIdle(
+ VkQueue _queue)
+{
+ struct anv_queue *queue = (struct anv_queue *) _queue;
+
+ return vkDeviceWaitIdle((VkDevice) queue->device);
+}
+
+VkResult VKAPI vkDeviceWaitIdle(
+ 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->dyn_state_pool, 32, 32);
+ bo = &device->dyn_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->dyn_state_pool, state);
+
+ return VK_SUCCESS;
+
+ fail:
+ anv_state_pool_free(&device->dyn_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 VKAPI vkAllocMemory(
+ 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 VKAPI vkFreeMemory(
+ 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 VKAPI vkSetMemoryPriority(
+ VkDevice device,
+ VkDeviceMemory mem,
+ VkMemoryPriority priority)
+{
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkMapMemory(
+ 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 VKAPI vkUnmapMemory(
+ 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 VKAPI vkFlushMappedMemory(
+ VkDevice device,
+ VkDeviceMemory mem,
+ VkDeviceSize offset,
+ VkDeviceSize size)
+{
+ /* clflush here for !llc platforms */
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkPinSystemMemory(
+ VkDevice device,
+ const void* pSysMem,
+ size_t memSize,
+ VkDeviceMemory* pMem)
+{
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkGetMultiDeviceCompatibility(
+ VkPhysicalDevice physicalDevice0,
+ VkPhysicalDevice physicalDevice1,
+ VkPhysicalDeviceCompatibilityInfo* pInfo)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkOpenSharedMemory(
+ VkDevice device,
+ const VkMemoryOpenInfo* pOpenInfo,
+ VkDeviceMemory* pMem)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkOpenSharedSemaphore(
+ VkDevice device,
+ const VkSemaphoreOpenInfo* pOpenInfo,
+ VkSemaphore* pSemaphore)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkOpenPeerMemory(
+ VkDevice device,
+ const VkPeerMemoryOpenInfo* pOpenInfo,
+ VkDeviceMemory* pMem)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkOpenPeerImage(
+ 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_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 VKAPI vkDestroyObject(
+ 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 VKAPI vkGetObjectInfo(
+ 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;
+ }
+
+}
+
+VkResult VKAPI vkQueueBindObjectMemory(
+ VkQueue queue,
+ VkObjectType objType,
+ VkObject object,
+ uint32_t allocationIdx,
+ VkDeviceMemory _mem,
+ VkDeviceSize memOffset)
+{
+ struct anv_buffer *buffer;
+ struct anv_image *image;
+ struct anv_device_memory *mem = (struct anv_device_memory *) _mem;
+
+ switch (objType) {
+ case VK_OBJECT_TYPE_BUFFER:
+ buffer = (struct anv_buffer *) object;
+ buffer->mem = mem;
+ buffer->offset = memOffset;
+ break;
+ case VK_OBJECT_TYPE_IMAGE:
+ image = (struct anv_image *) object;
+ image->mem = mem;
+ image->offset = memOffset;
+ break;
+ default:
+ break;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkQueueBindObjectMemoryRange(
+ VkQueue queue,
+ VkObjectType objType,
+ VkObject object,
+ uint32_t allocationIdx,
+ VkDeviceSize rangeOffset,
+ VkDeviceSize rangeSize,
+ VkDeviceMemory mem,
+ VkDeviceSize memOffset)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult vkQueueBindImageMemoryRange(
+ VkQueue queue,
+ VkImage image,
+ uint32_t allocationIdx,
+ const VkImageMemoryBindInfo* pBindInfo,
+ VkDeviceMemory mem,
+ VkDeviceSize memOffset)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkCreateFence(
+ VkDevice device,
+ const VkFenceCreateInfo* pCreateInfo,
+ VkFence* pFence)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkResetFences(
+ VkDevice device,
+ uint32_t fenceCount,
+ VkFence* pFences)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkGetFenceStatus(
+ VkDevice device,
+ VkFence fence)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkWaitForFences(
+ VkDevice device,
+ uint32_t fenceCount,
+ const VkFence* pFences,
+ bool32_t waitAll,
+ uint64_t timeout)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Queue semaphore functions
+
+VkResult VKAPI vkCreateSemaphore(
+ VkDevice device,
+ const VkSemaphoreCreateInfo* pCreateInfo,
+ VkSemaphore* pSemaphore)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkQueueSignalSemaphore(
+ VkQueue queue,
+ VkSemaphore semaphore)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkQueueWaitSemaphore(
+ VkQueue queue,
+ VkSemaphore semaphore)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Event functions
+
+VkResult VKAPI vkCreateEvent(
+ VkDevice device,
+ const VkEventCreateInfo* pCreateInfo,
+ VkEvent* pEvent)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkGetEventStatus(
+ VkDevice device,
+ VkEvent event)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkSetEvent(
+ VkDevice device,
+ VkEvent event)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkResetEvent(
+ VkDevice device,
+ VkEvent event)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Query functions
+
+struct anv_query_pool {
+ VkQueryType type;
+ uint32_t slots;
+ struct anv_bo bo;
+};
+
+VkResult VKAPI vkCreateQueryPool(
+ VkDevice _device,
+ const VkQueryPoolCreateInfo* pCreateInfo,
+ VkQueryPool* pQueryPool)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_query_pool *pool;
+ VkResult result;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO);
+
+ pool = anv_device_alloc(device, sizeof(*pool), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (pool == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ pool->type = pCreateInfo->queryType;
+ result = anv_bo_init_new(&pool->bo, device, pCreateInfo->slots * 16);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ *pQueryPool = (VkQueryPool) pool;
+
+ return VK_SUCCESS;
+
+ fail:
+ anv_device_free(device, pool);
+
+ return result;
+}
+
+VkResult VKAPI vkGetQueryPoolResults(
+ VkDevice device,
+ VkQueryPool queryPool,
+ uint32_t startQuery,
+ uint32_t queryCount,
+ size_t* pDataSize,
+ void* pData,
+ VkQueryResultFlags flags)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Format capabilities
+
+VkResult VKAPI vkGetFormatInfo(
+ VkDevice device,
+ VkFormat format,
+ VkFormatInfoType infoType,
+ size_t* pDataSize,
+ void* pData)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Buffer functions
+
+VkResult VKAPI vkCreateBuffer(
+ VkDevice _device,
+ const VkBufferCreateInfo* pCreateInfo,
+ VkBuffer* pBuffer)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_buffer *buffer;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
+
+ buffer = anv_device_alloc(device, sizeof(*buffer), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (buffer == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ buffer->size = pCreateInfo->size;
+ buffer->mem = NULL;
+ buffer->offset = 0;
+
+ *pBuffer = (VkBuffer) buffer;
+
+ return VK_SUCCESS;
+}
+
+// Buffer view functions
+
+VkResult VKAPI vkCreateBufferView(
+ VkDevice _device,
+ const VkBufferViewCreateInfo* pCreateInfo,
+ VkBufferView* pView)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_buffer_view *view;
+ const struct anv_format *format;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO);
+
+ view = anv_device_alloc(device, sizeof(*view), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (view == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ view->buffer = (struct anv_buffer *) pCreateInfo->buffer;
+ view->offset = pCreateInfo->offset;
+ view->surface_state =
+ anv_state_pool_alloc(&device->surface_state_pool, 64, 64);
+
+ format = anv_format_for_vk_format(pCreateInfo->format);
+ /* This assumes RGBA float format. */
+ uint32_t stride = 4;
+ uint32_t num_elements = pCreateInfo->range / stride;
+ struct GEN8_RENDER_SURFACE_STATE surface_state = {
+ .SurfaceType = SURFTYPE_BUFFER,
+ .SurfaceArray = false,
+ .SurfaceFormat = format->format,
+ .SurfaceVerticalAlignment = VALIGN4,
+ .SurfaceHorizontalAlignment = HALIGN4,
+ .TileMode = LINEAR,
+ .VerticalLineStride = 0,
+ .VerticalLineStrideOffset = 0,
+ .SamplerL2BypassModeDisable = true,
+ .RenderCacheReadWriteMode = WriteOnlyCache,
+ .MemoryObjectControlState = 0, /* FIXME: MOCS */
+ .BaseMipLevel = 0,
+ .SurfaceQPitch = 0,
+ .Height = (num_elements >> 7) & 0x3fff,
+ .Width = num_elements & 0x7f,
+ .Depth = (num_elements >> 21) & 0x3f,
+ .SurfacePitch = stride - 1,
+ .MinimumArrayElement = 0,
+ .NumberofMultisamples = MULTISAMPLECOUNT_1,
+ .XOffset = 0,
+ .YOffset = 0,
+ .SurfaceMinLOD = 0,
+ .MIPCountLOD = 0,
+ .AuxiliarySurfaceMode = AUX_NONE,
+ .RedClearColor = 0,
+ .GreenClearColor = 0,
+ .BlueClearColor = 0,
+ .AlphaClearColor = 0,
+ .ShaderChannelSelectRed = SCS_RED,
+ .ShaderChannelSelectGreen = SCS_GREEN,
+ .ShaderChannelSelectBlue = SCS_BLUE,
+ .ShaderChannelSelectAlpha = SCS_ALPHA,
+ .ResourceMinLOD = 0,
+ /* FIXME: We assume that the image must be bound at this time. */
+ .SurfaceBaseAddress = { NULL, view->buffer->offset + view->offset },
+ };
+
+ GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state);
+
+ *pView = (VkImageView) view;
+
+ return VK_SUCCESS;
+}
+
+// Sampler functions
+
+struct anv_sampler {
+ uint32_t state[4];
+};
+
+VkResult VKAPI vkCreateSampler(
+ VkDevice _device,
+ const VkSamplerCreateInfo* pCreateInfo,
+ VkSampler* pSampler)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_sampler *sampler;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
+
+ sampler = anv_device_alloc(device, sizeof(*sampler), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (!sampler)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ struct GEN8_SAMPLER_STATE sampler_state = {
+ .SamplerDisable = 0,
+ .TextureBorderColorMode = 0,
+ .LODPreClampMode = 0,
+ .BaseMipLevel = 0,
+ .MipModeFilter = 0,
+ .MagModeFilter = 0,
+ .MinModeFilter = 0,
+ .TextureLODBias = 0,
+ .AnisotropicAlgorithm = 0,
+ .MinLOD = 0,
+ .MaxLOD = 0,
+ .ChromaKeyEnable = 0,
+ .ChromaKeyIndex = 0,
+ .ChromaKeyMode = 0,
+ .ShadowFunction = 0,
+ .CubeSurfaceControlMode = 0,
+ .IndirectStatePointer = 0,
+ .LODClampMagnificationMode = 0,
+ .MaximumAnisotropy = 0,
+ .RAddressMinFilterRoundingEnable = 0,
+ .RAddressMagFilterRoundingEnable = 0,
+ .VAddressMinFilterRoundingEnable = 0,
+ .VAddressMagFilterRoundingEnable = 0,
+ .UAddressMinFilterRoundingEnable = 0,
+ .UAddressMagFilterRoundingEnable = 0,
+ .TrilinearFilterQuality = 0,
+ .NonnormalizedCoordinateEnable = 0,
+ .TCXAddressControlMode = 0,
+ .TCYAddressControlMode = 0,
+ .TCZAddressControlMode = 0,
+ };
+
+ GEN8_SAMPLER_STATE_pack(NULL, sampler->state, &sampler_state);
+
+ *pSampler = (VkSampler) sampler;
+
+ return VK_SUCCESS;
+}
+
+// Descriptor set functions
+
+VkResult VKAPI vkCreateDescriptorSetLayout(
+ VkDevice _device,
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayout* pSetLayout)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_descriptor_set_layout *set_layout;
+ uint32_t count, k;
+ size_t size, total;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
+
+ count = 0;
+ for (uint32_t i = 0; i < pCreateInfo->count; i++)
+ count += pCreateInfo->pBinding[i].count;
+
+ size = sizeof(*set_layout) +
+ count * sizeof(set_layout->bindings[0]);
+ set_layout = anv_device_alloc(device, size, 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (!set_layout)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ k = 0;
+ total = 0;
+ for (uint32_t i = 0; i < pCreateInfo->count; i++) {
+ for (uint32_t j = 0; j < pCreateInfo->pBinding[i].count; j++) {
+ set_layout->bindings[k].mask = pCreateInfo->pBinding[i].stageFlags;
+ set_layout->bindings[k].type = pCreateInfo->pBinding[i].descriptorType;
+ k++;
+ }
+
+ total += pCreateInfo->pBinding[i].count *
+ __builtin_popcount(pCreateInfo->pBinding[i].stageFlags);
+ }
+
+ set_layout->total = total;
+ set_layout->count = count;
+
+ *pSetLayout = (VkDescriptorSetLayout) set_layout;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkBeginDescriptorPoolUpdate(
+ VkDevice device,
+ VkDescriptorUpdateMode updateMode)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkEndDescriptorPoolUpdate(
+ VkDevice device,
+ VkCmdBuffer cmd)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkCreateDescriptorPool(
+ VkDevice device,
+ VkDescriptorPoolUsage poolUsage,
+ uint32_t maxSets,
+ const VkDescriptorPoolCreateInfo* pCreateInfo,
+ VkDescriptorPool* pDescriptorPool)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkResetDescriptorPool(
+ VkDevice device,
+ VkDescriptorPool descriptorPool)
+{
+ return VK_UNSUPPORTED;
+}
+
+VkResult VKAPI vkAllocDescriptorSets(
+ VkDevice _device,
+ VkDescriptorPool descriptorPool,
+ VkDescriptorSetUsage setUsage,
+ uint32_t count,
+ const VkDescriptorSetLayout* pSetLayouts,
+ VkDescriptorSet* pDescriptorSets,
+ uint32_t* pCount)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ const struct anv_descriptor_set_layout *layout;
+ struct anv_descriptor_set *set;
+ size_t size;
+
+ for (uint32_t i = 0; i < count; i++) {
+ layout = (struct anv_descriptor_set_layout *) pSetLayouts[i];
+ size = sizeof(*set) + layout->total * sizeof(set->descriptors[0]);
+ set = anv_device_alloc(device, size, 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (!set) {
+ *pCount = i;
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+ pDescriptorSets[i] = (VkDescriptorSet) set;
+ }
+
+ *pCount = count;
+
+ return VK_UNSUPPORTED;
+}
+
+void VKAPI vkClearDescriptorSets(
+ VkDevice device,
+ VkDescriptorPool descriptorPool,
+ uint32_t count,
+ const VkDescriptorSet* pDescriptorSets)
+{
+}
+
+void VKAPI vkUpdateDescriptors(
+ VkDevice _device,
+ VkDescriptorSet descriptorSet,
+ uint32_t updateCount,
+ const void** ppUpdateArray)
+{
+ struct anv_descriptor_set *set = (struct anv_descriptor_set *) descriptorSet;
+ VkUpdateSamplers *update_samplers;
+ VkUpdateSamplerTextures *update_sampler_textures;
+ VkUpdateImages *update_images;
+ VkUpdateBuffers *update_buffers;
+ VkUpdateAsCopy *update_as_copy;
+
+ for (uint32_t i = 0; i < updateCount; i++) {
+ const struct anv_common *common = ppUpdateArray[i];
+
+ switch (common->sType) {
+ case VK_STRUCTURE_TYPE_UPDATE_SAMPLERS:
+ update_samplers = (VkUpdateSamplers *) common;
+
+ for (uint32_t j = 0; j < update_samplers->count; j++) {
+ set->descriptors[update_samplers->binding + j] =
+ (void *) update_samplers->pSamplers[j];
+ }
+ break;
+
+ case VK_STRUCTURE_TYPE_UPDATE_SAMPLER_TEXTURES:
+ /* FIXME: Shouldn't this be *_UPDATE_SAMPLER_IMAGES? */
+ update_sampler_textures = (VkUpdateSamplerTextures *) common;
+
+ for (uint32_t j = 0; j < update_sampler_textures->count; j++) {
+ set->descriptors[update_sampler_textures->binding + j] =
+ (void *) update_sampler_textures->pSamplerImageViews[j].pImageView->view;
+ }
+ break;
+
+ case VK_STRUCTURE_TYPE_UPDATE_IMAGES:
+ update_images = (VkUpdateImages *) common;
+
+ for (uint32_t j = 0; j < update_images->count; j++) {
+ set->descriptors[update_images->binding + j] =
+ (void *) update_images->pImageViews[j].view;
+ }
+ break;
+
+ case VK_STRUCTURE_TYPE_UPDATE_BUFFERS:
+ update_buffers = (VkUpdateBuffers *) common;
+
+ for (uint32_t j = 0; j < update_buffers->count; j++) {
+ set->descriptors[update_buffers->binding + j] =
+ (void *) update_buffers->pBufferViews[j].view;
+ }
+ /* FIXME: descriptor arrays? */
+ break;
+
+ case VK_STRUCTURE_TYPE_UPDATE_AS_COPY:
+ update_as_copy = (VkUpdateAsCopy *) common;
+ (void) update_as_copy;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+// State object functions
+
+static inline int64_t
+clamp_int64(int64_t x, int64_t min, int64_t max)
+{
+ if (x < min)
+ return min;
+ else if (x < max)
+ return x;
+ else
+ return max;
+}
+
+VkResult VKAPI vkCreateDynamicViewportState(
+ VkDevice _device,
+ const VkDynamicVpStateCreateInfo* pCreateInfo,
+ VkDynamicVpState* pState)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_dynamic_vp_state *state;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO);
+
+ state = anv_device_alloc(device, sizeof(*state), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (state == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ unsigned count = pCreateInfo->viewportAndScissorCount;
+ state->sf_clip_vp = anv_state_pool_alloc(&device->dyn_state_pool,
+ count * 64, 64);
+ state->cc_vp = anv_state_pool_alloc(&device->dyn_state_pool,
+ count * 8, 32);
+ state->scissor = anv_state_pool_alloc(&device->dyn_state_pool,
+ count * 32, 32);
+
+ for (uint32_t i = 0; i < pCreateInfo->viewportAndScissorCount; i++) {
+ const VkViewport *vp = &pCreateInfo->pViewports[i];
+ const VkRect *s = &pCreateInfo->pScissors[i];
+
+ struct GEN8_SF_CLIP_VIEWPORT sf_clip_viewport = {
+ .ViewportMatrixElementm00 = vp->width / 2,
+ .ViewportMatrixElementm11 = vp->height / 2,
+ .ViewportMatrixElementm22 = (vp->maxDepth - vp->minDepth) / 2,
+ .ViewportMatrixElementm30 = vp->originX + vp->width / 2,
+ .ViewportMatrixElementm31 = vp->originY + vp->height / 2,
+ .ViewportMatrixElementm32 = (vp->maxDepth + vp->minDepth) / 2,
+ .XMinClipGuardband = -1.0f,
+ .XMaxClipGuardband = 1.0f,
+ .YMinClipGuardband = -1.0f,
+ .YMaxClipGuardband = 1.0f,
+ .XMinViewPort = vp->originX,
+ .XMaxViewPort = vp->originX + vp->width - 1,
+ .YMinViewPort = vp->originY,
+ .YMaxViewPort = vp->originY + vp->height - 1,
+ };
+
+ struct GEN8_CC_VIEWPORT cc_viewport = {
+ .MinimumDepth = vp->minDepth,
+ .MaximumDepth = vp->maxDepth
+ };
+
+ /* Since xmax and ymax are inclusive, we have to have xmax < xmin or
+ * ymax < ymin for empty clips. In case clip x, y, width height are all
+ * 0, the clamps below produce 0 for xmin, ymin, xmax, ymax, which isn't
+ * what we want. Just special case empty clips and produce a canonical
+ * empty clip. */
+ static const struct GEN8_SCISSOR_RECT empty_scissor = {
+ .ScissorRectangleYMin = 1,
+ .ScissorRectangleXMin = 1,
+ .ScissorRectangleYMax = 0,
+ .ScissorRectangleXMax = 0
+ };
+
+ const int max = 0xffff;
+ struct GEN8_SCISSOR_RECT scissor = {
+ /* Do this math using int64_t so overflow gets clamped correctly. */
+ .ScissorRectangleYMin = clamp_int64(s->offset.y, 0, max),
+ .ScissorRectangleXMin = clamp_int64(s->offset.x, 0, max),
+ .ScissorRectangleYMax = clamp_int64((uint64_t) s->offset.y + s->extent.height - 1, 0, max),
+ .ScissorRectangleXMax = clamp_int64((uint64_t) s->offset.x + s->extent.width - 1, 0, max)
+ };
+
+ GEN8_SF_CLIP_VIEWPORT_pack(NULL, state->sf_clip_vp.map + i * 64, &sf_clip_viewport);
+ GEN8_CC_VIEWPORT_pack(NULL, state->cc_vp.map + i * 32, &cc_viewport);
+
+ if (s->extent.width <= 0 || s->extent.height <= 0) {
+ GEN8_SCISSOR_RECT_pack(NULL, state->scissor.map + i * 32, &empty_scissor);
+ } else {
+ GEN8_SCISSOR_RECT_pack(NULL, state->scissor.map + i * 32, &scissor);
+ }
+ }
+
+ *pState = (VkDynamicVpState) state;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkCreateDynamicRasterState(
+ VkDevice _device,
+ const VkDynamicRsStateCreateInfo* pCreateInfo,
+ VkDynamicRsState* pState)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_dynamic_rs_state *state;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO);
+
+ state = anv_device_alloc(device, sizeof(*state), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (state == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ /* Missing these:
+ * float depthBias;
+ * float depthBiasClamp;
+ * float slopeScaledDepthBias;
+ * float pointFadeThreshold;
+ * // optional (GL45) - Size of point fade threshold
+ */
+
+ struct GEN8_3DSTATE_SF sf = {
+ GEN8_3DSTATE_SF_header,
+ .LineWidth = pCreateInfo->lineWidth,
+ .PointWidth = pCreateInfo->pointSize,
+ };
+
+ GEN8_3DSTATE_SF_pack(NULL, state->state_sf, &sf);
+
+ *pState = (VkDynamicRsState) state;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkCreateDynamicColorBlendState(
+ VkDevice _device,
+ const VkDynamicCbStateCreateInfo* pCreateInfo,
+ VkDynamicCbState* pState)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_dynamic_cb_state *state;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO);
+
+ state = anv_device_alloc(device, sizeof(*state), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (state == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ *pState = (VkDynamicCbState) state;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkCreateDynamicDepthStencilState(
+ VkDevice device,
+ const VkDynamicDsStateCreateInfo* pCreateInfo,
+ VkDynamicDsState* pState)
+{
+ return VK_UNSUPPORTED;
+}
+
+// Command buffer functions
+
+VkResult VKAPI vkCreateCommandBuffer(
+ VkDevice _device,
+ const VkCmdBufferCreateInfo* pCreateInfo,
+ VkCmdBuffer* pCmdBuffer)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_cmd_buffer *cmd_buffer;
+ VkResult result;
+
+ cmd_buffer = anv_device_alloc(device, sizeof(*cmd_buffer), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (cmd_buffer == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ cmd_buffer->device = device;
+
+ result = anv_batch_init(&cmd_buffer->batch, device);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ cmd_buffer->exec2_objects =
+ anv_device_alloc(device, 8192 * sizeof(cmd_buffer->exec2_objects[0]), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (cmd_buffer->exec2_objects == NULL) {
+ result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ goto fail_batch;
+ }
+
+ cmd_buffer->exec2_bos =
+ anv_device_alloc(device, 8192 * sizeof(cmd_buffer->exec2_bos[0]), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (cmd_buffer->exec2_bos == NULL) {
+ result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ goto fail_exec2_objects;
+ }
+
+ anv_state_stream_init(&cmd_buffer->surface_state_stream,
+ &device->surface_state_block_pool);
+
+ cmd_buffer->dirty = 0;
+ cmd_buffer->vb_dirty = 0;
+
+ *pCmdBuffer = (VkCmdBuffer) cmd_buffer;
+
+ return VK_SUCCESS;
+
+ fail_exec2_objects:
+ anv_device_free(device, cmd_buffer->exec2_objects);
+ fail_batch:
+ anv_batch_finish(&cmd_buffer->batch, device);
+ fail:
+ anv_device_free(device, cmd_buffer);
+
+ return result;
+}
+
+VkResult VKAPI vkBeginCommandBuffer(
+ VkCmdBuffer cmdBuffer,
+ const VkCmdBufferBeginInfo* pBeginInfo)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_device *device = cmd_buffer->device;
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_PIPELINE_SELECT,
+ .PipelineSelection = _3D);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_STATE_SIP);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_STATE_BASE_ADDRESS,
+ .GeneralStateBaseAddress = { NULL, 0 },
+ .GeneralStateBaseAddressModifyEnable = true,
+ .GeneralStateBufferSize = 0xfffff,
+ .GeneralStateBufferSizeModifyEnable = true,
+
+ .SurfaceStateBaseAddress = { &device->surface_state_block_pool.bo, 0 },
+ .SurfaceStateMemoryObjectControlState = 0, /* FIXME: MOCS */
+ .SurfaceStateBaseAddressModifyEnable = true,
+
+ .DynamicStateBaseAddress = { &device->dyn_state_block_pool.bo, 0 },
+ .DynamicStateBaseAddressModifyEnable = true,
+ .DynamicStateBufferSize = 0xfffff,
+ .DynamicStateBufferSizeModifyEnable = true,
+
+ .IndirectObjectBaseAddress = { NULL, 0 },
+ .IndirectObjectBaseAddressModifyEnable = true,
+ .IndirectObjectBufferSize = 0xfffff,
+ .IndirectObjectBufferSizeModifyEnable = true,
+
+ .InstructionBaseAddress = { &device->instruction_block_pool.bo, 0 },
+ .InstructionBaseAddressModifyEnable = true,
+ .InstructionBufferSize = 0xfffff,
+ .InstructionBuffersizeModifyEnable = true);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_VF_STATISTICS,
+ .StatisticsEnable = true);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_HS, .Enable = false);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_TE, .TEEnable = false);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_DS, .FunctionEnable = false);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_STREAMOUT, .SOFunctionEnable = false);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_VS,
+ .ConstantBufferOffset = 0,
+ .ConstantBufferSize = 4);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_GS,
+ .ConstantBufferOffset = 4,
+ .ConstantBufferSize = 4);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_PS,
+ .ConstantBufferOffset = 8,
+ .ConstantBufferSize = 4);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_CLIP,
+ .ClipEnable = true,
+ .ViewportXYClipTestEnable = true);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_WM_CHROMAKEY,
+ .ChromaKeyKillEnable = false);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_SBE_SWIZ);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_AA_LINE_PARAMETERS);
+
+ /* Hardcoded state: */
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_DEPTH_BUFFER,
+ .SurfaceType = SURFTYPE_2D,
+ .Width = 1,
+ .Height = 1,
+ .SurfaceFormat = D16_UNORM,
+ .SurfaceBaseAddress = { NULL, 0 },
+ .HierarchicalDepthBufferEnable = 0);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_WM_DEPTH_STENCIL,
+ .DepthTestEnable = false,
+ .DepthBufferWriteEnable = false);
+
+ return VK_SUCCESS;
+}
+
+static void
+anv_cmd_buffer_add_bo(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_bo *bo, struct anv_reloc_list *list)
+{
+ struct drm_i915_gem_exec_object2 *obj;
+
+ bo->index = cmd_buffer->bo_count;
+ obj = &cmd_buffer->exec2_objects[bo->index];
+ cmd_buffer->exec2_bos[bo->index] = bo;
+ cmd_buffer->bo_count++;
+
+ obj->handle = bo->gem_handle;
+ obj->relocation_count = 0;
+ obj->relocs_ptr = 0;
+ obj->alignment = 0;
+ obj->offset = bo->offset;
+ obj->flags = 0;
+ obj->rsvd1 = 0;
+ obj->rsvd2 = 0;
+
+ if (list) {
+ obj->relocation_count = list->num_relocs;
+ obj->relocs_ptr = (uintptr_t) list->relocs;
+ }
+}
+
+static void
+anv_cmd_buffer_add_validate_bos(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_reloc_list *list)
+{
+ struct anv_bo *bo, *batch_bo;
+
+ batch_bo = &cmd_buffer->batch.bo;
+ for (size_t i = 0; i < list->num_relocs; i++) {
+ bo = list->reloc_bos[i];
+ /* Skip any relocations targeting the batch bo. We need to make sure
+ * it's the last in the list so we'll add it manually later.
+ */
+ if (bo == batch_bo)
+ continue;
+ if (bo->index < cmd_buffer->bo_count && cmd_buffer->exec2_bos[bo->index] == bo)
+ continue;
+
+ anv_cmd_buffer_add_bo(cmd_buffer, bo, NULL);
+ }
+}
+
+static void
+anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_reloc_list *list)
+{
+ struct anv_bo *bo;
+
+ /* If the kernel supports I915_EXEC_NO_RELOC, it will compare offset in
+ * struct drm_i915_gem_exec_object2 against the bos current offset and if
+ * all bos haven't moved it will skip relocation processing alltogether.
+ * If I915_EXEC_NO_RELOC is not supported, the kernel ignores the incoming
+ * value of offset so we can set it either way. For that to work we need
+ * to make sure all relocs use the same presumed offset.
+ */
+
+ for (size_t i = 0; i < list->num_relocs; i++) {
+ bo = list->reloc_bos[i];
+ if (bo->offset != list->relocs[i].presumed_offset)
+ cmd_buffer->need_reloc = true;
+
+ list->relocs[i].target_handle = bo->index;
+ }
+}
+
+VkResult VKAPI vkEndCommandBuffer(
+ VkCmdBuffer cmdBuffer)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_device *device = cmd_buffer->device;
+ struct anv_batch *batch = &cmd_buffer->batch;
+
+ anv_batch_emit(batch, GEN8_MI_BATCH_BUFFER_END);
+
+ /* Round batch up to an even number of dwords. */
+ if ((batch->next - batch->bo.map) & 4)
+ anv_batch_emit(batch, GEN8_MI_NOOP);
+
+ cmd_buffer->bo_count = 0;
+ cmd_buffer->need_reloc = false;
+
+ /* Lock for access to bo->index. */
+ pthread_mutex_lock(&device->mutex);
+
+ /* Add block pool bos first so we can add them with their relocs. */
+ anv_cmd_buffer_add_bo(cmd_buffer, &device->surface_state_block_pool.bo,
+ &batch->surf_relocs);
+
+ anv_cmd_buffer_add_validate_bos(cmd_buffer, &batch->surf_relocs);
+ anv_cmd_buffer_add_validate_bos(cmd_buffer, &batch->cmd_relocs);
+ anv_cmd_buffer_add_bo(cmd_buffer, &batch->bo, &batch->cmd_relocs);
+ anv_cmd_buffer_process_relocs(cmd_buffer, &batch->surf_relocs);
+ anv_cmd_buffer_process_relocs(cmd_buffer, &batch->cmd_relocs);
+
+ cmd_buffer->execbuf.buffers_ptr = (uintptr_t) cmd_buffer->exec2_objects;
+ cmd_buffer->execbuf.buffer_count = cmd_buffer->bo_count;
+ cmd_buffer->execbuf.batch_start_offset = 0;
+ cmd_buffer->execbuf.batch_len = batch->next - batch->bo.map;
+ cmd_buffer->execbuf.cliprects_ptr = 0;
+ cmd_buffer->execbuf.num_cliprects = 0;
+ cmd_buffer->execbuf.DR1 = 0;
+ cmd_buffer->execbuf.DR4 = 0;
+
+ cmd_buffer->execbuf.flags = I915_EXEC_HANDLE_LUT;
+ if (!cmd_buffer->need_reloc)
+ cmd_buffer->execbuf.flags |= I915_EXEC_NO_RELOC;
+ cmd_buffer->execbuf.flags |= I915_EXEC_RENDER;
+ cmd_buffer->execbuf.rsvd1 = device->context_id;
+ cmd_buffer->execbuf.rsvd2 = 0;
+
+ pthread_mutex_unlock(&device->mutex);
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkResetCommandBuffer(
+ VkCmdBuffer cmdBuffer)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ anv_batch_reset(&cmd_buffer->batch);
+
+ return VK_SUCCESS;
+}
+
+// Command buffer building functions
+
+void VKAPI vkCmdBindPipeline(
+ VkCmdBuffer cmdBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ VkPipeline _pipeline)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ cmd_buffer->pipeline = (struct anv_pipeline *) _pipeline;
+ cmd_buffer->dirty |= ANV_CMD_BUFFER_PIPELINE_DIRTY;
+}
+
+void VKAPI vkCmdBindDynamicStateObject(
+ VkCmdBuffer cmdBuffer,
+ VkStateBindPoint stateBindPoint,
+ VkDynamicStateObject dynamicState)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_dynamic_vp_state *vp_state;
+
+ switch (stateBindPoint) {
+ case VK_STATE_BIND_POINT_VIEWPORT:
+ vp_state = (struct anv_dynamic_vp_state *) dynamicState;
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_SCISSOR_STATE_POINTERS,
+ .ScissorRectPointer = vp_state->scissor.offset);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_VIEWPORT_STATE_POINTERS_CC,
+ .CCViewportPointer = vp_state->cc_vp.offset);
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP,
+ .SFClipViewportPointer = vp_state->sf_clip_vp.offset);
+ break;
+ case VK_STATE_BIND_POINT_RASTER:
+ cmd_buffer->rs_state = (struct anv_dynamic_rs_state *) dynamicState;
+ cmd_buffer->dirty |= ANV_CMD_BUFFER_RS_DIRTY;
+ break;
+ case VK_STATE_BIND_POINT_COLOR_BLEND:
+ case VK_STATE_BIND_POINT_DEPTH_STENCIL:
+ break;
+ default:
+ break;
+ };
+}
+
+void VKAPI vkCmdBindDescriptorSets(
+ VkCmdBuffer cmdBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ uint32_t firstSet,
+ uint32_t setCount,
+ const VkDescriptorSet* pDescriptorSets,
+ uint32_t dynamicOffsetCount,
+ const uint32_t* pDynamicOffsets)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ /* What are the semantics for setting descriptor sets? Assuming that
+ * setting preserves lower sets and invalidate higher sets. This means that
+ * we can set the number of active sets to firstSet + setCount.
+ */
+
+ for (uint32_t i = 0; i < setCount; i++)
+ cmd_buffer->descriptor_sets[firstSet + i] =
+ (struct anv_descriptor_set *) pDescriptorSets[i];
+
+ cmd_buffer->num_descriptor_sets = firstSet + setCount;
+ cmd_buffer->dirty |= ANV_CMD_BUFFER_DESCRIPTOR_SET_DIRTY;
+}
+
+void VKAPI vkCmdBindIndexBuffer(
+ VkCmdBuffer cmdBuffer,
+ VkBuffer _buffer,
+ VkDeviceSize offset,
+ VkIndexType indexType)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_buffer *buffer = (struct anv_buffer *) _buffer;
+
+ static const uint32_t vk_to_gen_index_type[] = {
+ [VK_INDEX_TYPE_UINT8] = INDEX_BYTE,
+ [VK_INDEX_TYPE_UINT16] = INDEX_WORD,
+ [VK_INDEX_TYPE_UINT32] = INDEX_DWORD,
+ };
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_INDEX_BUFFER,
+ .IndexFormat = vk_to_gen_index_type[indexType],
+ .MemoryObjectControlState = 0,
+ .BufferStartingAddress = { &buffer->mem->bo, buffer->offset + offset },
+ .BufferSize = buffer->size - offset);
+}
+
+void VKAPI vkCmdBindVertexBuffers(
+ VkCmdBuffer cmdBuffer,
+ uint32_t startBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ /* We have to defer setting up vertex buffer since we need the buffer
+ * stride from the pipeline. */
+
+ for (uint32_t i = 0; i < bindingCount; i++) {
+ cmd_buffer->vb[startBinding + i].buffer = (struct anv_buffer *) pBuffers[i];
+ cmd_buffer->vb[startBinding + i].offset = pOffsets[i];
+ cmd_buffer->vb_dirty |= 1 << (startBinding + i);
+ }
+}
+
+static void
+flush_descriptor_sets(struct anv_cmd_buffer *cmd_buffer)
+{
+ static const uint32_t opcodes[] = {
+ [VK_SHADER_STAGE_VERTEX] = 38,
+ [VK_SHADER_STAGE_TESS_CONTROL] = 39,
+ [VK_SHADER_STAGE_TESS_EVALUATION] = 40,
+ [VK_SHADER_STAGE_GEOMETRY] = 41,
+ [VK_SHADER_STAGE_FRAGMENT] = 42,
+ [VK_SHADER_STAGE_COMPUTE] = 0,
+ };
+
+ struct anv_pipeline_layout *layout = cmd_buffer->pipeline->layout;
+ struct anv_framebuffer *framebuffer = cmd_buffer->framebuffer;
+
+ for (uint32_t s = 0; s < VK_NUM_SHADER_STAGE; s++) {
+
+ uint32_t bias = s == VK_SHADER_STAGE_FRAGMENT ? MAX_RTS : 0;
+ uint32_t count, *table;
+ struct anv_state table_state;
+
+ if (layout)
+ count = layout->stage[s].count + bias;
+ else if (s == VK_SHADER_STAGE_FRAGMENT)
+ count = framebuffer->color_attachment_count;
+ else
+ count = 0;
+
+ if (count == 0)
+ continue;
+
+ table_state = anv_state_stream_alloc(&cmd_buffer->surface_state_stream,
+ count * 4, 32);
+ table = table_state.map;
+
+ if (s == VK_SHADER_STAGE_FRAGMENT) {
+ for (uint32_t i = 0; i < framebuffer->color_attachment_count; i++) {
+ struct anv_color_attachment_view *view = framebuffer->color_attachments[i];
+ table[i] = view->surface_state.offset;
+
+ /* Don't write the reloc back to the surface state. We do that at
+ * submit time. Surface address is dwords 8-9. */
+ anv_reloc_list_add(&cmd_buffer->batch.surf_relocs,
+ view->surface_state.offset + 8 * sizeof(int32_t),
+ &view->image->mem->bo, view->image->offset);
+ }
+ }
+
+ if (layout) {
+ for (uint32_t i = 0; i < layout->stage[s].count; i++) {
+ struct anv_pipeline_layout_entry *e = &layout->stage[s].entries[i];
+ struct anv_image_view *image_view;
+ struct anv_buffer_view *buffer_view;
+ void *d = cmd_buffer->descriptor_sets[e->set]->descriptors[e->index];
+
+ switch (e->type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ image_view = d;
+ table[bias + i] = image_view->surface_state.offset;
+ anv_reloc_list_add(&cmd_buffer->batch.surf_relocs,
+ image_view->surface_state.offset + 8 * sizeof(int32_t),
+ &image_view->image->mem->bo,
+ image_view->image->offset);
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ /* FIXME: What are these? TBOs? */
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ buffer_view = d;
+ table[bias + i] = buffer_view->surface_state.offset;
+ anv_reloc_list_add(&cmd_buffer->batch.surf_relocs,
+ buffer_view->surface_state.offset + 8 * sizeof(int32_t),
+ &buffer_view->buffer->mem->bo,
+ buffer_view->buffer->offset + buffer_view->offset);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /* FIXME: Samplers */
+
+ /* The binding table pointer commands all have the same structure, only
+ * the opcode differs.
+ */
+ anv_batch_emit(&cmd_buffer->batch,
+ GEN8_3DSTATE_BINDING_TABLE_POINTERS_VS,
+ ._3DCommandSubOpcode = opcodes[s],
+ .PointertoVSBindingTable = table_state.offset);
+ }
+}
+
+static void
+anv_cmd_buffer_flush_state(struct anv_cmd_buffer *cmd_buffer)
+{
+ struct anv_pipeline *pipeline = cmd_buffer->pipeline;
+ const uint32_t num_buffers = __builtin_popcount(cmd_buffer->vb_dirty);
+ const uint32_t num_dwords = 1 + num_buffers * 4;
+ uint32_t *p;
+
+ if (cmd_buffer->vb_dirty) {
+ p = anv_batch_emitn(&cmd_buffer->batch, num_dwords,
+ GEN8_3DSTATE_VERTEX_BUFFERS);
+ uint32_t vb, i = 0;
+ for_each_bit(vb, cmd_buffer->vb_dirty) {
+ struct anv_buffer *buffer = cmd_buffer->vb[vb].buffer;
+ uint32_t offset = cmd_buffer->vb[vb].offset;
+
+ struct GEN8_VERTEX_BUFFER_STATE state = {
+ .VertexBufferIndex = vb,
+ .MemoryObjectControlState = 0,
+ .AddressModifyEnable = true,
+ .BufferPitch = pipeline->binding_stride[vb],
+ .BufferStartingAddress = { &buffer->mem->bo, buffer->offset + offset },
+ .BufferSize = buffer->size - offset
+ };
+
+ GEN8_VERTEX_BUFFER_STATE_pack(&cmd_buffer->batch, &p[1 + i * 4], &state);
+ i++;
+ }
+ }
+
+ if (cmd_buffer->dirty & ANV_CMD_BUFFER_PIPELINE_DIRTY)
+ anv_batch_emit_batch(&cmd_buffer->batch, &pipeline->batch);
+
+ if (cmd_buffer->dirty & ANV_CMD_BUFFER_DESCRIPTOR_SET_DIRTY)
+ flush_descriptor_sets(cmd_buffer);
+
+ if (cmd_buffer->dirty & (ANV_CMD_BUFFER_PIPELINE_DIRTY | ANV_CMD_BUFFER_RS_DIRTY)) {
+ /* maybe: anv_batch_merge(batch, GEN8_3DSTATE_SF, a, b) */
+ uint32_t *dw;
+
+ dw = anv_batch_emit_dwords(&cmd_buffer->batch, GEN8_3DSTATE_SF_length);
+ for (uint32_t i = 0; i < GEN8_3DSTATE_SF_length; i++)
+ dw[i] = cmd_buffer->rs_state->state_sf[i] | pipeline->state_sf[i];
+ }
+
+ cmd_buffer->vb_dirty = 0;
+ cmd_buffer->dirty = 0;
+}
+
+void VKAPI vkCmdDraw(
+ VkCmdBuffer cmdBuffer,
+ uint32_t firstVertex,
+ uint32_t vertexCount,
+ uint32_t firstInstance,
+ uint32_t instanceCount)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ anv_cmd_buffer_flush_state(cmd_buffer);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DPRIMITIVE,
+ .VertexAccessType = SEQUENTIAL,
+ .VertexCountPerInstance = vertexCount,
+ .StartVertexLocation = firstVertex,
+ .InstanceCount = instanceCount,
+ .StartInstanceLocation = firstInstance,
+ .BaseVertexLocation = 0);
+}
+
+void VKAPI vkCmdDrawIndexed(
+ VkCmdBuffer cmdBuffer,
+ uint32_t firstIndex,
+ uint32_t indexCount,
+ int32_t vertexOffset,
+ uint32_t firstInstance,
+ uint32_t instanceCount)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+
+ anv_cmd_buffer_flush_state(cmd_buffer);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DPRIMITIVE,
+ .VertexAccessType = RANDOM,
+ .VertexCountPerInstance = indexCount,
+ .StartVertexLocation = firstIndex,
+ .InstanceCount = instanceCount,
+ .StartInstanceLocation = firstInstance,
+ .BaseVertexLocation = 0);
+}
+
+static void
+anv_batch_lrm(struct anv_batch *batch,
+ uint32_t reg, struct anv_bo *bo, uint32_t offset)
+{
+ anv_batch_emit(batch, GEN8_MI_LOAD_REGISTER_MEM,
+ .RegisterAddress = reg,
+ .MemoryAddress = { bo, offset });
+}
+
+static void
+anv_batch_lri(struct anv_batch *batch, uint32_t reg, uint32_t imm)
+{
+ anv_batch_emit(batch, GEN8_MI_LOAD_REGISTER_IMM,
+ .RegisterOffset = reg,
+ .DataDWord = imm);
+}
+
+/* Auto-Draw / Indirect Registers */
+#define GEN7_3DPRIM_END_OFFSET 0x2420
+#define GEN7_3DPRIM_START_VERTEX 0x2430
+#define GEN7_3DPRIM_VERTEX_COUNT 0x2434
+#define GEN7_3DPRIM_INSTANCE_COUNT 0x2438
+#define GEN7_3DPRIM_START_INSTANCE 0x243C
+#define GEN7_3DPRIM_BASE_VERTEX 0x2440
+
+void VKAPI vkCmdDrawIndirect(
+ VkCmdBuffer cmdBuffer,
+ VkBuffer _buffer,
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_buffer *buffer = (struct anv_buffer *) _buffer;
+ struct anv_bo *bo = &buffer->mem->bo;
+ uint32_t bo_offset = buffer->offset + offset;
+
+ anv_cmd_buffer_flush_state(cmd_buffer);
+
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_VERTEX_COUNT, bo, bo_offset);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_INSTANCE_COUNT, bo, bo_offset + 4);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_START_VERTEX, bo, bo_offset + 8);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_START_INSTANCE, bo, bo_offset + 12);
+ anv_batch_lri(&cmd_buffer->batch, GEN7_3DPRIM_BASE_VERTEX, 0);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DPRIMITIVE,
+ .IndirectParameterEnable = true,
+ .VertexAccessType = SEQUENTIAL);
+}
+
+void VKAPI vkCmdDrawIndexedIndirect(
+ VkCmdBuffer cmdBuffer,
+ VkBuffer _buffer,
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_buffer *buffer = (struct anv_buffer *) _buffer;
+ struct anv_bo *bo = &buffer->mem->bo;
+ uint32_t bo_offset = buffer->offset + offset;
+
+ anv_cmd_buffer_flush_state(cmd_buffer);
+
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_VERTEX_COUNT, bo, bo_offset);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_INSTANCE_COUNT, bo, bo_offset + 4);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_START_VERTEX, bo, bo_offset + 8);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_BASE_VERTEX, bo, bo_offset + 12);
+ anv_batch_lrm(&cmd_buffer->batch, GEN7_3DPRIM_START_INSTANCE, bo, bo_offset + 16);
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DPRIMITIVE,
+ .IndirectParameterEnable = true,
+ .VertexAccessType = RANDOM);
+}
+
+void VKAPI vkCmdDispatch(
+ VkCmdBuffer cmdBuffer,
+ uint32_t x,
+ uint32_t y,
+ uint32_t z)
+{
+}
+
+void VKAPI vkCmdDispatchIndirect(
+ VkCmdBuffer cmdBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset)
+{
+}
+
+void VKAPI vkCmdSetEvent(
+ VkCmdBuffer cmdBuffer,
+ VkEvent event,
+ VkPipeEvent pipeEvent)
+{
+}
+
+void VKAPI vkCmdResetEvent(
+ VkCmdBuffer cmdBuffer,
+ VkEvent event,
+ VkPipeEvent pipeEvent)
+{
+}
+
+void VKAPI vkCmdWaitEvents(
+ VkCmdBuffer cmdBuffer,
+ VkWaitEvent waitEvent,
+ uint32_t eventCount,
+ const VkEvent* pEvents,
+ uint32_t memBarrierCount,
+ const void** ppMemBarriers)
+{
+}
+
+void VKAPI vkCmdPipelineBarrier(
+ VkCmdBuffer cmdBuffer,
+ VkWaitEvent waitEvent,
+ uint32_t pipeEventCount,
+ const VkPipeEvent* pPipeEvents,
+ uint32_t memBarrierCount,
+ const void** ppMemBarriers)
+{
+}
+
+static void
+anv_batch_emit_ps_depth_count(struct anv_batch *batch,
+ struct anv_bo *bo, uint32_t offset)
+{
+ anv_batch_emit(batch, GEN8_PIPE_CONTROL,
+ .DestinationAddressType = DAT_PPGTT,
+ .PostSyncOperation = WritePSDepthCount,
+ .Address = { bo, offset }); /* FIXME: This is only lower 32 bits */
+}
+
+void VKAPI vkCmdBeginQuery(
+ VkCmdBuffer cmdBuffer,
+ VkQueryPool queryPool,
+ uint32_t slot,
+ VkQueryControlFlags flags)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_query_pool *pool = (struct anv_query_pool *) queryPool;
+
+ switch (pool->type) {
+ case VK_QUERY_TYPE_OCCLUSION:
+ anv_batch_emit_ps_depth_count(&cmd_buffer->batch, &pool->bo, slot * 16);
+ break;
+
+ case VK_QUERY_TYPE_PIPELINE_STATISTICS:
+ break;
+
+ default:
+ break;
+ }
+}
+
+void VKAPI vkCmdEndQuery(
+ VkCmdBuffer cmdBuffer,
+ VkQueryPool queryPool,
+ uint32_t slot)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_query_pool *pool = (struct anv_query_pool *) queryPool;
+
+ switch (pool->type) {
+ case VK_QUERY_TYPE_OCCLUSION:
+ anv_batch_emit_ps_depth_count(&cmd_buffer->batch, &pool->bo, slot * 16 + 8);
+ break;
+
+ case VK_QUERY_TYPE_PIPELINE_STATISTICS:
+ break;
+
+ default:
+ break;
+ }
+}
+
+void VKAPI vkCmdResetQueryPool(
+ VkCmdBuffer cmdBuffer,
+ VkQueryPool queryPool,
+ uint32_t startQuery,
+ uint32_t queryCount)
+{
+}
+
+#define TIMESTAMP 0x44070
+
+void VKAPI vkCmdWriteTimestamp(
+ VkCmdBuffer cmdBuffer,
+ VkTimestampType timestampType,
+ VkBuffer destBuffer,
+ VkDeviceSize destOffset)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_buffer *buffer = (struct anv_buffer *) destBuffer;
+ struct anv_bo *bo = &buffer->mem->bo;
+
+ switch (timestampType) {
+ case VK_TIMESTAMP_TYPE_TOP:
+ anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM,
+ .RegisterAddress = TIMESTAMP,
+ .MemoryAddress = { bo, buffer->offset + destOffset });
+ break;
+
+ case VK_TIMESTAMP_TYPE_BOTTOM:
+ anv_batch_emit(&cmd_buffer->batch, GEN8_PIPE_CONTROL,
+ .DestinationAddressType = DAT_PPGTT,
+ .PostSyncOperation = WriteTimestamp,
+ .Address = /* FIXME: This is only lower 32 bits */
+ { bo, buffer->offset + destOffset });
+ break;
+
+ default:
+ break;
+ }
+}
+
+void VKAPI vkCmdCopyQueryPoolResults(
+ VkCmdBuffer cmdBuffer,
+ VkQueryPool queryPool,
+ uint32_t startQuery,
+ uint32_t queryCount,
+ VkBuffer destBuffer,
+ VkDeviceSize destOffset,
+ VkDeviceSize destStride,
+ VkQueryResultFlags flags)
+{
+}
+
+void VKAPI vkCmdInitAtomicCounters(
+ VkCmdBuffer cmdBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ uint32_t startCounter,
+ uint32_t counterCount,
+ const uint32_t* pData)
+{
+}
+
+void VKAPI vkCmdLoadAtomicCounters(
+ VkCmdBuffer cmdBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ uint32_t startCounter,
+ uint32_t counterCount,
+ VkBuffer srcBuffer,
+ VkDeviceSize srcOffset)
+{
+}
+
+void VKAPI vkCmdSaveAtomicCounters(
+ VkCmdBuffer cmdBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ uint32_t startCounter,
+ uint32_t counterCount,
+ VkBuffer destBuffer,
+ VkDeviceSize destOffset)
+{
+}
+
+VkResult VKAPI vkCreateFramebuffer(
+ VkDevice _device,
+ const VkFramebufferCreateInfo* pCreateInfo,
+ VkFramebuffer* pFramebuffer)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_framebuffer *framebuffer;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
+
+ framebuffer = anv_device_alloc(device, sizeof(*framebuffer), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (framebuffer == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ framebuffer->color_attachment_count = pCreateInfo->colorAttachmentCount;
+ for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
+ framebuffer->color_attachments[i] =
+ (struct anv_color_attachment_view *) pCreateInfo->pColorAttachments[i].view;
+ }
+
+ if (pCreateInfo->pDepthStencilAttachment) {
+ framebuffer->depth_stencil =
+ (struct anv_depth_stencil_view *) pCreateInfo->pDepthStencilAttachment->view;
+ }
+
+ framebuffer->sample_count = pCreateInfo->sampleCount;
+ framebuffer->width = pCreateInfo->width;
+ framebuffer->height = pCreateInfo->height;
+ framebuffer->layers = pCreateInfo->layers;
+
+ *pFramebuffer = (VkFramebuffer) framebuffer;
+
+ return VK_SUCCESS;
+}
+
+VkResult VKAPI vkCreateRenderPass(
+ VkDevice _device,
+ const VkRenderPassCreateInfo* pCreateInfo,
+ VkRenderPass* pRenderPass)
+{
+ struct anv_device *device = (struct anv_device *) _device;
+ struct anv_render_pass *pass;
+
+ assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO);
+
+ pass = anv_device_alloc(device, sizeof(*pass), 8,
+ VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
+ if (pass == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ pass->render_area = pCreateInfo->renderArea;
+
+ *pRenderPass = (VkRenderPass) pass;
+
+ return VK_SUCCESS;
+}
+
+void VKAPI vkCmdBeginRenderPass(
+ VkCmdBuffer cmdBuffer,
+ const VkRenderPassBegin* pRenderPassBegin)
+{
+ struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer;
+ struct anv_render_pass *pass = (struct anv_render_pass *) pRenderPassBegin->renderPass;
+
+ cmd_buffer->framebuffer = (struct anv_framebuffer *) pRenderPassBegin->framebuffer;
+ cmd_buffer->dirty |= ANV_CMD_BUFFER_DESCRIPTOR_SET_DIRTY;
+
+ anv_batch_emit(&cmd_buffer->batch, GEN8_3DSTATE_DRAWING_RECTANGLE,
+ .ClippedDrawingRectangleYMin = pass->render_area.offset.y,
+ .ClippedDrawingRectangleXMin = pass->render_area.offset.x,
+ .ClippedDrawingRectangleYMax =
+ pass->render_area.offset.y + pass->render_area.extent.height - 1,
+ .ClippedDrawingRectangleXMax =
+ pass->render_area.offset.x + pass->render_area.extent.width - 1,
+ .DrawingRectangleOriginY = 0,
+ .DrawingRectangleOriginX = 0);
+}
+
+void VKAPI vkCmdEndRenderPass(
+ VkCmdBuffer cmdBuffer,
+ VkRenderPass renderPass)
+{
+}