| /* |
| * 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) |
| return result; |
| |
| 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 = MAX_SETS; |
| properties->maxThreadGroupSize = 512; |
| properties->timestampFrequency = 1000 * 1000 * 1000 / ns_per_tick; |
| properties->multiColorAttachmentClears = true; |
| properties->maxDescriptorSets = 8; |
| 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 = true; |
| queue_properties->maxMemReferences = 256; |
| 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); |
| |
| |
| /* Binding table pointers are only 16 bits so we have to make sure that |
| * they get allocated at the beginning of the surface state BO. To |
| * handle this, we create a separate block pool that works out of the |
| * first 64 KB of the surface state BO. |
| */ |
| anv_block_pool_init_slave(&device->binding_table_block_pool, |
| &device->surface_state_block_pool, 32); |
| |
| 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; |
| struct anv_fence *fence = (struct anv_fence *) _fence; |
| 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); |
| |
| if (fence) { |
| ret = anv_gem_execbuffer(device, &fence->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_state_stream_finish(&cmd_buffer->binding_table_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_fence_destructor(struct anv_device * device, |
| VkObject object) |
| { |
| struct anv_fence *fence = (struct anv_fence *) object; |
| |
| anv_gem_munmap(fence->bo.map, fence->bo.size); |
| anv_gem_close(device, fence->bo.gem_handle); |
| anv_device_free(device, fence); |
| |
| return VK_SUCCESS; |
| } |
| |
| static VkResult |
| anv_query_pool_destructor(struct anv_device * device, |
| VkObject object) |
| { |
| struct anv_query_pool *pool = (struct anv_query_pool *) object; |
| |
| anv_gem_munmap(pool->bo.map, pool->bo.size); |
| anv_gem_close(device, pool->bo.gem_handle); |
| anv_device_free(device, pool); |
| |
| 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, |
| [VK_OBJECT_TYPE_FENCE] = anv_fence_destructor, |
| [VK_OBJECT_TYPE_QUERY_POOL] = anv_query_pool_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; |
| } |
| } |
| |
| static uint32_t |
| get_allocation_count(VkObjectType objType) |
| { |
| switch (objType) { |
| case VK_OBJECT_TYPE_BUFFER: |
| case VK_OBJECT_TYPE_IMAGE: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| VkResult anv_GetObjectInfo( |
| VkDevice _device, |
| VkObjectType objType, |
| VkObject object, |
| VkObjectInfoType infoType, |
| size_t* pDataSize, |
| void* pData) |
| { |
| VkMemoryRequirements memory_requirements; |
| uint32_t *count; |
| |
| switch (infoType) { |
| case VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS: |
| *pDataSize = sizeof(memory_requirements); |
| if (pData == NULL) |
| return VK_SUCCESS; |
| |
| fill_memory_requirements(objType, object, pData); |
| return VK_SUCCESS; |
| |
| case VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT: |
| *pDataSize = sizeof(count); |
| if (pData == NULL) |
| return VK_SUCCESS; |
| |
| count = pData; |
| *count = get_allocation_count(objType); |
| return VK_SUCCESS; |
| |
| default: |
| return VK_UNSUPPORTED; |
| } |
| |
| } |
| |
| VkResult anv_QueueBindObjectMemory( |
| 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->bo = &mem->bo; |
| buffer->offset = memOffset; |
| break; |
| case VK_OBJECT_TYPE_IMAGE: |
| image = (struct anv_image *) object; |
| image->bo = &mem->bo; |
| image->offset = memOffset; |
| break; |
| default: |
| break; |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_QueueBindObjectMemoryRange( |
| VkQueue queue, |
| VkObjectType objType, |
| VkObject object, |
| uint32_t allocationIdx, |
| VkDeviceSize rangeOffset, |
| VkDeviceSize rangeSize, |
| VkDeviceMemory mem, |
| VkDeviceSize memOffset) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_QueueBindImageMemoryRange( |
| VkQueue queue, |
| VkImage image, |
| uint32_t allocationIdx, |
| const VkImageMemoryBindInfo* pBindInfo, |
| VkDeviceMemory mem, |
| VkDeviceSize memOffset) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_CreateFence( |
| VkDevice _device, |
| const VkFenceCreateInfo* pCreateInfo, |
| VkFence* pFence) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_fence *fence; |
| struct anv_batch batch; |
| VkResult result; |
| |
| const uint32_t fence_size = 128; |
| |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); |
| |
| fence = anv_device_alloc(device, sizeof(*fence), 8, |
| VK_SYSTEM_ALLOC_TYPE_API_OBJECT); |
| if (fence == NULL) |
| return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| result = anv_bo_init_new(&fence->bo, device, fence_size); |
| if (result != VK_SUCCESS) |
| goto fail; |
| |
| fence->bo.map = |
| anv_gem_mmap(device, fence->bo.gem_handle, 0, fence->bo.size); |
| batch.next = fence->bo.map; |
| anv_batch_emit(&batch, GEN8_MI_BATCH_BUFFER_END); |
| anv_batch_emit(&batch, GEN8_MI_NOOP); |
| |
| fence->exec2_objects[0].handle = fence->bo.gem_handle; |
| fence->exec2_objects[0].relocation_count = 0; |
| fence->exec2_objects[0].relocs_ptr = 0; |
| fence->exec2_objects[0].alignment = 0; |
| fence->exec2_objects[0].offset = fence->bo.offset; |
| fence->exec2_objects[0].flags = 0; |
| fence->exec2_objects[0].rsvd1 = 0; |
| fence->exec2_objects[0].rsvd2 = 0; |
| |
| fence->execbuf.buffers_ptr = (uintptr_t) fence->exec2_objects; |
| fence->execbuf.buffer_count = 1; |
| fence->execbuf.batch_start_offset = 0; |
| fence->execbuf.batch_len = batch.next - fence->bo.map; |
| fence->execbuf.cliprects_ptr = 0; |
| fence->execbuf.num_cliprects = 0; |
| fence->execbuf.DR1 = 0; |
| fence->execbuf.DR4 = 0; |
| |
| fence->execbuf.flags = |
| I915_EXEC_HANDLE_LUT | I915_EXEC_NO_RELOC | I915_EXEC_RENDER; |
| fence->execbuf.rsvd1 = device->context_id; |
| fence->execbuf.rsvd2 = 0; |
| |
| *pFence = (VkQueryPool) fence; |
| |
| return VK_SUCCESS; |
| |
| fail: |
| anv_device_free(device, fence); |
| |
| return result; |
| } |
| |
| VkResult anv_ResetFences( |
| VkDevice _device, |
| uint32_t fenceCount, |
| VkFence* pFences) |
| { |
| struct anv_fence **fences = (struct anv_fence **) pFences; |
| |
| for (uint32_t i; i < fenceCount; i++) |
| fences[i]->ready = false; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_GetFenceStatus( |
| VkDevice _device, |
| VkFence _fence) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_fence *fence = (struct anv_fence *) _fence; |
| int64_t t = 0; |
| int ret; |
| |
| if (fence->ready) |
| return VK_SUCCESS; |
| |
| ret = anv_gem_wait(device, fence->bo.gem_handle, &t); |
| if (ret == 0) { |
| fence->ready = true; |
| return VK_SUCCESS; |
| } |
| |
| return VK_NOT_READY; |
| } |
| |
| VkResult anv_WaitForFences( |
| VkDevice _device, |
| uint32_t fenceCount, |
| const VkFence* pFences, |
| bool32_t waitAll, |
| uint64_t timeout) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_fence **fences = (struct anv_fence **) pFences; |
| int64_t t = timeout; |
| int ret; |
| |
| /* FIXME: handle !waitAll */ |
| |
| for (uint32_t i = 0; i < fenceCount; i++) { |
| ret = anv_gem_wait(device, fences[i]->bo.gem_handle, &t); |
| if (ret == -1 && errno == ETIME) |
| return VK_TIMEOUT; |
| else if (ret == -1) |
| return vk_error(VK_ERROR_UNKNOWN); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| // Queue semaphore functions |
| |
| VkResult anv_CreateSemaphore( |
| VkDevice device, |
| const VkSemaphoreCreateInfo* pCreateInfo, |
| VkSemaphore* pSemaphore) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_QueueSignalSemaphore( |
| VkQueue queue, |
| VkSemaphore semaphore) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_QueueWaitSemaphore( |
| VkQueue queue, |
| VkSemaphore semaphore) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| // Event functions |
| |
| VkResult anv_CreateEvent( |
| VkDevice device, |
| const VkEventCreateInfo* pCreateInfo, |
| VkEvent* pEvent) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_GetEventStatus( |
| VkDevice device, |
| VkEvent event) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_SetEvent( |
| VkDevice device, |
| VkEvent event) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| VkResult anv_ResetEvent( |
| VkDevice device, |
| VkEvent event) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| // Query functions |
| |
| VkResult anv_CreateQueryPool( |
| VkDevice _device, |
| const VkQueryPoolCreateInfo* pCreateInfo, |
| VkQueryPool* pQueryPool) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_query_pool *pool; |
| VkResult result; |
| size_t size; |
| |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO); |
| |
| switch (pCreateInfo->queryType) { |
| case VK_QUERY_TYPE_OCCLUSION: |
| break; |
| case VK_QUERY_TYPE_PIPELINE_STATISTICS: |
| return VK_UNSUPPORTED; |
| default: |
| unreachable(""); |
| } |
| |
| 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; |
| size = pCreateInfo->slots * sizeof(struct anv_query_pool_slot); |
| result = anv_bo_init_new(&pool->bo, device, size); |
| if (result != VK_SUCCESS) |
| goto fail; |
| |
| pool->bo.map = anv_gem_mmap(device, pool->bo.gem_handle, 0, size); |
| |
| *pQueryPool = (VkQueryPool) pool; |
| |
| return VK_SUCCESS; |
| |
| fail: |
| anv_device_free(device, pool); |
| |
| return result; |
| } |
| |
| VkResult anv_GetQueryPoolResults( |
| VkDevice _device, |
| VkQueryPool queryPool, |
| uint32_t startQuery, |
| uint32_t queryCount, |
| size_t* pDataSize, |
| void* pData, |
| VkQueryResultFlags flags) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_query_pool *pool = (struct anv_query_pool *) queryPool; |
| struct anv_query_pool_slot *slot = pool->bo.map; |
| int64_t timeout = INT64_MAX; |
| uint32_t *dst32 = pData; |
| uint64_t *dst64 = pData; |
| uint64_t result; |
| int ret; |
| |
| if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) { |
| /* Where is the availabilty info supposed to go? */ |
| anv_finishme("VK_QUERY_RESULT_WITH_AVAILABILITY_BIT"); |
| return VK_UNSUPPORTED; |
| } |
| |
| assert(pool->type == VK_QUERY_TYPE_OCCLUSION); |
| |
| if (flags & VK_QUERY_RESULT_64_BIT) |
| *pDataSize = queryCount * sizeof(uint64_t); |
| else |
| *pDataSize = queryCount * sizeof(uint32_t); |
| |
| if (pData == NULL) |
| return VK_SUCCESS; |
| |
| if (flags & VK_QUERY_RESULT_WAIT_BIT) { |
| ret = anv_gem_wait(device, pool->bo.gem_handle, &timeout); |
| if (ret == -1) |
| return vk_error(VK_ERROR_UNKNOWN); |
| } |
| |
| for (uint32_t i = 0; i < queryCount; i++) { |
| result = slot[startQuery + i].end - slot[startQuery + i].begin; |
| if (flags & VK_QUERY_RESULT_64_BIT) { |
| *dst64++ = result; |
| } else { |
| if (result > UINT32_MAX) |
| result = UINT32_MAX; |
| *dst32++ = result; |
| } |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| // Buffer functions |
| |
| VkResult anv_CreateBuffer( |
| 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->bo = NULL; |
| buffer->offset = 0; |
| |
| *pBuffer = (VkBuffer) buffer; |
| |
| return VK_SUCCESS; |
| } |
| |
| // Buffer view functions |
| |
| VkResult anv_CreateBufferView( |
| VkDevice _device, |
| const VkBufferViewCreateInfo* pCreateInfo, |
| VkBufferView* pView) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_buffer *buffer = (struct anv_buffer *) pCreateInfo->buffer; |
| struct anv_surface_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->bo = buffer->bo; |
| view->offset = buffer->offset + pCreateInfo->offset; |
| view->surface_state = |
| anv_state_pool_alloc(&device->surface_state_pool, 64, 64); |
| view->format = pCreateInfo->format; |
| |
| 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->offset }, |
| }; |
| |
| GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state); |
| |
| *pView = (VkImageView) view; |
| |
| return VK_SUCCESS; |
| } |
| |
| // Sampler functions |
| |
| VkResult anv_CreateSampler( |
| 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_SAMPLER_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); |
| |
| static const uint32_t vk_to_gen_tex_filter[] = { |
| [VK_TEX_FILTER_NEAREST] = MAPFILTER_NEAREST, |
| [VK_TEX_FILTER_LINEAR] = MAPFILTER_LINEAR |
| }; |
| |
| static const uint32_t vk_to_gen_mipmap_mode[] = { |
| [VK_TEX_MIPMAP_MODE_BASE] = MIPFILTER_NONE, |
| [VK_TEX_MIPMAP_MODE_NEAREST] = MIPFILTER_NEAREST, |
| [VK_TEX_MIPMAP_MODE_LINEAR] = MIPFILTER_LINEAR |
| }; |
| |
| static const uint32_t vk_to_gen_tex_address[] = { |
| [VK_TEX_ADDRESS_WRAP] = TCM_WRAP, |
| [VK_TEX_ADDRESS_MIRROR] = TCM_MIRROR, |
| [VK_TEX_ADDRESS_CLAMP] = TCM_CLAMP, |
| [VK_TEX_ADDRESS_MIRROR_ONCE] = TCM_MIRROR_ONCE, |
| [VK_TEX_ADDRESS_CLAMP_BORDER] = TCM_CLAMP_BORDER, |
| }; |
| |
| static const uint32_t vk_to_gen_compare_op[] = { |
| [VK_COMPARE_OP_NEVER] = PREFILTEROPNEVER, |
| [VK_COMPARE_OP_LESS] = PREFILTEROPLESS, |
| [VK_COMPARE_OP_EQUAL] = PREFILTEROPEQUAL, |
| [VK_COMPARE_OP_LESS_EQUAL] = PREFILTEROPLEQUAL, |
| [VK_COMPARE_OP_GREATER] = PREFILTEROPGREATER, |
| [VK_COMPARE_OP_NOT_EQUAL] = PREFILTEROPNOTEQUAL, |
| [VK_COMPARE_OP_GREATER_EQUAL] = PREFILTEROPGEQUAL, |
| [VK_COMPARE_OP_ALWAYS] = PREFILTEROPALWAYS, |
| }; |
| |
| if (pCreateInfo->maxAnisotropy > 0) |
| anv_finishme("missing support for anisotropic filtering"); |
| |
| struct GEN8_SAMPLER_STATE sampler_state = { |
| .SamplerDisable = false, |
| .TextureBorderColorMode = DX10OGL, |
| .LODPreClampMode = 0, |
| .BaseMipLevel = 0, |
| .MipModeFilter = vk_to_gen_mipmap_mode[pCreateInfo->mipMode], |
| .MagModeFilter = vk_to_gen_tex_filter[pCreateInfo->magFilter], |
| .MinModeFilter = vk_to_gen_tex_filter[pCreateInfo->minFilter], |
| .TextureLODBias = pCreateInfo->mipLodBias * 256, |
| .AnisotropicAlgorithm = EWAApproximation, |
| .MinLOD = pCreateInfo->minLod * 256, |
| .MaxLOD = pCreateInfo->maxLod * 256, |
| .ChromaKeyEnable = 0, |
| .ChromaKeyIndex = 0, |
| .ChromaKeyMode = 0, |
| .ShadowFunction = vk_to_gen_compare_op[pCreateInfo->compareOp], |
| .CubeSurfaceControlMode = 0, |
| .IndirectStatePointer = 0, |
| .LODClampMagnificationMode = MIPNONE, |
| .MaximumAnisotropy = 0, |
| .RAddressMinFilterRoundingEnable = 0, |
| .RAddressMagFilterRoundingEnable = 0, |
| .VAddressMinFilterRoundingEnable = 0, |
| .VAddressMagFilterRoundingEnable = 0, |
| .UAddressMinFilterRoundingEnable = 0, |
| .UAddressMagFilterRoundingEnable = 0, |
| .TrilinearFilterQuality = 0, |
| .NonnormalizedCoordinateEnable = 0, |
| .TCXAddressControlMode = vk_to_gen_tex_address[pCreateInfo->addressU], |
| .TCYAddressControlMode = vk_to_gen_tex_address[pCreateInfo->addressV], |
| .TCZAddressControlMode = vk_to_gen_tex_address[pCreateInfo->addressW], |
| }; |
| |
| GEN8_SAMPLER_STATE_pack(NULL, sampler->state, &sampler_state); |
| |
| *pSampler = (VkSampler) sampler; |
| |
| return VK_SUCCESS; |
| } |
| |
| // Descriptor set functions |
| |
| VkResult anv_CreateDescriptorSetLayout( |
| VkDevice _device, |
| const VkDescriptorSetLayoutCreateInfo* pCreateInfo, |
| VkDescriptorSetLayout* pSetLayout) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_descriptor_set_layout *set_layout; |
| |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); |
| |
| uint32_t sampler_count[VK_NUM_SHADER_STAGE] = { 0, }; |
| uint32_t surface_count[VK_NUM_SHADER_STAGE] = { 0, }; |
| uint32_t num_dynamic_buffers = 0; |
| uint32_t count = 0; |
| uint32_t s; |
| |
| for (uint32_t i = 0; i < pCreateInfo->count; i++) { |
| switch (pCreateInfo->pBinding[i].descriptorType) { |
| case VK_DESCRIPTOR_TYPE_SAMPLER: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| sampler_count[s] += pCreateInfo->pBinding[i].count; |
| break; |
| |
| case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| sampler_count[s] += pCreateInfo->pBinding[i].count; |
| |
| /* fall through */ |
| |
| case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: |
| case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: |
| case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| surface_count[s] += pCreateInfo->pBinding[i].count; |
| break; |
| default: |
| break; |
| } |
| |
| count += pCreateInfo->pBinding[i].count; |
| } |
| |
| for (uint32_t i = 0; i < pCreateInfo->count; i++) { |
| switch (pCreateInfo->pBinding[i].descriptorType) { |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: |
| num_dynamic_buffers++; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| uint32_t sampler_total = 0; |
| uint32_t surface_total = 0; |
| for (uint32_t s = 0; s < VK_NUM_SHADER_STAGE; s++) { |
| sampler_total += sampler_count[s]; |
| surface_total += surface_count[s]; |
| } |
| |
| size_t size = sizeof(*set_layout) + |
| (sampler_total + surface_total) * sizeof(uint32_t); |
| 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); |
| |
| set_layout->num_dynamic_buffers = num_dynamic_buffers; |
| set_layout->count = count; |
| |
| uint32_t *p = set_layout->entries; |
| uint32_t *sampler[VK_NUM_SHADER_STAGE]; |
| uint32_t *surface[VK_NUM_SHADER_STAGE]; |
| for (uint32_t s = 0; s < VK_NUM_SHADER_STAGE; s++) { |
| set_layout->stage[s].surface_count = surface_count[s]; |
| set_layout->stage[s].surface_start = surface[s] = p; |
| p += surface_count[s]; |
| set_layout->stage[s].sampler_count = sampler_count[s]; |
| set_layout->stage[s].sampler_start = sampler[s] = p; |
| p += sampler_count[s]; |
| } |
| |
| uint32_t descriptor = 0; |
| for (uint32_t i = 0; i < pCreateInfo->count; i++) { |
| switch (pCreateInfo->pBinding[i].descriptorType) { |
| case VK_DESCRIPTOR_TYPE_SAMPLER: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| for (uint32_t j = 0; j < pCreateInfo->pBinding[i].count; j++) |
| *(sampler[s])++ = descriptor + j; |
| break; |
| |
| case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| for (uint32_t j = 0; j < pCreateInfo->pBinding[i].count; j++) |
| *(sampler[s])++ = descriptor + j; |
| |
| /* fallthrough */ |
| |
| case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: |
| case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: |
| case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: |
| for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) |
| for (uint32_t j = 0; j < pCreateInfo->pBinding[i].count; j++) { |
| *(surface[s])++ = descriptor + j; |
| } |
| break; |
| default: |
| unreachable(""); |
| } |
| descriptor += pCreateInfo->pBinding[i].count; |
| } |
| |
| *pSetLayout = (VkDescriptorSetLayout) set_layout; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_BeginDescriptorPoolUpdate( |
| VkDevice device, |
| VkDescriptorUpdateMode updateMode) |
| { |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_EndDescriptorPoolUpdate( |
| VkDevice device, |
| VkCmdBuffer cmd) |
| { |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_CreateDescriptorPool( |
| VkDevice device, |
| VkDescriptorPoolUsage poolUsage, |
| uint32_t maxSets, |
| const VkDescriptorPoolCreateInfo* pCreateInfo, |
| VkDescriptorPool* pDescriptorPool) |
| { |
| *pDescriptorPool = 1; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_ResetDescriptorPool( |
| VkDevice device, |
| VkDescriptorPool descriptorPool) |
| { |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_AllocDescriptorSets( |
| 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->count * 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_SUCCESS; |
| } |
| |
| void anv_ClearDescriptorSets( |
| VkDevice device, |
| VkDescriptorPool descriptorPool, |
| uint32_t count, |
| const VkDescriptorSet* pDescriptorSets) |
| { |
| } |
| |
| void anv_UpdateDescriptors( |
| 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].sampler = |
| (struct anv_sampler *) 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].view = |
| (struct anv_surface_view *) |
| update_sampler_textures->pSamplerImageViews[j].pImageView->view; |
| set->descriptors[update_sampler_textures->binding + j].sampler = |
| (struct anv_sampler *) |
| update_sampler_textures->pSamplerImageViews[j].sampler; |
| } |
| 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].view = |
| (struct anv_surface_view *) 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].view = |
| (struct anv_surface_view *) 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 anv_CreateDynamicViewportState( |
| 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->dynamic_state_pool, |
| count * 64, 64); |
| state->cc_vp = anv_state_pool_alloc(&device->dynamic_state_pool, |
| count * 8, 32); |
| state->scissor = anv_state_pool_alloc(&device->dynamic_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 anv_CreateDynamicRasterState( |
| 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 anv_CreateDynamicColorBlendState( |
| 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 anv_CreateDynamicDepthStencilState( |
| VkDevice device, |
| const VkDynamicDsStateCreateInfo* pCreateInfo, |
| VkDynamicDsState* pState) |
| { |
| stub_return(VK_UNSUPPORTED); |
| } |
| |
| // Command buffer functions |
| |
| VkResult anv_CreateCommandBuffer( |
| 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; |
| cmd_buffer->rs_state = NULL; |
| cmd_buffer->vp_state = NULL; |
| memset(&cmd_buffer->default_bindings, 0, sizeof(cmd_buffer->default_bindings)); |
| cmd_buffer->bindings = &cmd_buffer->default_bindings; |
| |
| 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->binding_table_state_stream, |
| &device->binding_table_block_pool); |
| anv_state_stream_init(&cmd_buffer->surface_state_stream, |
| &device->surface_state_block_pool); |
| anv_state_stream_init(&cmd_buffer->dynamic_state_stream, |
| &device->dynamic_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 anv_BeginCommandBuffer( |
| 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->dynamic_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_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 anv_EndCommandBuffer( |
| 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 anv_ResetCommandBuffer( |
| 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 anv_CmdBindPipeline( |
| 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 anv_CmdBindDynamicStateObject( |
| 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; |
| /* We emit state immediately, but set cmd_buffer->vp_state to indicate |
| * that vp state has been set in this command buffer. */ |
| cmd_buffer->vp_state = vp_state; |
| 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 anv_CmdBindDescriptorSets( |
| 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; |
| struct anv_pipeline_layout *layout = cmd_buffer->pipeline->layout; |
| struct anv_bindings *bindings = cmd_buffer->bindings; |
| |
| uint32_t offset = 0; |
| for (uint32_t i = 0; i < setCount; i++) { |
| struct anv_descriptor_set *set = |
| (struct anv_descriptor_set *) pDescriptorSets[i]; |
| struct anv_descriptor_set_layout *set_layout = layout->set[firstSet + i].layout; |
| |
| for (uint32_t s = 0; s < VK_NUM_SHADER_STAGE; s++) { |
| uint32_t *surface_to_desc = set_layout->stage[s].surface_start; |
| uint32_t *sampler_to_desc = set_layout->stage[s].sampler_start; |
| uint32_t bias = s == VK_SHADER_STAGE_FRAGMENT ? MAX_RTS : 0; |
| uint32_t start; |
| |
| start = bias + layout->set[firstSet + i].surface_start[s]; |
| for (uint32_t b = 0; b < set_layout->stage[s].surface_count; b++) { |
| struct anv_surface_view *view = set->descriptors[surface_to_desc[b]].view; |
| |
| bindings->descriptors[s].surfaces[start + b] = |
| view->surface_state.offset; |
| bindings->descriptors[s].relocs[start + b].bo = view->bo; |
| bindings->descriptors[s].relocs[start + b].offset = view->offset; |
| } |
| |
| start = layout->set[firstSet + i].sampler_start[s]; |
| for (uint32_t b = 0; b < set_layout->stage[s].sampler_count; b++) { |
| struct anv_sampler *sampler = set->descriptors[sampler_to_desc[b]].sampler; |
| |
| memcpy(&bindings->descriptors[s].samplers[start + b], |
| sampler->state, sizeof(sampler->state)); |
| } |
| } |
| |
| offset += layout->set[firstSet + i].layout->num_dynamic_buffers; |
| } |
| |
| cmd_buffer->dirty |= ANV_CMD_BUFFER_DESCRIPTOR_SET_DIRTY; |
| } |
| |
| void anv_CmdBindIndexBuffer( |
| 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->bo, buffer->offset + offset }, |
| .BufferSize = buffer->size - offset); |
| } |
| |
| void anv_CmdBindVertexBuffers( |
| 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; |
| struct anv_bindings *bindings = cmd_buffer->bindings; |
| |
| /* 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++) { |
| bindings->vb[startBinding + i].buffer = (struct anv_buffer *) pBuffers[i]; |
| bindings->vb[startBinding + i].offset = pOffsets[i]; |
| cmd_buffer->vb_dirty |= 1 << (startBinding + i); |
| } |
| } |
| |
| static void |
| flush_descriptor_sets(struct anv_cmd_buffer *cmd_buffer) |
| { |
| struct anv_pipeline_layout *layout = cmd_buffer->pipeline->layout; |
| struct anv_bindings *bindings = cmd_buffer->bindings; |
| uint32_t layers = cmd_buffer->framebuffer->layers; |
| |
| for (uint32_t s = 0; s < VK_NUM_SHADER_STAGE; s++) { |
| uint32_t bias; |
| |
| if (s == VK_SHADER_STAGE_FRAGMENT) { |
| bias = MAX_RTS; |
| layers = cmd_buffer->framebuffer->layers; |
| } else { |
| bias = 0; |
| layers = 0; |
| } |
| |
| /* This is a little awkward: layout can be NULL but we still have to |
| * allocate and set a binding table for the PS stage for render |
| * targets. */ |
| uint32_t surface_count = layout ? layout->stage[s].surface_count : 0; |
| |
| if (layers + surface_count > 0) { |
| struct anv_state state; |
| uint32_t size; |
| |
| size = (bias + surface_count) * sizeof(uint32_t); |
| state = anv_state_stream_alloc(&cmd_buffer->binding_table_state_stream, |
| size, 32); |
| memcpy(state.map, bindings->descriptors[s].surfaces, size); |
| |
| for (uint32_t i = 0; i < layers; i++) |
| anv_reloc_list_add(&cmd_buffer->batch.surf_relocs, |
| bindings->descriptors[s].surfaces[i] + 8 * sizeof(int32_t), |
| bindings->descriptors[s].relocs[i].bo, |
| bindings->descriptors[s].relocs[i].offset); |
| |
| for (uint32_t i = 0; i < surface_count; i++) |
| anv_reloc_list_add(&cmd_buffer->batch.surf_relocs, |
| bindings->descriptors[s].surfaces[bias + i] + 8 * sizeof(int32_t), |
| bindings->descriptors[s].relocs[bias + i].bo, |
| bindings->descriptors[s].relocs[bias + i].offset); |
| |
| static const uint32_t binding_table_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, |
| }; |
| |
| anv_batch_emit(&cmd_buffer->batch, |
| GEN8_3DSTATE_BINDING_TABLE_POINTERS_VS, |
| ._3DCommandSubOpcode = binding_table_opcodes[s], |
| .PointertoVSBindingTable = state.offset); |
| } |
| |
| if (layout && layout->stage[s].sampler_count > 0) { |
| struct anv_state state; |
| size_t size; |
| |
| size = layout->stage[s].sampler_count * 16; |
| state = anv_state_stream_alloc(&cmd_buffer->dynamic_state_stream, size, 32); |
| memcpy(state.map, bindings->descriptors[s].samplers, size); |
| |
| static const uint32_t sampler_state_opcodes[] = { |
| [VK_SHADER_STAGE_VERTEX] = 43, |
| [VK_SHADER_STAGE_TESS_CONTROL] = 44, /* HS */ |
| [VK_SHADER_STAGE_TESS_EVALUATION] = 45, /* DS */ |
| [VK_SHADER_STAGE_GEOMETRY] = 46, |
| [VK_SHADER_STAGE_FRAGMENT] = 47, |
| [VK_SHADER_STAGE_COMPUTE] = 0, |
| }; |
| |
| anv_batch_emit(&cmd_buffer->batch, |
| GEN8_3DSTATE_SAMPLER_STATE_POINTERS_VS, |
| ._3DCommandSubOpcode = sampler_state_opcodes[s], |
| .PointertoVSSamplerState = state.offset); |
| } |
| } |
| } |
| |
| static void |
| anv_cmd_buffer_flush_state(struct anv_cmd_buffer *cmd_buffer) |
| { |
| struct anv_pipeline *pipeline = cmd_buffer->pipeline; |
| struct anv_bindings *bindings = cmd_buffer->bindings; |
| 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 = bindings->vb[vb].buffer; |
| uint32_t offset = bindings->vb[vb].offset; |
| |
| struct GEN8_VERTEX_BUFFER_STATE state = { |
| .VertexBufferIndex = vb, |
| .MemoryObjectControlState = 0, |
| .AddressModifyEnable = true, |
| .BufferPitch = pipeline->binding_stride[vb], |
| .BufferStartingAddress = { buffer->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)) |
| anv_batch_emit_merge(&cmd_buffer->batch, |
| cmd_buffer->rs_state->state_sf, pipeline->state_sf); |
| |
| cmd_buffer->vb_dirty = 0; |
| cmd_buffer->dirty = 0; |
| } |
| |
| void anv_CmdDraw( |
| 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 anv_CmdDrawIndexed( |
| 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 anv_CmdDrawIndirect( |
| 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->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 anv_CmdDrawIndexedIndirect( |
| 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->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 anv_CmdDispatch( |
| VkCmdBuffer cmdBuffer, |
| uint32_t x, |
| uint32_t y, |
| uint32_t z) |
| { |
| stub(); |
| } |
| |
| void anv_CmdDispatchIndirect( |
| VkCmdBuffer cmdBuffer, |
| VkBuffer buffer, |
| VkDeviceSize offset) |
| { |
| stub(); |
| } |
| |
| void anv_CmdSetEvent( |
| VkCmdBuffer cmdBuffer, |
| VkEvent event, |
| VkPipeEvent pipeEvent) |
| { |
| stub(); |
| } |
| |
| void anv_CmdResetEvent( |
| VkCmdBuffer cmdBuffer, |
| VkEvent event, |
| VkPipeEvent pipeEvent) |
| { |
| stub(); |
| } |
| |
| void anv_CmdWaitEvents( |
| VkCmdBuffer cmdBuffer, |
| VkWaitEvent waitEvent, |
| uint32_t eventCount, |
| const VkEvent* pEvents, |
| uint32_t memBarrierCount, |
| const void** ppMemBarriers) |
| { |
| stub(); |
| } |
| |
| void anv_CmdPipelineBarrier( |
| VkCmdBuffer cmdBuffer, |
| VkWaitEvent waitEvent, |
| uint32_t pipeEventCount, |
| const VkPipeEvent* pPipeEvents, |
| uint32_t memBarrierCount, |
| const void** ppMemBarriers) |
| { |
| stub(); |
| } |
| |
| 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 anv_CmdBeginQuery( |
| 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 * sizeof(struct anv_query_pool_slot)); |
| break; |
| |
| case VK_QUERY_TYPE_PIPELINE_STATISTICS: |
| default: |
| unreachable(""); |
| } |
| } |
| |
| void anv_CmdEndQuery( |
| 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 * sizeof(struct anv_query_pool_slot) + 8); |
| break; |
| |
| case VK_QUERY_TYPE_PIPELINE_STATISTICS: |
| default: |
| unreachable(""); |
| } |
| } |
| |
| void anv_CmdResetQueryPool( |
| VkCmdBuffer cmdBuffer, |
| VkQueryPool queryPool, |
| uint32_t startQuery, |
| uint32_t queryCount) |
| { |
| stub(); |
| } |
| |
| #define TIMESTAMP 0x2358 |
| |
| void anv_CmdWriteTimestamp( |
| 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->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 }); |
| anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM, |
| .RegisterAddress = TIMESTAMP + 4, |
| .MemoryAddress = { bo, buffer->offset + destOffset + 4 }); |
| 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; |
| } |
| } |
| |
| #define alu_opcode(v) __gen_field((v), 20, 31) |
| #define alu_operand1(v) __gen_field((v), 10, 19) |
| #define alu_operand2(v) __gen_field((v), 0, 9) |
| #define alu(opcode, operand1, operand2) \ |
| alu_opcode(opcode) | alu_operand1(operand1) | alu_operand2(operand2) |
| |
| #define OPCODE_NOOP 0x000 |
| #define OPCODE_LOAD 0x080 |
| #define OPCODE_LOADINV 0x480 |
| #define OPCODE_LOAD0 0x081 |
| #define OPCODE_LOAD1 0x481 |
| #define OPCODE_ADD 0x100 |
| #define OPCODE_SUB 0x101 |
| #define OPCODE_AND 0x102 |
| #define OPCODE_OR 0x103 |
| #define OPCODE_XOR 0x104 |
| #define OPCODE_STORE 0x180 |
| #define OPCODE_STOREINV 0x580 |
| |
| #define OPERAND_R0 0x00 |
| #define OPERAND_R1 0x01 |
| #define OPERAND_R2 0x02 |
| #define OPERAND_R3 0x03 |
| #define OPERAND_R4 0x04 |
| #define OPERAND_SRCA 0x20 |
| #define OPERAND_SRCB 0x21 |
| #define OPERAND_ACCU 0x31 |
| #define OPERAND_ZF 0x32 |
| #define OPERAND_CF 0x33 |
| |
| #define CS_GPR(n) (0x2600 + (n) * 8) |
| |
| static void |
| emit_load_alu_reg_u64(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 }); |
| anv_batch_emit(batch, GEN8_MI_LOAD_REGISTER_MEM, |
| .RegisterAddress = reg + 4, |
| .MemoryAddress = { bo, offset + 4 }); |
| } |
| |
| void anv_CmdCopyQueryPoolResults( |
| VkCmdBuffer cmdBuffer, |
| VkQueryPool queryPool, |
| uint32_t startQuery, |
| uint32_t queryCount, |
| VkBuffer destBuffer, |
| VkDeviceSize destOffset, |
| VkDeviceSize destStride, |
| VkQueryResultFlags flags) |
| { |
| struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *) cmdBuffer; |
| struct anv_query_pool *pool = (struct anv_query_pool *) queryPool; |
| struct anv_buffer *buffer = (struct anv_buffer *) destBuffer; |
| uint32_t slot_offset, dst_offset; |
| |
| if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) { |
| /* Where is the availabilty info supposed to go? */ |
| anv_finishme("VK_QUERY_RESULT_WITH_AVAILABILITY_BIT"); |
| return; |
| } |
| |
| assert(pool->type == VK_QUERY_TYPE_OCCLUSION); |
| |
| /* FIXME: If we're not waiting, should we just do this on the CPU? */ |
| if (flags & VK_QUERY_RESULT_WAIT_BIT) |
| anv_batch_emit(&cmd_buffer->batch, GEN8_PIPE_CONTROL, |
| .CommandStreamerStallEnable = true); |
| |
| dst_offset = buffer->offset + destOffset; |
| for (uint32_t i = 0; i < queryCount; i++) { |
| |
| slot_offset = (startQuery + i) * sizeof(struct anv_query_pool_slot); |
| |
| emit_load_alu_reg_u64(&cmd_buffer->batch, CS_GPR(0), &pool->bo, slot_offset); |
| emit_load_alu_reg_u64(&cmd_buffer->batch, CS_GPR(1), &pool->bo, slot_offset + 8); |
| |
| /* FIXME: We need to clamp the result for 32 bit. */ |
| |
| uint32_t *dw = anv_batch_emitn(&cmd_buffer->batch, 5, GEN8_MI_MATH); |
| dw[1] = alu(OPCODE_LOAD, OPERAND_SRCA, OPERAND_R1); |
| dw[2] = alu(OPCODE_LOAD, OPERAND_SRCB, OPERAND_R0); |
| dw[3] = alu(OPCODE_SUB, 0, 0); |
| dw[4] = alu(OPCODE_STORE, OPERAND_R2, OPERAND_ACCU); |
| |
| anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM, |
| .RegisterAddress = CS_GPR(2), |
| /* FIXME: This is only lower 32 bits */ |
| .MemoryAddress = { buffer->bo, dst_offset }); |
| |
| if (flags & VK_QUERY_RESULT_64_BIT) |
| anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM, |
| .RegisterAddress = CS_GPR(2) + 4, |
| /* FIXME: This is only lower 32 bits */ |
| .MemoryAddress = { buffer->bo, dst_offset + 4 }); |
| |
| dst_offset += destStride; |
| } |
| } |
| |
| void anv_CmdInitAtomicCounters( |
| VkCmdBuffer cmdBuffer, |
| VkPipelineBindPoint pipelineBindPoint, |
| uint32_t startCounter, |
| uint32_t counterCount, |
| const uint32_t* pData) |
| { |
| stub(); |
| } |
| |
| void anv_CmdLoadAtomicCounters( |
| VkCmdBuffer cmdBuffer, |
| VkPipelineBindPoint pipelineBindPoint, |
| uint32_t startCounter, |
| uint32_t counterCount, |
| VkBuffer srcBuffer, |
| VkDeviceSize srcOffset) |
| { |
| stub(); |
| } |
| |
| void anv_CmdSaveAtomicCounters( |
| VkCmdBuffer cmdBuffer, |
| VkPipelineBindPoint pipelineBindPoint, |
| uint32_t startCounter, |
| uint32_t counterCount, |
| VkBuffer destBuffer, |
| VkDeviceSize destOffset) |
| { |
| stub(); |
| } |
| |
| VkResult anv_CreateFramebuffer( |
| 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_surface_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; |
| |
| vkCreateDynamicViewportState((VkDevice) device, |
| &(VkDynamicVpStateCreateInfo) { |
| .sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO, |
| .viewportAndScissorCount = 2, |
| .pViewports = (VkViewport[]) { |
| { |
| .originX = 0, |
| .originY = 0, |
| .width = pCreateInfo->width, |
| .height = pCreateInfo->height, |
| .minDepth = 0, |
| .maxDepth = 1 |
| }, |
| }, |
| .pScissors = (VkRect[]) { |
| { { 0, 0 }, |
| { pCreateInfo->width, pCreateInfo->height } }, |
| } |
| }, |
| &framebuffer->vp_state); |
| |
| *pFramebuffer = (VkFramebuffer) framebuffer; |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult anv_CreateRenderPass( |
| VkDevice _device, |
| const VkRenderPassCreateInfo* pCreateInfo, |
| VkRenderPass* pRenderPass) |
| { |
| struct anv_device *device = (struct anv_device *) _device; |
| struct anv_render_pass *pass; |
| size_t size; |
| |
| assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); |
| |
| size = sizeof(*pass) + |
| pCreateInfo->layers * sizeof(struct anv_render_pass_layer); |
| pass = anv_device_alloc(device, size, 8, |
| VK_SYSTEM_ALLOC_TYPE_API_OBJECT); |
| if (pass == NULL) |
| return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| pass->render_area = pCreateInfo->renderArea; |
| |
| pass->num_layers = pCreateInfo->layers; |
| |
| pass->num_clear_layers = 0; |
| for (uint32_t i = 0; i < pCreateInfo->layers; i++) { |
| pass->layers[i].color_load_op = pCreateInfo->pColorLoadOps[i]; |
| pass->layers[i].clear_color = pCreateInfo->pColorLoadClearValues[i]; |
| if (pass->layers[i].color_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) |
| pass->num_clear_layers++; |
| } |
| |
| *pRenderPass = (VkRenderPass) pass; |
| |
| return VK_SUCCESS; |
| } |
| |
| void |
| anv_cmd_buffer_fill_render_targets(struct anv_cmd_buffer *cmd_buffer) |
| { |
| struct anv_framebuffer *framebuffer = cmd_buffer->framebuffer; |
| struct anv_bindings *bindings = cmd_buffer->bindings; |
| |
| for (uint32_t i = 0; i < framebuffer->color_attachment_count; i++) { |
| struct anv_surface_view *view = framebuffer->color_attachments[i]; |
| |
| bindings->descriptors[VK_SHADER_STAGE_FRAGMENT].surfaces[i] = view->surface_state.offset; |
| bindings->descriptors[VK_SHADER_STAGE_FRAGMENT].relocs[i].bo = view->bo; |
| bindings->descriptors[VK_SHADER_STAGE_FRAGMENT].relocs[i].offset = view->offset; |
| } |
| cmd_buffer->dirty |= ANV_CMD_BUFFER_DESCRIPTOR_SET_DIRTY; |
| } |
| |
| void anv_CmdBeginRenderPass( |
| 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; |
| struct anv_framebuffer *framebuffer = |
| (struct anv_framebuffer *) pRenderPassBegin->framebuffer; |
| |
| cmd_buffer->framebuffer = framebuffer; |
| |
| 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); |
| |
| anv_cmd_buffer_fill_render_targets(cmd_buffer); |
| |
| anv_cmd_buffer_clear(cmd_buffer, pass); |
| } |
| |
| void anv_CmdEndRenderPass( |
| VkCmdBuffer cmdBuffer, |
| VkRenderPass renderPass) |
| { |
| /* Emit a flushing pipe control at the end of a pass. This is kind of a |
| * hack but it ensures that render targets always actually get written. |
| * Eventually, we should do flushing based on image format transitions |
| * or something of that nature. |
| */ |
| struct anv_cmd_buffer *cmd_buffer = (struct anv_cmd_buffer *)cmdBuffer; |
| anv_batch_emit(&cmd_buffer->batch, GEN8_PIPE_CONTROL, |
| .PostSyncOperation = NoWrite, |
| .RenderTargetCacheFlushEnable = true, |
| .InstructionCacheInvalidateEnable = true, |
| .DepthCacheFlushEnable = true, |
| .VFCacheInvalidationEnable = true, |
| .TextureCacheInvalidationEnable = true, |
| .CommandStreamerStallEnable = true); |
| |
| stub(); |
| } |