From 2c2233e328341700b7bc5c574f9de21ab4e4116a Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Fri, 17 Jul 2015 15:04:27 -0700 Subject: vk: Prefix most filenames with anv Jason started the task by creating anv_cmd_buffer.c and anv_cmd_emit.c. This patch finishes the task by renaming all other files except gen*_pack.h and glsl_scraper.py. --- src/vulkan/.gitignore | 6 +- src/vulkan/Makefile.am | 56 +- src/vulkan/allocator.c | 665 ----------- src/vulkan/anv_allocator.c | 665 +++++++++++ src/vulkan/anv_aub.c | 310 +++++ src/vulkan/anv_aub.h | 153 +++ src/vulkan/anv_cmd_buffer.c | 2 +- src/vulkan/anv_cmd_emit.c | 2 +- src/vulkan/anv_compiler.cpp | 1209 +++++++++++++++++++ src/vulkan/anv_device.c | 2390 +++++++++++++++++++++++++++++++++++++ src/vulkan/anv_entrypoints_gen.py | 269 +++++ src/vulkan/anv_formats.c | 334 ++++++ src/vulkan/anv_gem.c | 279 +++++ src/vulkan/anv_image.c | 745 ++++++++++++ src/vulkan/anv_intel.c | 97 ++ src/vulkan/anv_meta.c | 1449 ++++++++++++++++++++++ src/vulkan/anv_pipeline.c | 950 +++++++++++++++ src/vulkan/anv_private.h | 1081 +++++++++++++++++ src/vulkan/anv_query.c | 352 ++++++ src/vulkan/anv_util.c | 151 +++ src/vulkan/anv_x11.c | 299 +++++ src/vulkan/aub.c | 310 ----- src/vulkan/aub.h | 153 --- src/vulkan/compiler.cpp | 1209 ------------------- src/vulkan/device.c | 2390 ------------------------------------- src/vulkan/formats.c | 334 ------ src/vulkan/gem.c | 279 ----- src/vulkan/image.c | 745 ------------ src/vulkan/intel.c | 97 -- src/vulkan/meta.c | 1449 ---------------------- src/vulkan/pipeline.c | 950 --------------- src/vulkan/private.h | 1081 ----------------- src/vulkan/query.c | 352 ------ src/vulkan/util.c | 151 --- src/vulkan/vk_gen.py | 269 ----- src/vulkan/x11.c | 299 ----- 36 files changed, 10766 insertions(+), 10766 deletions(-) delete mode 100644 src/vulkan/allocator.c create mode 100644 src/vulkan/anv_allocator.c create mode 100644 src/vulkan/anv_aub.c create mode 100644 src/vulkan/anv_aub.h create mode 100644 src/vulkan/anv_compiler.cpp create mode 100644 src/vulkan/anv_device.c create mode 100644 src/vulkan/anv_entrypoints_gen.py create mode 100644 src/vulkan/anv_formats.c create mode 100644 src/vulkan/anv_gem.c create mode 100644 src/vulkan/anv_image.c create mode 100644 src/vulkan/anv_intel.c create mode 100644 src/vulkan/anv_meta.c create mode 100644 src/vulkan/anv_pipeline.c create mode 100644 src/vulkan/anv_private.h create mode 100644 src/vulkan/anv_query.c create mode 100644 src/vulkan/anv_util.c create mode 100644 src/vulkan/anv_x11.c delete mode 100644 src/vulkan/aub.c delete mode 100644 src/vulkan/aub.h delete mode 100644 src/vulkan/compiler.cpp delete mode 100644 src/vulkan/device.c delete mode 100644 src/vulkan/formats.c delete mode 100644 src/vulkan/gem.c delete mode 100644 src/vulkan/image.c delete mode 100644 src/vulkan/intel.c delete mode 100644 src/vulkan/meta.c delete mode 100644 src/vulkan/pipeline.c delete mode 100644 src/vulkan/private.h delete mode 100644 src/vulkan/query.c delete mode 100644 src/vulkan/util.c delete mode 100644 src/vulkan/vk_gen.py delete mode 100644 src/vulkan/x11.c (limited to 'src/vulkan') diff --git a/src/vulkan/.gitignore b/src/vulkan/.gitignore index 617b6d4ebb9..30c614497e5 100644 --- a/src/vulkan/.gitignore +++ b/src/vulkan/.gitignore @@ -1,4 +1,4 @@ # Generated source files -/*-spirv.h -/entrypoints.c -/entrypoints.h +/*_spirv.h +/anv_entrypoints.c +/anv_entrypoints.h diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am index 5147f6c69d0..6d1212c532c 100644 --- a/src/vulkan/Makefile.am +++ b/src/vulkan/Makefile.am @@ -53,38 +53,38 @@ libvulkan_la_CFLAGS = \ libvulkan_la_CXXFLAGS = \ -Wall -Wextra -Wno-unused-parameter -fvisibility=hidden -O0 -g -libvulkan_la_SOURCES = \ - private.h \ - gem.c \ - device.c \ - anv_cmd_buffer.c \ - anv_cmd_emit.c \ - aub.c \ - allocator.c \ - util.c \ - pipeline.c \ - image.c \ - meta.c \ - intel.c \ - entrypoints.c \ - entrypoints.h \ - x11.c \ - formats.c \ - compiler.cpp \ - query.c - -BUILT_SOURCES = \ - entrypoints.h \ - entrypoints.c \ - meta-spirv.h - -entrypoints.h : vk_gen.py $(vulkan_include_HEADERS) +libvulkan_la_SOURCES = \ + anv_allocator.c \ + anv_aub.c \ + anv_cmd_buffer.c \ + anv_cmd_emit.c \ + anv_compiler.cpp \ + anv_device.c \ + anv_entrypoints.c \ + anv_entrypoints.h \ + anv_formats.c \ + anv_gem.c \ + anv_image.c \ + anv_intel.c \ + anv_meta.c \ + anv_pipeline.c \ + anv_private.h \ + anv_query.c \ + anv_util.c \ + anv_x11.c + +BUILT_SOURCES = \ + anv_entrypoints.h \ + anv_entrypoints.c \ + anv_meta_spirv.h + +anv_entrypoints.h : anv_entrypoints_gen.py $(vulkan_include_HEADERS) $(AM_V_GEN)cat $(vulkan_include_HEADERS) | $(PYTHON2) $< header > $@ -entrypoints.c : vk_gen.py $(vulkan_include_HEADERS) +anv_entrypoints.c : anv_entrypoints_gen.py $(vulkan_include_HEADERS) $(AM_V_GEN)cat $(vulkan_include_HEADERS) | $(PYTHON2) $< code > $@ -%-spirv.h: %.c glsl_scraper.py +%_spirv.h: %.c glsl_scraper.py $(AM_V_GEN) $(PYTHON2) $(srcdir)/glsl_scraper.py --glsl-only -o $@ $< CLEANFILES = $(BUILT_SOURCES) diff --git a/src/vulkan/allocator.c b/src/vulkan/allocator.c deleted file mode 100644 index 2d0d255721b..00000000000 --- a/src/vulkan/allocator.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - * 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. - */ - -#define _DEFAULT_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "private.h" - -#ifdef HAVE_VALGRIND -#define VG_NOACCESS_READ(__ptr) ({ \ - VALGRIND_MAKE_MEM_DEFINED((__ptr), sizeof(*(__ptr))); \ - __typeof(*(__ptr)) __val = *(__ptr); \ - VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr)));\ - __val; \ -}) -#define VG_NOACCESS_WRITE(__ptr, __val) ({ \ - VALGRIND_MAKE_MEM_UNDEFINED((__ptr), sizeof(*(__ptr))); \ - *(__ptr) = (__val); \ - VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr))); \ -}) -#else -#define VG_NOACCESS_READ(__ptr) (*(__ptr)) -#define VG_NOACCESS_WRITE(__ptr, __val) (*(__ptr) = (__val)) -#endif - -/* Design goals: - * - * - Lock free (except when resizing underlying bos) - * - * - Constant time allocation with typically only one atomic - * - * - Multiple allocation sizes without fragmentation - * - * - Can grow while keeping addresses and offset of contents stable - * - * - All allocations within one bo so we can point one of the - * STATE_BASE_ADDRESS pointers at it. - * - * The overall design is a two-level allocator: top level is a fixed size, big - * block (8k) allocator, which operates out of a bo. Allocation is done by - * either pulling a block from the free list or growing the used range of the - * bo. Growing the range may run out of space in the bo which we then need to - * grow. Growing the bo is tricky in a multi-threaded, lockless environment: - * we need to keep all pointers and contents in the old map valid. GEM bos in - * general can't grow, but we use a trick: we create a memfd and use ftruncate - * to grow it as necessary. We mmap the new size and then create a gem bo for - * it using the new gem userptr ioctl. Without heavy-handed locking around - * our allocation fast-path, there isn't really a way to munmap the old mmap, - * so we just keep it around until garbage collection time. While the block - * allocator is lockless for normal operations, we block other threads trying - * to allocate while we're growing the map. It sholdn't happen often, and - * growing is fast anyway. - * - * At the next level we can use various sub-allocators. The state pool is a - * pool of smaller, fixed size objects, which operates much like the block - * pool. It uses a free list for freeing objects, but when it runs out of - * space it just allocates a new block from the block pool. This allocator is - * intended for longer lived state objects such as SURFACE_STATE and most - * other persistent state objects in the API. We may need to track more info - * with these object and a pointer back to the CPU object (eg VkImage). In - * those cases we just allocate a slightly bigger object and put the extra - * state after the GPU state object. - * - * The state stream allocator works similar to how the i965 DRI driver streams - * all its state. Even with Vulkan, we need to emit transient state (whether - * surface state base or dynamic state base), and for that we can just get a - * block and fill it up. These cases are local to a command buffer and the - * sub-allocator need not be thread safe. The streaming allocator gets a new - * block when it runs out of space and chains them together so they can be - * easily freed. - */ - -/* Allocations are always at least 64 byte aligned, so 1 is an invalid value. - * We use it to indicate the free list is empty. */ -#define EMPTY 1 - -struct anv_mmap_cleanup { - void *map; - size_t size; - uint32_t gem_handle; -}; - -#define ANV_MMAP_CLEANUP_INIT ((struct anv_mmap_cleanup){0}) - -static inline long -sys_futex(void *addr1, int op, int val1, - struct timespec *timeout, void *addr2, int val3) -{ - return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); -} - -static inline int -futex_wake(uint32_t *addr, int count) -{ - return sys_futex(addr, FUTEX_WAKE, count, NULL, NULL, 0); -} - -static inline int -futex_wait(uint32_t *addr, int32_t value) -{ - return sys_futex(addr, FUTEX_WAIT, value, NULL, NULL, 0); -} - -static inline int -memfd_create(const char *name, unsigned int flags) -{ - return syscall(SYS_memfd_create, name, flags); -} - -static inline uint32_t -ilog2_round_up(uint32_t value) -{ - assert(value != 0); - return 32 - __builtin_clz(value - 1); -} - -static inline uint32_t -round_to_power_of_two(uint32_t value) -{ - return 1 << ilog2_round_up(value); -} - -static bool -anv_free_list_pop(union anv_free_list *list, void **map, uint32_t *offset) -{ - union anv_free_list current, next, old; - - current = *list; - while (current.offset != EMPTY) { - /* We have to add a memory barrier here so that the list head (and - * offset) gets read before we read the map pointer. This way we - * know that the map pointer is valid for the given offset at the - * point where we read it. - */ - __sync_synchronize(); - - uint32_t *next_ptr = *map + current.offset; - next.offset = VG_NOACCESS_READ(next_ptr); - next.count = current.count + 1; - old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, next.u64); - if (old.u64 == current.u64) { - *offset = current.offset; - return true; - } - current = old; - } - - return false; -} - -static void -anv_free_list_push(union anv_free_list *list, void *map, uint32_t offset) -{ - union anv_free_list current, old, new; - uint32_t *next_ptr = map + offset; - - old = *list; - do { - current = old; - VG_NOACCESS_WRITE(next_ptr, current.offset); - new.offset = offset; - new.count = current.count + 1; - old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, new.u64); - } while (old.u64 != current.u64); -} - -/* All pointers in the ptr_free_list are assumed to be page-aligned. This - * means that the bottom 12 bits should all be zero. - */ -#define PFL_COUNT(x) ((uintptr_t)(x) & 0xfff) -#define PFL_PTR(x) ((void *)((uintptr_t)(x) & ~0xfff)) -#define PFL_PACK(ptr, count) ({ \ - assert(((uintptr_t)(ptr) & 0xfff) == 0); \ - (void *)((uintptr_t)(ptr) | (uintptr_t)((count) & 0xfff)); \ -}) - -static bool -anv_ptr_free_list_pop(void **list, void **elem) -{ - void *current = *list; - while (PFL_PTR(current) != NULL) { - void **next_ptr = PFL_PTR(current); - void *new_ptr = VG_NOACCESS_READ(next_ptr); - unsigned new_count = PFL_COUNT(current) + 1; - void *new = PFL_PACK(new_ptr, new_count); - void *old = __sync_val_compare_and_swap(list, current, new); - if (old == current) { - *elem = PFL_PTR(current); - return true; - } - current = old; - } - - return false; -} - -static void -anv_ptr_free_list_push(void **list, void *elem) -{ - void *old, *current; - void **next_ptr = elem; - - old = *list; - do { - current = old; - VG_NOACCESS_WRITE(next_ptr, PFL_PTR(current)); - unsigned new_count = PFL_COUNT(current) + 1; - void *new = PFL_PACK(elem, new_count); - old = __sync_val_compare_and_swap(list, current, new); - } while (old != current); -} - -static int -anv_block_pool_grow(struct anv_block_pool *pool); - -void -anv_block_pool_init(struct anv_block_pool *pool, - struct anv_device *device, uint32_t block_size) -{ - assert(is_power_of_two(block_size)); - - pool->device = device; - pool->bo.gem_handle = 0; - pool->bo.offset = 0; - pool->size = 0; - pool->block_size = block_size; - pool->next_block = 0; - pool->free_list = ANV_FREE_LIST_EMPTY; - anv_vector_init(&pool->mmap_cleanups, - round_to_power_of_two(sizeof(struct anv_mmap_cleanup)), 128); - - /* Immediately grow the pool so we'll have a backing bo. */ - anv_block_pool_grow(pool); -} - -void -anv_block_pool_finish(struct anv_block_pool *pool) -{ - struct anv_mmap_cleanup *cleanup; - - anv_vector_foreach(cleanup, &pool->mmap_cleanups) { - if (cleanup->map) - munmap(cleanup->map, cleanup->size); - if (cleanup->gem_handle) - anv_gem_close(pool->device, cleanup->gem_handle); - } - - anv_vector_finish(&pool->mmap_cleanups); - - close(pool->fd); -} - -static int -anv_block_pool_grow(struct anv_block_pool *pool) -{ - size_t size; - void *map; - int gem_handle; - struct anv_mmap_cleanup *cleanup; - - if (pool->size == 0) { - size = 32 * pool->block_size; - } else { - size = pool->size * 2; - } - - cleanup = anv_vector_add(&pool->mmap_cleanups); - if (!cleanup) - return -1; - *cleanup = ANV_MMAP_CLEANUP_INIT; - - if (pool->size == 0) - pool->fd = memfd_create("block pool", MFD_CLOEXEC); - - if (pool->fd == -1) - return -1; - - if (ftruncate(pool->fd, size) == -1) - return -1; - - /* First try to see if mremap can grow the map in place. */ - map = MAP_FAILED; - if (pool->size > 0) - map = mremap(pool->map, pool->size, size, 0); - if (map == MAP_FAILED) { - /* Just leak the old map until we destroy the pool. We can't munmap it - * without races or imposing locking on the block allocate fast path. On - * the whole the leaked maps adds up to less than the size of the - * current map. MAP_POPULATE seems like the right thing to do, but we - * should try to get some numbers. - */ - map = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_POPULATE, pool->fd, 0); - cleanup->map = map; - cleanup->size = size; - } - if (map == MAP_FAILED) - return -1; - - gem_handle = anv_gem_userptr(pool->device, map, size); - if (gem_handle == 0) - return -1; - cleanup->gem_handle = gem_handle; - - /* Now that we successfull allocated everything, we can write the new - * values back into pool. */ - pool->map = map; - pool->bo.gem_handle = gem_handle; - pool->bo.size = size; - pool->bo.map = map; - pool->bo.index = 0; - - /* Write size last and after the memory barrier here. We need the memory - * barrier to make sure map and gem_handle are written before other threads - * see the new size. A thread could allocate a block and then go try using - * the old pool->map and access out of bounds. */ - - __sync_synchronize(); - pool->size = size; - - return 0; -} - -uint32_t -anv_block_pool_alloc(struct anv_block_pool *pool) -{ - uint32_t offset, block, size; - - /* Try free list first. */ - if (anv_free_list_pop(&pool->free_list, &pool->map, &offset)) { - assert(pool->map); - return offset; - } - - restart: - size = pool->size; - block = __sync_fetch_and_add(&pool->next_block, pool->block_size); - if (block < size) { - assert(pool->map); - return block; - } else if (block == size) { - /* We allocated the first block outside the pool, we have to grow it. - * pool->next_block acts a mutex: threads who try to allocate now will - * get block indexes above the current limit and hit futex_wait - * below. */ - int err = anv_block_pool_grow(pool); - assert(err == 0); - (void) err; - futex_wake(&pool->size, INT_MAX); - } else { - futex_wait(&pool->size, size); - __sync_fetch_and_add(&pool->next_block, -pool->block_size); - goto restart; - } - - return block; -} - -void -anv_block_pool_free(struct anv_block_pool *pool, uint32_t offset) -{ - anv_free_list_push(&pool->free_list, pool->map, offset); -} - -static void -anv_fixed_size_state_pool_init(struct anv_fixed_size_state_pool *pool, - size_t state_size) -{ - /* At least a cache line and must divide the block size. */ - assert(state_size >= 64 && is_power_of_two(state_size)); - - pool->state_size = state_size; - pool->free_list = ANV_FREE_LIST_EMPTY; - pool->block.next = 0; - pool->block.end = 0; -} - -static uint32_t -anv_fixed_size_state_pool_alloc(struct anv_fixed_size_state_pool *pool, - struct anv_block_pool *block_pool) -{ - uint32_t offset; - struct anv_block_state block, old, new; - - /* Try free list first. */ - if (anv_free_list_pop(&pool->free_list, &block_pool->map, &offset)) - return offset; - - /* If free list was empty (or somebody raced us and took the items) we - * allocate a new item from the end of the block */ - restart: - block.u64 = __sync_fetch_and_add(&pool->block.u64, pool->state_size); - - if (block.next < block.end) { - return block.next; - } else if (block.next == block.end) { - new.next = anv_block_pool_alloc(block_pool); - new.end = new.next + block_pool->block_size; - old.u64 = __sync_fetch_and_add(&pool->block.u64, new.u64 - block.u64); - if (old.next != block.next) - futex_wake(&pool->block.end, INT_MAX); - return new.next; - } else { - futex_wait(&pool->block.end, block.end); - __sync_fetch_and_add(&pool->block.u64, -pool->state_size); - goto restart; - } -} - -static void -anv_fixed_size_state_pool_free(struct anv_fixed_size_state_pool *pool, - struct anv_block_pool *block_pool, - uint32_t offset) -{ - anv_free_list_push(&pool->free_list, block_pool->map, offset); -} - -void -anv_state_pool_init(struct anv_state_pool *pool, - struct anv_block_pool *block_pool) -{ - pool->block_pool = block_pool; - for (unsigned i = 0; i < ANV_STATE_BUCKETS; i++) { - size_t size = 1 << (ANV_MIN_STATE_SIZE_LOG2 + i); - anv_fixed_size_state_pool_init(&pool->buckets[i], size); - } -} - -struct anv_state -anv_state_pool_alloc(struct anv_state_pool *pool, size_t size, size_t align) -{ - unsigned size_log2 = ilog2_round_up(size < align ? align : size); - assert(size_log2 <= ANV_MAX_STATE_SIZE_LOG2); - if (size_log2 < ANV_MIN_STATE_SIZE_LOG2) - size_log2 = ANV_MIN_STATE_SIZE_LOG2; - unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2; - - struct anv_state state; - state.alloc_size = 1 << size_log2; - state.offset = anv_fixed_size_state_pool_alloc(&pool->buckets[bucket], - pool->block_pool); - state.map = pool->block_pool->map + state.offset; - VG(VALGRIND_MALLOCLIKE_BLOCK(state.map, size, 0, false)); - return state; -} - -void -anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state) -{ - assert(is_power_of_two(state.alloc_size)); - unsigned size_log2 = ilog2_round_up(state.alloc_size); - assert(size_log2 >= ANV_MIN_STATE_SIZE_LOG2 && - size_log2 <= ANV_MAX_STATE_SIZE_LOG2); - unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2; - - VG(VALGRIND_FREELIKE_BLOCK(state.map, 0)); - anv_fixed_size_state_pool_free(&pool->buckets[bucket], - pool->block_pool, state.offset); -} - -#define NULL_BLOCK 1 -struct stream_block { - uint32_t next; - - /* The map for the BO at the time the block was givne to us */ - void *current_map; - -#ifdef HAVE_VALGRIND - void *_vg_ptr; -#endif -}; - -/* The state stream allocator is a one-shot, single threaded allocator for - * variable sized blocks. We use it for allocating dynamic state. - */ -void -anv_state_stream_init(struct anv_state_stream *stream, - struct anv_block_pool *block_pool) -{ - stream->block_pool = block_pool; - stream->next = 0; - stream->end = 0; - stream->current_block = NULL_BLOCK; -} - -void -anv_state_stream_finish(struct anv_state_stream *stream) -{ - struct stream_block *sb; - uint32_t block, next_block; - - block = stream->current_block; - while (block != NULL_BLOCK) { - sb = stream->block_pool->map + block; - next_block = VG_NOACCESS_READ(&sb->next); - VG(VALGRIND_FREELIKE_BLOCK(VG_NOACCESS_READ(&sb->_vg_ptr), 0)); - anv_block_pool_free(stream->block_pool, block); - block = next_block; - } -} - -struct anv_state -anv_state_stream_alloc(struct anv_state_stream *stream, - uint32_t size, uint32_t alignment) -{ - struct stream_block *sb; - struct anv_state state; - uint32_t block; - - state.offset = align_u32(stream->next, alignment); - if (state.offset + size > stream->end) { - block = anv_block_pool_alloc(stream->block_pool); - void *current_map = stream->block_pool->map; - sb = current_map + block; - VG_NOACCESS_WRITE(&sb->current_map, current_map); - VG_NOACCESS_WRITE(&sb->next, stream->current_block); - VG(VG_NOACCESS_WRITE(&sb->_vg_ptr, 0)); - stream->current_block = block; - stream->next = block + sizeof(*sb); - stream->end = block + stream->block_pool->block_size; - state.offset = align_u32(stream->next, alignment); - assert(state.offset + size <= stream->end); - } - - sb = stream->block_pool->map + stream->current_block; - void *current_map = VG_NOACCESS_READ(&sb->current_map); - - state.map = current_map + state.offset; - state.alloc_size = size; - -#ifdef HAVE_VALGRIND - void *vg_ptr = VG_NOACCESS_READ(&sb->_vg_ptr); - if (vg_ptr == NULL) { - vg_ptr = state.map; - VG_NOACCESS_WRITE(&sb->_vg_ptr, vg_ptr); - VALGRIND_MALLOCLIKE_BLOCK(vg_ptr, size, 0, false); - } else { - ptrdiff_t vg_offset = vg_ptr - current_map; - assert(vg_offset >= stream->current_block && - vg_offset < stream->end); - VALGRIND_RESIZEINPLACE_BLOCK(vg_ptr, - stream->next - vg_offset, - (state.offset + size) - vg_offset, - 0); - } -#endif - - stream->next = state.offset + size; - - return state; -} - -struct bo_pool_bo_link { - struct bo_pool_bo_link *next; - struct anv_bo bo; -}; - -void -anv_bo_pool_init(struct anv_bo_pool *pool, - struct anv_device *device, uint32_t bo_size) -{ - pool->device = device; - pool->bo_size = bo_size; - pool->free_list = NULL; -} - -void -anv_bo_pool_finish(struct anv_bo_pool *pool) -{ - struct bo_pool_bo_link *link = PFL_PTR(pool->free_list); - while (link != NULL) { - struct bo_pool_bo_link link_copy = VG_NOACCESS_READ(link); - - /* The anv_gem_m[un]map() functions are also valgrind-safe so they - * act as an alloc/free. In order to avoid a double-free warning, we - * need to mark thiss as malloc'd before we unmap it. - */ - VG(VALGRIND_MALLOCLIKE_BLOCK(link_copy.bo.map, pool->bo_size, 0, false)); - - anv_gem_munmap(link_copy.bo.map, pool->bo_size); - anv_gem_close(pool->device, link_copy.bo.gem_handle); - link = link_copy.next; - } -} - -VkResult -anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo) -{ - VkResult result; - - void *next_free_void; - if (anv_ptr_free_list_pop(&pool->free_list, &next_free_void)) { - struct bo_pool_bo_link *next_free = next_free_void; - *bo = VG_NOACCESS_READ(&next_free->bo); - assert(bo->map == next_free); - assert(bo->size == pool->bo_size); - - VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, pool->bo_size, 0, false)); - - return VK_SUCCESS; - } - - struct anv_bo new_bo; - - result = anv_bo_init_new(&new_bo, pool->device, pool->bo_size); - if (result != VK_SUCCESS) - return result; - - assert(new_bo.size == pool->bo_size); - - new_bo.map = anv_gem_mmap(pool->device, new_bo.gem_handle, 0, pool->bo_size); - if (new_bo.map == NULL) { - anv_gem_close(pool->device, new_bo.gem_handle); - return vk_error(VK_ERROR_MEMORY_MAP_FAILED); - } - - /* We don't need to call VALGRIND_MALLOCLIKE_BLOCK here because gem_mmap - * calls it for us. If we really want to be pedantic we could do a - * VALGRIND_FREELIKE_BLOCK right after the mmap, but there's no good - * reason. - */ - - *bo = new_bo; - return VK_SUCCESS; -} - -void -anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo) -{ - struct bo_pool_bo_link *link = bo->map; - link->bo = *bo; - - VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); - anv_ptr_free_list_push(&pool->free_list, link); -} diff --git a/src/vulkan/anv_allocator.c b/src/vulkan/anv_allocator.c new file mode 100644 index 00000000000..d85b919154d --- /dev/null +++ b/src/vulkan/anv_allocator.c @@ -0,0 +1,665 @@ +/* + * 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. + */ + +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "anv_private.h" + +#ifdef HAVE_VALGRIND +#define VG_NOACCESS_READ(__ptr) ({ \ + VALGRIND_MAKE_MEM_DEFINED((__ptr), sizeof(*(__ptr))); \ + __typeof(*(__ptr)) __val = *(__ptr); \ + VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr)));\ + __val; \ +}) +#define VG_NOACCESS_WRITE(__ptr, __val) ({ \ + VALGRIND_MAKE_MEM_UNDEFINED((__ptr), sizeof(*(__ptr))); \ + *(__ptr) = (__val); \ + VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr))); \ +}) +#else +#define VG_NOACCESS_READ(__ptr) (*(__ptr)) +#define VG_NOACCESS_WRITE(__ptr, __val) (*(__ptr) = (__val)) +#endif + +/* Design goals: + * + * - Lock free (except when resizing underlying bos) + * + * - Constant time allocation with typically only one atomic + * + * - Multiple allocation sizes without fragmentation + * + * - Can grow while keeping addresses and offset of contents stable + * + * - All allocations within one bo so we can point one of the + * STATE_BASE_ADDRESS pointers at it. + * + * The overall design is a two-level allocator: top level is a fixed size, big + * block (8k) allocator, which operates out of a bo. Allocation is done by + * either pulling a block from the free list or growing the used range of the + * bo. Growing the range may run out of space in the bo which we then need to + * grow. Growing the bo is tricky in a multi-threaded, lockless environment: + * we need to keep all pointers and contents in the old map valid. GEM bos in + * general can't grow, but we use a trick: we create a memfd and use ftruncate + * to grow it as necessary. We mmap the new size and then create a gem bo for + * it using the new gem userptr ioctl. Without heavy-handed locking around + * our allocation fast-path, there isn't really a way to munmap the old mmap, + * so we just keep it around until garbage collection time. While the block + * allocator is lockless for normal operations, we block other threads trying + * to allocate while we're growing the map. It sholdn't happen often, and + * growing is fast anyway. + * + * At the next level we can use various sub-allocators. The state pool is a + * pool of smaller, fixed size objects, which operates much like the block + * pool. It uses a free list for freeing objects, but when it runs out of + * space it just allocates a new block from the block pool. This allocator is + * intended for longer lived state objects such as SURFACE_STATE and most + * other persistent state objects in the API. We may need to track more info + * with these object and a pointer back to the CPU object (eg VkImage). In + * those cases we just allocate a slightly bigger object and put the extra + * state after the GPU state object. + * + * The state stream allocator works similar to how the i965 DRI driver streams + * all its state. Even with Vulkan, we need to emit transient state (whether + * surface state base or dynamic state base), and for that we can just get a + * block and fill it up. These cases are local to a command buffer and the + * sub-allocator need not be thread safe. The streaming allocator gets a new + * block when it runs out of space and chains them together so they can be + * easily freed. + */ + +/* Allocations are always at least 64 byte aligned, so 1 is an invalid value. + * We use it to indicate the free list is empty. */ +#define EMPTY 1 + +struct anv_mmap_cleanup { + void *map; + size_t size; + uint32_t gem_handle; +}; + +#define ANV_MMAP_CLEANUP_INIT ((struct anv_mmap_cleanup){0}) + +static inline long +sys_futex(void *addr1, int op, int val1, + struct timespec *timeout, void *addr2, int val3) +{ + return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); +} + +static inline int +futex_wake(uint32_t *addr, int count) +{ + return sys_futex(addr, FUTEX_WAKE, count, NULL, NULL, 0); +} + +static inline int +futex_wait(uint32_t *addr, int32_t value) +{ + return sys_futex(addr, FUTEX_WAIT, value, NULL, NULL, 0); +} + +static inline int +memfd_create(const char *name, unsigned int flags) +{ + return syscall(SYS_memfd_create, name, flags); +} + +static inline uint32_t +ilog2_round_up(uint32_t value) +{ + assert(value != 0); + return 32 - __builtin_clz(value - 1); +} + +static inline uint32_t +round_to_power_of_two(uint32_t value) +{ + return 1 << ilog2_round_up(value); +} + +static bool +anv_free_list_pop(union anv_free_list *list, void **map, uint32_t *offset) +{ + union anv_free_list current, next, old; + + current = *list; + while (current.offset != EMPTY) { + /* We have to add a memory barrier here so that the list head (and + * offset) gets read before we read the map pointer. This way we + * know that the map pointer is valid for the given offset at the + * point where we read it. + */ + __sync_synchronize(); + + uint32_t *next_ptr = *map + current.offset; + next.offset = VG_NOACCESS_READ(next_ptr); + next.count = current.count + 1; + old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, next.u64); + if (old.u64 == current.u64) { + *offset = current.offset; + return true; + } + current = old; + } + + return false; +} + +static void +anv_free_list_push(union anv_free_list *list, void *map, uint32_t offset) +{ + union anv_free_list current, old, new; + uint32_t *next_ptr = map + offset; + + old = *list; + do { + current = old; + VG_NOACCESS_WRITE(next_ptr, current.offset); + new.offset = offset; + new.count = current.count + 1; + old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, new.u64); + } while (old.u64 != current.u64); +} + +/* All pointers in the ptr_free_list are assumed to be page-aligned. This + * means that the bottom 12 bits should all be zero. + */ +#define PFL_COUNT(x) ((uintptr_t)(x) & 0xfff) +#define PFL_PTR(x) ((void *)((uintptr_t)(x) & ~0xfff)) +#define PFL_PACK(ptr, count) ({ \ + assert(((uintptr_t)(ptr) & 0xfff) == 0); \ + (void *)((uintptr_t)(ptr) | (uintptr_t)((count) & 0xfff)); \ +}) + +static bool +anv_ptr_free_list_pop(void **list, void **elem) +{ + void *current = *list; + while (PFL_PTR(current) != NULL) { + void **next_ptr = PFL_PTR(current); + void *new_ptr = VG_NOACCESS_READ(next_ptr); + unsigned new_count = PFL_COUNT(current) + 1; + void *new = PFL_PACK(new_ptr, new_count); + void *old = __sync_val_compare_and_swap(list, current, new); + if (old == current) { + *elem = PFL_PTR(current); + return true; + } + current = old; + } + + return false; +} + +static void +anv_ptr_free_list_push(void **list, void *elem) +{ + void *old, *current; + void **next_ptr = elem; + + old = *list; + do { + current = old; + VG_NOACCESS_WRITE(next_ptr, PFL_PTR(current)); + unsigned new_count = PFL_COUNT(current) + 1; + void *new = PFL_PACK(elem, new_count); + old = __sync_val_compare_and_swap(list, current, new); + } while (old != current); +} + +static int +anv_block_pool_grow(struct anv_block_pool *pool); + +void +anv_block_pool_init(struct anv_block_pool *pool, + struct anv_device *device, uint32_t block_size) +{ + assert(is_power_of_two(block_size)); + + pool->device = device; + pool->bo.gem_handle = 0; + pool->bo.offset = 0; + pool->size = 0; + pool->block_size = block_size; + pool->next_block = 0; + pool->free_list = ANV_FREE_LIST_EMPTY; + anv_vector_init(&pool->mmap_cleanups, + round_to_power_of_two(sizeof(struct anv_mmap_cleanup)), 128); + + /* Immediately grow the pool so we'll have a backing bo. */ + anv_block_pool_grow(pool); +} + +void +anv_block_pool_finish(struct anv_block_pool *pool) +{ + struct anv_mmap_cleanup *cleanup; + + anv_vector_foreach(cleanup, &pool->mmap_cleanups) { + if (cleanup->map) + munmap(cleanup->map, cleanup->size); + if (cleanup->gem_handle) + anv_gem_close(pool->device, cleanup->gem_handle); + } + + anv_vector_finish(&pool->mmap_cleanups); + + close(pool->fd); +} + +static int +anv_block_pool_grow(struct anv_block_pool *pool) +{ + size_t size; + void *map; + int gem_handle; + struct anv_mmap_cleanup *cleanup; + + if (pool->size == 0) { + size = 32 * pool->block_size; + } else { + size = pool->size * 2; + } + + cleanup = anv_vector_add(&pool->mmap_cleanups); + if (!cleanup) + return -1; + *cleanup = ANV_MMAP_CLEANUP_INIT; + + if (pool->size == 0) + pool->fd = memfd_create("block pool", MFD_CLOEXEC); + + if (pool->fd == -1) + return -1; + + if (ftruncate(pool->fd, size) == -1) + return -1; + + /* First try to see if mremap can grow the map in place. */ + map = MAP_FAILED; + if (pool->size > 0) + map = mremap(pool->map, pool->size, size, 0); + if (map == MAP_FAILED) { + /* Just leak the old map until we destroy the pool. We can't munmap it + * without races or imposing locking on the block allocate fast path. On + * the whole the leaked maps adds up to less than the size of the + * current map. MAP_POPULATE seems like the right thing to do, but we + * should try to get some numbers. + */ + map = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, pool->fd, 0); + cleanup->map = map; + cleanup->size = size; + } + if (map == MAP_FAILED) + return -1; + + gem_handle = anv_gem_userptr(pool->device, map, size); + if (gem_handle == 0) + return -1; + cleanup->gem_handle = gem_handle; + + /* Now that we successfull allocated everything, we can write the new + * values back into pool. */ + pool->map = map; + pool->bo.gem_handle = gem_handle; + pool->bo.size = size; + pool->bo.map = map; + pool->bo.index = 0; + + /* Write size last and after the memory barrier here. We need the memory + * barrier to make sure map and gem_handle are written before other threads + * see the new size. A thread could allocate a block and then go try using + * the old pool->map and access out of bounds. */ + + __sync_synchronize(); + pool->size = size; + + return 0; +} + +uint32_t +anv_block_pool_alloc(struct anv_block_pool *pool) +{ + uint32_t offset, block, size; + + /* Try free list first. */ + if (anv_free_list_pop(&pool->free_list, &pool->map, &offset)) { + assert(pool->map); + return offset; + } + + restart: + size = pool->size; + block = __sync_fetch_and_add(&pool->next_block, pool->block_size); + if (block < size) { + assert(pool->map); + return block; + } else if (block == size) { + /* We allocated the first block outside the pool, we have to grow it. + * pool->next_block acts a mutex: threads who try to allocate now will + * get block indexes above the current limit and hit futex_wait + * below. */ + int err = anv_block_pool_grow(pool); + assert(err == 0); + (void) err; + futex_wake(&pool->size, INT_MAX); + } else { + futex_wait(&pool->size, size); + __sync_fetch_and_add(&pool->next_block, -pool->block_size); + goto restart; + } + + return block; +} + +void +anv_block_pool_free(struct anv_block_pool *pool, uint32_t offset) +{ + anv_free_list_push(&pool->free_list, pool->map, offset); +} + +static void +anv_fixed_size_state_pool_init(struct anv_fixed_size_state_pool *pool, + size_t state_size) +{ + /* At least a cache line and must divide the block size. */ + assert(state_size >= 64 && is_power_of_two(state_size)); + + pool->state_size = state_size; + pool->free_list = ANV_FREE_LIST_EMPTY; + pool->block.next = 0; + pool->block.end = 0; +} + +static uint32_t +anv_fixed_size_state_pool_alloc(struct anv_fixed_size_state_pool *pool, + struct anv_block_pool *block_pool) +{ + uint32_t offset; + struct anv_block_state block, old, new; + + /* Try free list first. */ + if (anv_free_list_pop(&pool->free_list, &block_pool->map, &offset)) + return offset; + + /* If free list was empty (or somebody raced us and took the items) we + * allocate a new item from the end of the block */ + restart: + block.u64 = __sync_fetch_and_add(&pool->block.u64, pool->state_size); + + if (block.next < block.end) { + return block.next; + } else if (block.next == block.end) { + new.next = anv_block_pool_alloc(block_pool); + new.end = new.next + block_pool->block_size; + old.u64 = __sync_fetch_and_add(&pool->block.u64, new.u64 - block.u64); + if (old.next != block.next) + futex_wake(&pool->block.end, INT_MAX); + return new.next; + } else { + futex_wait(&pool->block.end, block.end); + __sync_fetch_and_add(&pool->block.u64, -pool->state_size); + goto restart; + } +} + +static void +anv_fixed_size_state_pool_free(struct anv_fixed_size_state_pool *pool, + struct anv_block_pool *block_pool, + uint32_t offset) +{ + anv_free_list_push(&pool->free_list, block_pool->map, offset); +} + +void +anv_state_pool_init(struct anv_state_pool *pool, + struct anv_block_pool *block_pool) +{ + pool->block_pool = block_pool; + for (unsigned i = 0; i < ANV_STATE_BUCKETS; i++) { + size_t size = 1 << (ANV_MIN_STATE_SIZE_LOG2 + i); + anv_fixed_size_state_pool_init(&pool->buckets[i], size); + } +} + +struct anv_state +anv_state_pool_alloc(struct anv_state_pool *pool, size_t size, size_t align) +{ + unsigned size_log2 = ilog2_round_up(size < align ? align : size); + assert(size_log2 <= ANV_MAX_STATE_SIZE_LOG2); + if (size_log2 < ANV_MIN_STATE_SIZE_LOG2) + size_log2 = ANV_MIN_STATE_SIZE_LOG2; + unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2; + + struct anv_state state; + state.alloc_size = 1 << size_log2; + state.offset = anv_fixed_size_state_pool_alloc(&pool->buckets[bucket], + pool->block_pool); + state.map = pool->block_pool->map + state.offset; + VG(VALGRIND_MALLOCLIKE_BLOCK(state.map, size, 0, false)); + return state; +} + +void +anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state) +{ + assert(is_power_of_two(state.alloc_size)); + unsigned size_log2 = ilog2_round_up(state.alloc_size); + assert(size_log2 >= ANV_MIN_STATE_SIZE_LOG2 && + size_log2 <= ANV_MAX_STATE_SIZE_LOG2); + unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2; + + VG(VALGRIND_FREELIKE_BLOCK(state.map, 0)); + anv_fixed_size_state_pool_free(&pool->buckets[bucket], + pool->block_pool, state.offset); +} + +#define NULL_BLOCK 1 +struct stream_block { + uint32_t next; + + /* The map for the BO at the time the block was givne to us */ + void *current_map; + +#ifdef HAVE_VALGRIND + void *_vg_ptr; +#endif +}; + +/* The state stream allocator is a one-shot, single threaded allocator for + * variable sized blocks. We use it for allocating dynamic state. + */ +void +anv_state_stream_init(struct anv_state_stream *stream, + struct anv_block_pool *block_pool) +{ + stream->block_pool = block_pool; + stream->next = 0; + stream->end = 0; + stream->current_block = NULL_BLOCK; +} + +void +anv_state_stream_finish(struct anv_state_stream *stream) +{ + struct stream_block *sb; + uint32_t block, next_block; + + block = stream->current_block; + while (block != NULL_BLOCK) { + sb = stream->block_pool->map + block; + next_block = VG_NOACCESS_READ(&sb->next); + VG(VALGRIND_FREELIKE_BLOCK(VG_NOACCESS_READ(&sb->_vg_ptr), 0)); + anv_block_pool_free(stream->block_pool, block); + block = next_block; + } +} + +struct anv_state +anv_state_stream_alloc(struct anv_state_stream *stream, + uint32_t size, uint32_t alignment) +{ + struct stream_block *sb; + struct anv_state state; + uint32_t block; + + state.offset = align_u32(stream->next, alignment); + if (state.offset + size > stream->end) { + block = anv_block_pool_alloc(stream->block_pool); + void *current_map = stream->block_pool->map; + sb = current_map + block; + VG_NOACCESS_WRITE(&sb->current_map, current_map); + VG_NOACCESS_WRITE(&sb->next, stream->current_block); + VG(VG_NOACCESS_WRITE(&sb->_vg_ptr, 0)); + stream->current_block = block; + stream->next = block + sizeof(*sb); + stream->end = block + stream->block_pool->block_size; + state.offset = align_u32(stream->next, alignment); + assert(state.offset + size <= stream->end); + } + + sb = stream->block_pool->map + stream->current_block; + void *current_map = VG_NOACCESS_READ(&sb->current_map); + + state.map = current_map + state.offset; + state.alloc_size = size; + +#ifdef HAVE_VALGRIND + void *vg_ptr = VG_NOACCESS_READ(&sb->_vg_ptr); + if (vg_ptr == NULL) { + vg_ptr = state.map; + VG_NOACCESS_WRITE(&sb->_vg_ptr, vg_ptr); + VALGRIND_MALLOCLIKE_BLOCK(vg_ptr, size, 0, false); + } else { + ptrdiff_t vg_offset = vg_ptr - current_map; + assert(vg_offset >= stream->current_block && + vg_offset < stream->end); + VALGRIND_RESIZEINPLACE_BLOCK(vg_ptr, + stream->next - vg_offset, + (state.offset + size) - vg_offset, + 0); + } +#endif + + stream->next = state.offset + size; + + return state; +} + +struct bo_pool_bo_link { + struct bo_pool_bo_link *next; + struct anv_bo bo; +}; + +void +anv_bo_pool_init(struct anv_bo_pool *pool, + struct anv_device *device, uint32_t bo_size) +{ + pool->device = device; + pool->bo_size = bo_size; + pool->free_list = NULL; +} + +void +anv_bo_pool_finish(struct anv_bo_pool *pool) +{ + struct bo_pool_bo_link *link = PFL_PTR(pool->free_list); + while (link != NULL) { + struct bo_pool_bo_link link_copy = VG_NOACCESS_READ(link); + + /* The anv_gem_m[un]map() functions are also valgrind-safe so they + * act as an alloc/free. In order to avoid a double-free warning, we + * need to mark thiss as malloc'd before we unmap it. + */ + VG(VALGRIND_MALLOCLIKE_BLOCK(link_copy.bo.map, pool->bo_size, 0, false)); + + anv_gem_munmap(link_copy.bo.map, pool->bo_size); + anv_gem_close(pool->device, link_copy.bo.gem_handle); + link = link_copy.next; + } +} + +VkResult +anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo) +{ + VkResult result; + + void *next_free_void; + if (anv_ptr_free_list_pop(&pool->free_list, &next_free_void)) { + struct bo_pool_bo_link *next_free = next_free_void; + *bo = VG_NOACCESS_READ(&next_free->bo); + assert(bo->map == next_free); + assert(bo->size == pool->bo_size); + + VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, pool->bo_size, 0, false)); + + return VK_SUCCESS; + } + + struct anv_bo new_bo; + + result = anv_bo_init_new(&new_bo, pool->device, pool->bo_size); + if (result != VK_SUCCESS) + return result; + + assert(new_bo.size == pool->bo_size); + + new_bo.map = anv_gem_mmap(pool->device, new_bo.gem_handle, 0, pool->bo_size); + if (new_bo.map == NULL) { + anv_gem_close(pool->device, new_bo.gem_handle); + return vk_error(VK_ERROR_MEMORY_MAP_FAILED); + } + + /* We don't need to call VALGRIND_MALLOCLIKE_BLOCK here because gem_mmap + * calls it for us. If we really want to be pedantic we could do a + * VALGRIND_FREELIKE_BLOCK right after the mmap, but there's no good + * reason. + */ + + *bo = new_bo; + return VK_SUCCESS; +} + +void +anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo) +{ + struct bo_pool_bo_link *link = bo->map; + link->bo = *bo; + + VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); + anv_ptr_free_list_push(&pool->free_list, link); +} diff --git a/src/vulkan/anv_aub.c b/src/vulkan/anv_aub.c new file mode 100644 index 00000000000..97f124a0aad --- /dev/null +++ b/src/vulkan/anv_aub.c @@ -0,0 +1,310 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "anv_private.h" +#include "anv_aub.h" + +struct anv_aub_writer { + FILE *file; + uint32_t offset; + int gen; +}; + +static void +aub_out(struct anv_aub_writer *writer, uint32_t data) +{ + fwrite(&data, 1, 4, writer->file); +} + +static void +aub_out_data(struct anv_aub_writer *writer, const void *data, size_t size) +{ + fwrite(data, 1, size, writer->file); +} + +static struct anv_aub_writer * +get_anv_aub_writer(struct anv_device *device) +{ + struct anv_aub_writer *writer = device->aub_writer; + int entry = 0x200003; + int i; + int gtt_size = 0x10000; + const char *filename; + + if (geteuid() != getuid()) + return NULL; + + if (writer) + return writer; + + writer = malloc(sizeof(*writer)); + if (writer == NULL) + return NULL; + + filename = "intel.aub"; + writer->gen = device->info.gen; + writer->file = fopen(filename, "w+"); + if (!writer->file) { + free(writer); + return NULL; + } + + /* Start allocating objects from just after the GTT. */ + writer->offset = gtt_size; + + /* Start with a (required) version packet. */ + aub_out(writer, CMD_AUB_HEADER | (13 - 2)); + aub_out(writer, + (4 << AUB_HEADER_MAJOR_SHIFT) | + (0 << AUB_HEADER_MINOR_SHIFT)); + for (i = 0; i < 8; i++) { + aub_out(writer, 0); /* app name */ + } + aub_out(writer, 0); /* timestamp */ + aub_out(writer, 0); /* timestamp */ + aub_out(writer, 0); /* comment len */ + + /* Set up the GTT. The max we can handle is 256M */ + aub_out(writer, CMD_AUB_TRACE_HEADER_BLOCK | ((writer->gen >= 8 ? 6 : 5) - 2)); + aub_out(writer, + AUB_TRACE_MEMTYPE_GTT_ENTRY | + AUB_TRACE_TYPE_NOTYPE | AUB_TRACE_OP_DATA_WRITE); + aub_out(writer, 0); /* subtype */ + aub_out(writer, 0); /* offset */ + aub_out(writer, gtt_size); /* size */ + if (writer->gen >= 8) + aub_out(writer, 0); + for (i = 0x000; i < gtt_size; i += 4, entry += 0x1000) { + aub_out(writer, entry); + } + + return device->aub_writer = writer; +} + +void +anv_aub_writer_destroy(struct anv_aub_writer *writer) +{ + fclose(writer->file); + free(writer); +} + + +/** + * Break up large objects into multiple writes. Otherwise a 128kb VBO + * would overflow the 16 bits of size field in the packet header and + * everything goes badly after that. + */ +static void +aub_write_trace_block(struct anv_aub_writer *writer, uint32_t type, + void *virtual, uint32_t size, uint32_t gtt_offset) +{ + uint32_t block_size; + uint32_t offset; + uint32_t subtype = 0; + static const char null_block[8 * 4096]; + + for (offset = 0; offset < size; offset += block_size) { + block_size = size - offset; + + if (block_size > 8 * 4096) + block_size = 8 * 4096; + + aub_out(writer, + CMD_AUB_TRACE_HEADER_BLOCK | + ((writer->gen >= 8 ? 6 : 5) - 2)); + aub_out(writer, + AUB_TRACE_MEMTYPE_GTT | + type | AUB_TRACE_OP_DATA_WRITE); + aub_out(writer, subtype); + aub_out(writer, gtt_offset + offset); + aub_out(writer, align_u32(block_size, 4)); + if (writer->gen >= 8) + aub_out(writer, 0); + + if (virtual) + aub_out_data(writer, (char *) virtual + offset, block_size); + else + aub_out_data(writer, null_block, block_size); + + /* Pad to a multiple of 4 bytes. */ + aub_out_data(writer, null_block, -block_size & 3); + } +} + +/* + * Make a ringbuffer on fly and dump it + */ +static void +aub_build_dump_ringbuffer(struct anv_aub_writer *writer, + uint32_t batch_offset, uint32_t offset, + int ring_flag) +{ + uint32_t ringbuffer[4096]; + int ring = AUB_TRACE_TYPE_RING_PRB0; /* The default ring */ + int ring_count = 0; + + if (ring_flag == I915_EXEC_BSD) + ring = AUB_TRACE_TYPE_RING_PRB1; + else if (ring_flag == I915_EXEC_BLT) + ring = AUB_TRACE_TYPE_RING_PRB2; + + /* Make a ring buffer to execute our batchbuffer. */ + memset(ringbuffer, 0, sizeof(ringbuffer)); + if (writer->gen >= 8) { + ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START | (3 - 2); + ringbuffer[ring_count++] = batch_offset; + ringbuffer[ring_count++] = 0; + } else { + ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START; + ringbuffer[ring_count++] = batch_offset; + } + + /* Write out the ring. This appears to trigger execution of + * the ring in the simulator. + */ + aub_out(writer, + CMD_AUB_TRACE_HEADER_BLOCK | + ((writer->gen >= 8 ? 6 : 5) - 2)); + aub_out(writer, + AUB_TRACE_MEMTYPE_GTT | ring | AUB_TRACE_OP_COMMAND_WRITE); + aub_out(writer, 0); /* general/surface subtype */ + aub_out(writer, offset); + aub_out(writer, ring_count * 4); + if (writer->gen >= 8) + aub_out(writer, 0); + + /* FIXME: Need some flush operations here? */ + aub_out_data(writer, ringbuffer, ring_count * 4); +} + +struct aub_bo { + uint32_t offset; + void *map; + void *relocated; +}; + +static void +relocate_bo(struct anv_bo *bo, struct drm_i915_gem_relocation_entry *relocs, + size_t num_relocs, struct aub_bo *bos) +{ + struct aub_bo *aub_bo = &bos[bo->index]; + struct drm_i915_gem_relocation_entry *reloc; + uint32_t *dw; + + aub_bo->relocated = malloc(bo->size); + memcpy(aub_bo->relocated, aub_bo->map, bo->size); + for (size_t i = 0; i < num_relocs; i++) { + reloc = &relocs[i]; + assert(reloc->offset < bo->size); + dw = aub_bo->relocated + reloc->offset; + *dw = bos[reloc->target_handle].offset + reloc->delta; + } +} + +void +anv_cmd_buffer_dump(struct anv_cmd_buffer *cmd_buffer) +{ + struct anv_device *device = cmd_buffer->device; + struct anv_batch *batch = &cmd_buffer->batch; + struct anv_aub_writer *writer; + struct anv_bo *bo; + uint32_t ring_flag = 0; + uint32_t offset; + struct aub_bo *aub_bos; + + writer = get_anv_aub_writer(device); + if (writer == NULL) + return; + + aub_bos = malloc(cmd_buffer->exec2_bo_count * sizeof(aub_bos[0])); + offset = writer->offset; + for (uint32_t i = 0; i < cmd_buffer->exec2_bo_count; i++) { + bo = cmd_buffer->exec2_bos[i]; + if (bo->map) + aub_bos[i].map = bo->map; + else + aub_bos[i].map = anv_gem_mmap(device, bo->gem_handle, 0, bo->size); + aub_bos[i].relocated = aub_bos[i].map; + aub_bos[i].offset = offset; + offset = align_u32(offset + bo->size + 4095, 4096); + } + + struct anv_batch_bo *first_bbo; + for (struct anv_batch_bo *bbo = cmd_buffer->last_batch_bo; + bbo != NULL; bbo = bbo->prev_batch_bo) { + /* Keep stashing the current BO until we get to the beginning */ + first_bbo = bbo; + + /* Handle relocations for this batch BO */ + relocate_bo(&bbo->bo, &batch->relocs.relocs[bbo->first_reloc], + bbo->num_relocs, aub_bos); + } + assert(first_bbo->prev_batch_bo == NULL); + + for (struct anv_batch_bo *bbo = cmd_buffer->surface_batch_bo; + bbo != NULL; bbo = bbo->prev_batch_bo) { + + /* Handle relocations for this surface state BO */ + relocate_bo(&bbo->bo, + &cmd_buffer->surface_relocs.relocs[bbo->first_reloc], + bbo->num_relocs, aub_bos); + } + + for (uint32_t i = 0; i < cmd_buffer->exec2_bo_count; i++) { + bo = cmd_buffer->exec2_bos[i]; + if (i == cmd_buffer->exec2_bo_count - 1) { + assert(bo == &first_bbo->bo); + aub_write_trace_block(writer, AUB_TRACE_TYPE_BATCH, + aub_bos[i].relocated, + first_bbo->length, aub_bos[i].offset); + } else { + aub_write_trace_block(writer, AUB_TRACE_TYPE_NOTYPE, + aub_bos[i].relocated, + bo->size, aub_bos[i].offset); + } + if (aub_bos[i].relocated != aub_bos[i].map) + free(aub_bos[i].relocated); + if (aub_bos[i].map != bo->map) + anv_gem_munmap(aub_bos[i].map, bo->size); + } + + /* Dump ring buffer */ + aub_build_dump_ringbuffer(writer, aub_bos[first_bbo->bo.index].offset, + offset, ring_flag); + + free(aub_bos); + + fflush(writer->file); +} diff --git a/src/vulkan/anv_aub.h b/src/vulkan/anv_aub.h new file mode 100644 index 00000000000..7a67712ff9c --- /dev/null +++ b/src/vulkan/anv_aub.h @@ -0,0 +1,153 @@ +/* + * 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. + * + * Authors: + * Eric Anholt + * + */ + +/** @file intel_aub.h + * + * The AUB file is a file format used by Intel's internal simulation + * and other validation tools. It can be used at various levels by a + * driver to input state to the simulated hardware or a replaying + * debugger. + * + * We choose to dump AUB files using the trace block format for ease + * of implementation -- dump out the blocks of memory as plain blobs + * and insert ring commands to execute the batchbuffer blob. + */ + +#ifndef _INTEL_AUB_H +#define _INTEL_AUB_H + +#define AUB_MI_NOOP (0) +#define AUB_MI_BATCH_BUFFER_START (0x31 << 23) +#define AUB_PIPE_CONTROL (0x7a000002) + +/* DW0: instruction type. */ + +#define CMD_AUB (7 << 29) + +#define CMD_AUB_HEADER (CMD_AUB | (1 << 23) | (0x05 << 16)) +/* DW1 */ +# define AUB_HEADER_MAJOR_SHIFT 24 +# define AUB_HEADER_MINOR_SHIFT 16 + +#define CMD_AUB_TRACE_HEADER_BLOCK (CMD_AUB | (1 << 23) | (0x41 << 16)) +#define CMD_AUB_DUMP_BMP (CMD_AUB | (1 << 23) | (0x9e << 16)) + +/* DW1 */ +#define AUB_TRACE_OPERATION_MASK 0x000000ff +#define AUB_TRACE_OP_COMMENT 0x00000000 +#define AUB_TRACE_OP_DATA_WRITE 0x00000001 +#define AUB_TRACE_OP_COMMAND_WRITE 0x00000002 +#define AUB_TRACE_OP_MMIO_WRITE 0x00000003 +// operation = TRACE_DATA_WRITE, Type +#define AUB_TRACE_TYPE_MASK 0x0000ff00 +#define AUB_TRACE_TYPE_NOTYPE (0 << 8) +#define AUB_TRACE_TYPE_BATCH (1 << 8) +#define AUB_TRACE_TYPE_VERTEX_BUFFER (5 << 8) +#define AUB_TRACE_TYPE_2D_MAP (6 << 8) +#define AUB_TRACE_TYPE_CUBE_MAP (7 << 8) +#define AUB_TRACE_TYPE_VOLUME_MAP (9 << 8) +#define AUB_TRACE_TYPE_1D_MAP (10 << 8) +#define AUB_TRACE_TYPE_CONSTANT_BUFFER (11 << 8) +#define AUB_TRACE_TYPE_CONSTANT_URB (12 << 8) +#define AUB_TRACE_TYPE_INDEX_BUFFER (13 << 8) +#define AUB_TRACE_TYPE_GENERAL (14 << 8) +#define AUB_TRACE_TYPE_SURFACE (15 << 8) + + +// operation = TRACE_COMMAND_WRITE, Type = +#define AUB_TRACE_TYPE_RING_HWB (1 << 8) +#define AUB_TRACE_TYPE_RING_PRB0 (2 << 8) +#define AUB_TRACE_TYPE_RING_PRB1 (3 << 8) +#define AUB_TRACE_TYPE_RING_PRB2 (4 << 8) + +// Address space +#define AUB_TRACE_ADDRESS_SPACE_MASK 0x00ff0000 +#define AUB_TRACE_MEMTYPE_GTT (0 << 16) +#define AUB_TRACE_MEMTYPE_LOCAL (1 << 16) +#define AUB_TRACE_MEMTYPE_NONLOCAL (2 << 16) +#define AUB_TRACE_MEMTYPE_PCI (3 << 16) +#define AUB_TRACE_MEMTYPE_GTT_ENTRY (4 << 16) + +/* DW2 */ + +/** + * aub_state_struct_type enum values are encoded with the top 16 bits + * representing the type to be delivered to the .aub file, and the bottom 16 + * bits representing the subtype. This macro performs the encoding. + */ +#define ENCODE_SS_TYPE(type, subtype) (((type) << 16) | (subtype)) + +enum aub_state_struct_type { + AUB_TRACE_VS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 1), + AUB_TRACE_GS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 2), + AUB_TRACE_CLIP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 3), + AUB_TRACE_SF_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 4), + AUB_TRACE_WM_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 5), + AUB_TRACE_CC_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 6), + AUB_TRACE_CLIP_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 7), + AUB_TRACE_SF_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 8), + AUB_TRACE_CC_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x9), + AUB_TRACE_SAMPLER_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xa), + AUB_TRACE_KERNEL_INSTRUCTIONS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xb), + AUB_TRACE_SCRATCH_SPACE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xc), + AUB_TRACE_SAMPLER_DEFAULT_COLOR = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xd), + + AUB_TRACE_SCISSOR_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x15), + AUB_TRACE_BLEND_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x16), + AUB_TRACE_DEPTH_STENCIL_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x17), + + AUB_TRACE_VERTEX_BUFFER = ENCODE_SS_TYPE(AUB_TRACE_TYPE_VERTEX_BUFFER, 0), + AUB_TRACE_BINDING_TABLE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x100), + AUB_TRACE_SURFACE_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x200), + AUB_TRACE_VS_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 0), + AUB_TRACE_WM_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 1), +}; + +#undef ENCODE_SS_TYPE + +/** + * Decode a aub_state_struct_type value to determine the type that should be + * stored in the .aub file. + */ +static inline uint32_t AUB_TRACE_TYPE(enum aub_state_struct_type ss_type) +{ + return (ss_type & 0xFFFF0000) >> 16; +} + +/** + * Decode a state_struct_type value to determine the subtype that should be + * stored in the .aub file. + */ +static inline uint32_t AUB_TRACE_SUBTYPE(enum aub_state_struct_type ss_type) +{ + return ss_type & 0xFFFF; +} + +/* DW3: address */ +/* DW4: len */ + +#endif /* _INTEL_AUB_H */ diff --git a/src/vulkan/anv_cmd_buffer.c b/src/vulkan/anv_cmd_buffer.c index 0d24d0bda02..4d4dfa9fb53 100644 --- a/src/vulkan/anv_cmd_buffer.c +++ b/src/vulkan/anv_cmd_buffer.c @@ -27,7 +27,7 @@ #include #include -#include "private.h" +#include "anv_private.h" /** \file anv_cmd_buffer.c * diff --git a/src/vulkan/anv_cmd_emit.c b/src/vulkan/anv_cmd_emit.c index 6f8788c3481..8654c4a0ac7 100644 --- a/src/vulkan/anv_cmd_emit.c +++ b/src/vulkan/anv_cmd_emit.c @@ -27,7 +27,7 @@ #include #include -#include "private.h" +#include "anv_private.h" /** \file anv_cmd_buffer.c * diff --git a/src/vulkan/anv_compiler.cpp b/src/vulkan/anv_compiler.cpp new file mode 100644 index 00000000000..a50ecfde517 --- /dev/null +++ b/src/vulkan/anv_compiler.cpp @@ -0,0 +1,1209 @@ +/* + * 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 +#include +#include + +#include "anv_private.h" + +#include +#include /* brw_new_shader_program is here */ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* XXX: We need this to keep symbols in nir.h from conflicting with the + * generated GEN command packing headers. We need to fix *both* to not + * define something as generic as LOAD. + */ +#undef LOAD + +#include + +#define SPIR_V_MAGIC_NUMBER 0x07230203 + +static void +fail_if(int cond, const char *format, ...) +{ + va_list args; + + if (!cond) + return; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + exit(1); +} + +static VkResult +set_binding_table_layout(struct brw_stage_prog_data *prog_data, + struct anv_pipeline *pipeline, uint32_t stage) +{ + uint32_t bias, count, k, *map; + struct anv_pipeline_layout *layout = pipeline->layout; + + /* No layout is valid for shaders that don't bind any resources. */ + if (pipeline->layout == NULL) + return VK_SUCCESS; + + if (stage == VK_SHADER_STAGE_FRAGMENT) + bias = MAX_RTS; + else + bias = 0; + + count = layout->stage[stage].surface_count; + prog_data->map_entries = + (uint32_t *) malloc(count * sizeof(prog_data->map_entries[0])); + if (prog_data->map_entries == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + k = bias; + map = prog_data->map_entries; + for (uint32_t i = 0; i < layout->num_sets; i++) { + prog_data->bind_map[i].index = map; + for (uint32_t j = 0; j < layout->set[i].layout->stage[stage].surface_count; j++) + *map++ = k++; + + prog_data->bind_map[i].index_count = + layout->set[i].layout->stage[stage].surface_count; + } + + return VK_SUCCESS; +} + +static void +brw_vs_populate_key(struct brw_context *brw, + struct brw_vertex_program *vp, + struct brw_vs_prog_key *key) +{ + struct gl_context *ctx = &brw->ctx; + /* BRW_NEW_VERTEX_PROGRAM */ + struct gl_program *prog = (struct gl_program *) vp; + + memset(key, 0, sizeof(*key)); + + /* Just upload the program verbatim for now. Always send it all + * the inputs it asks for, whether they are varying or not. + */ + key->base.program_string_id = vp->id; + brw_setup_vue_key_clip_info(brw, &key->base, + vp->program.Base.UsesClipDistanceOut); + + /* _NEW_POLYGON */ + if (brw->gen < 6) { + key->copy_edgeflag = (ctx->Polygon.FrontMode != GL_FILL || + ctx->Polygon.BackMode != GL_FILL); + } + + if (prog->OutputsWritten & (VARYING_BIT_COL0 | VARYING_BIT_COL1 | + VARYING_BIT_BFC0 | VARYING_BIT_BFC1)) { + /* _NEW_LIGHT | _NEW_BUFFERS */ + key->clamp_vertex_color = ctx->Light._ClampVertexColor; + } + + /* _NEW_POINT */ + if (brw->gen < 6 && ctx->Point.PointSprite) { + for (int i = 0; i < 8; i++) { + if (ctx->Point.CoordReplace[i]) + key->point_coord_replace |= (1 << i); + } + } + + /* _NEW_TEXTURE */ + brw_populate_sampler_prog_key_data(ctx, prog, brw->vs.base.sampler_count, + &key->base.tex); +} + +static bool +really_do_vs_prog(struct brw_context *brw, + struct gl_shader_program *prog, + struct brw_vertex_program *vp, + struct brw_vs_prog_key *key, struct anv_pipeline *pipeline) +{ + GLuint program_size; + const GLuint *program; + struct brw_vs_compile c; + struct brw_vs_prog_data *prog_data = &pipeline->vs_prog_data; + struct brw_stage_prog_data *stage_prog_data = &prog_data->base.base; + void *mem_ctx; + struct gl_shader *vs = NULL; + + if (prog) + vs = prog->_LinkedShaders[MESA_SHADER_VERTEX]; + + memset(&c, 0, sizeof(c)); + memcpy(&c.key, key, sizeof(*key)); + memset(prog_data, 0, sizeof(*prog_data)); + + mem_ctx = ralloc_context(NULL); + + c.vp = vp; + + /* Allocate the references to the uniforms that will end up in the + * prog_data associated with the compiled program, and which will be freed + * by the state cache. + */ + int param_count; + if (vs) { + /* We add padding around uniform values below vec4 size, with the worst + * case being a float value that gets blown up to a vec4, so be + * conservative here. + */ + param_count = vs->num_uniform_components * 4; + + } else { + param_count = vp->program.Base.Parameters->NumParameters * 4; + } + /* vec4_visitor::setup_uniform_clipplane_values() also uploads user clip + * planes as uniforms. + */ + param_count += c.key.base.nr_userclip_plane_consts * 4; + + /* Setting nr_params here NOT to the size of the param and pull_param + * arrays, but to the number of uniform components vec4_visitor + * needs. vec4_visitor::setup_uniforms() will set it back to a proper value. + */ + stage_prog_data->nr_params = ALIGN(param_count, 4) / 4; + if (vs) { + stage_prog_data->nr_params += vs->num_samplers; + } + + GLbitfield64 outputs_written = vp->program.Base.OutputsWritten; + prog_data->inputs_read = vp->program.Base.InputsRead; + + if (c.key.copy_edgeflag) { + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_EDGE); + prog_data->inputs_read |= VERT_BIT_EDGEFLAG; + } + + if (brw->gen < 6) { + /* Put dummy slots into the VUE for the SF to put the replaced + * point sprite coords in. We shouldn't need these dummy slots, + * which take up precious URB space, but it would mean that the SF + * doesn't get nice aligned pairs of input coords into output + * coords, which would be a pain to handle. + */ + for (int i = 0; i < 8; i++) { + if (c.key.point_coord_replace & (1 << i)) + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_TEX0 + i); + } + + /* if back colors are written, allocate slots for front colors too */ + if (outputs_written & BITFIELD64_BIT(VARYING_SLOT_BFC0)) + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_COL0); + if (outputs_written & BITFIELD64_BIT(VARYING_SLOT_BFC1)) + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_COL1); + } + + /* In order for legacy clipping to work, we need to populate the clip + * distance varying slots whenever clipping is enabled, even if the vertex + * shader doesn't write to gl_ClipDistance. + */ + if (c.key.base.userclip_active) { + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0); + outputs_written |= BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1); + } + + brw_compute_vue_map(brw->intelScreen->devinfo, + &prog_data->base.vue_map, outputs_written); +\ + set_binding_table_layout(&prog_data->base.base, pipeline, + VK_SHADER_STAGE_VERTEX); + + /* Emit GEN4 code. + */ + program = brw_vs_emit(brw, prog, &c, prog_data, mem_ctx, &program_size); + if (program == NULL) { + ralloc_free(mem_ctx); + return false; + } + + struct anv_state vs_state = anv_state_stream_alloc(&pipeline->program_stream, + program_size, 64); + memcpy(vs_state.map, program, program_size); + + pipeline->vs_simd8 = vs_state.offset; + + ralloc_free(mem_ctx); + + return true; +} + +void brw_wm_populate_key(struct brw_context *brw, + struct brw_fragment_program *fp, + struct brw_wm_prog_key *key) +{ + struct gl_context *ctx = &brw->ctx; + struct gl_program *prog = (struct gl_program *) brw->fragment_program; + GLuint lookup = 0; + GLuint line_aa; + bool program_uses_dfdy = fp->program.UsesDFdy; + struct gl_framebuffer draw_buffer; + bool multisample_fbo; + + memset(key, 0, sizeof(*key)); + + for (int i = 0; i < MAX_SAMPLERS; i++) { + /* Assume color sampler, no swizzling. */ + key->tex.swizzles[i] = SWIZZLE_XYZW; + } + + /* A non-zero framebuffer name indicates that the framebuffer was created by + * the user rather than the window system. */ + draw_buffer.Name = 1; + draw_buffer.Visual.samples = 1; + draw_buffer._NumColorDrawBuffers = 1; + draw_buffer._NumColorDrawBuffers = 1; + draw_buffer.Width = 400; + draw_buffer.Height = 400; + ctx->DrawBuffer = &draw_buffer; + + multisample_fbo = ctx->DrawBuffer->Visual.samples > 1; + + /* Build the index for table lookup + */ + if (brw->gen < 6) { + /* _NEW_COLOR */ + if (fp->program.UsesKill || ctx->Color.AlphaEnabled) + lookup |= IZ_PS_KILL_ALPHATEST_BIT; + + if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) + lookup |= IZ_PS_COMPUTES_DEPTH_BIT; + + /* _NEW_DEPTH */ + if (ctx->Depth.Test) + lookup |= IZ_DEPTH_TEST_ENABLE_BIT; + + if (ctx->Depth.Test && ctx->Depth.Mask) /* ?? */ + lookup |= IZ_DEPTH_WRITE_ENABLE_BIT; + + /* _NEW_STENCIL | _NEW_BUFFERS */ + if (ctx->Stencil._Enabled) { + lookup |= IZ_STENCIL_TEST_ENABLE_BIT; + + if (ctx->Stencil.WriteMask[0] || + ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) + lookup |= IZ_STENCIL_WRITE_ENABLE_BIT; + } + key->iz_lookup = lookup; + } + + line_aa = AA_NEVER; + + /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ + if (ctx->Line.SmoothFlag) { + if (brw->reduced_primitive == GL_LINES) { + line_aa = AA_ALWAYS; + } + else if (brw->reduced_primitive == GL_TRIANGLES) { + if (ctx->Polygon.FrontMode == GL_LINE) { + line_aa = AA_SOMETIMES; + + if (ctx->Polygon.BackMode == GL_LINE || + (ctx->Polygon.CullFlag && + ctx->Polygon.CullFaceMode == GL_BACK)) + line_aa = AA_ALWAYS; + } + else if (ctx->Polygon.BackMode == GL_LINE) { + line_aa = AA_SOMETIMES; + + if ((ctx->Polygon.CullFlag && + ctx->Polygon.CullFaceMode == GL_FRONT)) + line_aa = AA_ALWAYS; + } + } + } + + key->line_aa = line_aa; + + /* _NEW_HINT */ + key->high_quality_derivatives = + ctx->Hint.FragmentShaderDerivative == GL_NICEST; + + if (brw->gen < 6) + key->stats_wm = brw->stats_wm; + + /* _NEW_LIGHT */ + key->flat_shade = (ctx->Light.ShadeModel == GL_FLAT); + + /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ + key->clamp_fragment_color = ctx->Color._ClampFragmentColor; + + /* _NEW_TEXTURE */ + brw_populate_sampler_prog_key_data(ctx, prog, brw->wm.base.sampler_count, + &key->tex); + + /* _NEW_BUFFERS */ + /* + * Include the draw buffer origin and height so that we can calculate + * fragment position values relative to the bottom left of the drawable, + * from the incoming screen origin relative position we get as part of our + * payload. + * + * This is only needed for the WM_WPOSXY opcode when the fragment program + * uses the gl_FragCoord input. + * + * We could avoid recompiling by including this as a constant referenced by + * our program, but if we were to do that it would also be nice to handle + * getting that constant updated at batchbuffer submit time (when we + * hold the lock and know where the buffer really is) rather than at emit + * time when we don't hold the lock and are just guessing. We could also + * just avoid using this as key data if the program doesn't use + * fragment.position. + * + * For DRI2 the origin_x/y will always be (0,0) but we still need the + * drawable height in order to invert the Y axis. + */ + if (fp->program.Base.InputsRead & VARYING_BIT_POS) { + key->drawable_height = ctx->DrawBuffer->Height; + } + + if ((fp->program.Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { + key->render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); + } + + /* _NEW_BUFFERS */ + key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; + + /* _NEW_MULTISAMPLE, _NEW_COLOR, _NEW_BUFFERS */ + key->replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && + (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); + + /* _NEW_BUFFERS _NEW_MULTISAMPLE */ + /* Ignore sample qualifier while computing this flag. */ + key->persample_shading = + _mesa_get_min_invocations_per_fragment(ctx, &fp->program, true) > 1; + if (key->persample_shading) + key->persample_2x = ctx->DrawBuffer->Visual.samples == 2; + + key->compute_pos_offset = + _mesa_get_min_invocations_per_fragment(ctx, &fp->program, false) > 1 && + fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_POS; + + key->compute_sample_id = + multisample_fbo && + ctx->Multisample.Enabled && + (fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_ID); + + /* BRW_NEW_VUE_MAP_GEOM_OUT */ + if (brw->gen < 6 || _mesa_bitcount_64(fp->program.Base.InputsRead & + BRW_FS_VARYING_INPUT_MASK) > 16) + key->input_slots_valid = brw->vue_map_geom_out.slots_valid; + + + /* _NEW_COLOR | _NEW_BUFFERS */ + /* Pre-gen6, the hardware alpha test always used each render + * target's alpha to do alpha test, as opposed to render target 0's alpha + * like GL requires. Fix that by building the alpha test into the + * shader, and we'll skip enabling the fixed function alpha test. + */ + if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { + key->alpha_test_func = ctx->Color.AlphaFunc; + key->alpha_test_ref = ctx->Color.AlphaRef; + } + + /* The unique fragment program ID */ + key->program_string_id = fp->id; + + ctx->DrawBuffer = NULL; +} + +static uint8_t +computed_depth_mode(struct gl_fragment_program *fp) +{ + if (fp->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + switch (fp->FragDepthLayout) { + case FRAG_DEPTH_LAYOUT_NONE: + case FRAG_DEPTH_LAYOUT_ANY: + return BRW_PSCDEPTH_ON; + case FRAG_DEPTH_LAYOUT_GREATER: + return BRW_PSCDEPTH_ON_GE; + case FRAG_DEPTH_LAYOUT_LESS: + return BRW_PSCDEPTH_ON_LE; + case FRAG_DEPTH_LAYOUT_UNCHANGED: + return BRW_PSCDEPTH_OFF; + } + } + return BRW_PSCDEPTH_OFF; +} + +static bool +really_do_wm_prog(struct brw_context *brw, + struct gl_shader_program *prog, + struct brw_fragment_program *fp, + struct brw_wm_prog_key *key, struct anv_pipeline *pipeline) +{ + struct gl_context *ctx = &brw->ctx; + void *mem_ctx = ralloc_context(NULL); + struct brw_wm_prog_data *prog_data = &pipeline->wm_prog_data; + struct gl_shader *fs = NULL; + unsigned int program_size; + const uint32_t *program; + + if (prog) + fs = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; + + memset(prog_data, 0, sizeof(*prog_data)); + + /* key->alpha_test_func means simulating alpha testing via discards, + * so the shader definitely kills pixels. + */ + prog_data->uses_kill = fp->program.UsesKill || key->alpha_test_func; + + prog_data->computed_depth_mode = computed_depth_mode(&fp->program); + + /* Allocate the references to the uniforms that will end up in the + * prog_data associated with the compiled program, and which will be freed + * by the state cache. + */ + int param_count; + if (fs) { + param_count = fs->num_uniform_components; + } else { + param_count = fp->program.Base.Parameters->NumParameters * 4; + } + /* The backend also sometimes adds params for texture size. */ + param_count += 2 * ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; + prog_data->base.param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data->base.pull_param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data->base.nr_params = param_count; + + prog_data->barycentric_interp_modes = + brw_compute_barycentric_interp_modes(brw, key->flat_shade, + key->persample_shading, + &fp->program); + + set_binding_table_layout(&prog_data->base, pipeline, + VK_SHADER_STAGE_FRAGMENT); + /* This needs to come after shader time and pull constant entries, but we + * don't have those set up now, so just put it after the layout entries. + */ + prog_data->binding_table.render_target_start = 0; + + program = brw_wm_fs_emit(brw, mem_ctx, key, prog_data, + &fp->program, prog, &program_size); + if (program == NULL) { + ralloc_free(mem_ctx); + return false; + } + + struct anv_state ps_state = anv_state_stream_alloc(&pipeline->program_stream, + program_size, 64); + memcpy(ps_state.map, program, program_size); + + if (prog_data->no_8) + pipeline->ps_simd8 = NO_KERNEL; + else + pipeline->ps_simd8 = ps_state.offset; + + if (prog_data->no_8 || prog_data->prog_offset_16) { + pipeline->ps_simd16 = ps_state.offset + prog_data->prog_offset_16; + } else { + pipeline->ps_simd16 = NO_KERNEL; + } + + ralloc_free(mem_ctx); + + return true; +} + +static void +brw_gs_populate_key(struct brw_context *brw, + struct anv_pipeline *pipeline, + struct brw_geometry_program *gp, + struct brw_gs_prog_key *key) +{ + struct gl_context *ctx = &brw->ctx; + struct brw_stage_state *stage_state = &brw->gs.base; + struct gl_program *prog = &gp->program.Base; + + memset(key, 0, sizeof(*key)); + + key->base.program_string_id = gp->id; + brw_setup_vue_key_clip_info(brw, &key->base, + gp->program.Base.UsesClipDistanceOut); + + /* _NEW_TEXTURE */ + brw_populate_sampler_prog_key_data(ctx, prog, stage_state->sampler_count, + &key->base.tex); + + struct brw_vs_prog_data *prog_data = &pipeline->vs_prog_data; + + /* BRW_NEW_VUE_MAP_VS */ + key->input_varyings = prog_data->base.vue_map.slots_valid; +} + +static bool +really_do_gs_prog(struct brw_context *brw, + struct gl_shader_program *prog, + struct brw_geometry_program *gp, + struct brw_gs_prog_key *key, struct anv_pipeline *pipeline) +{ + struct brw_gs_compile_output output; + + /* FIXME: We pass the bind map to the compile in the output struct. Need + * something better. */ + set_binding_table_layout(&output.prog_data.base.base, + pipeline, VK_SHADER_STAGE_GEOMETRY); + + brw_compile_gs_prog(brw, prog, gp, key, &output); + + struct anv_state gs_state = anv_state_stream_alloc(&pipeline->program_stream, + output.program_size, 64); + memcpy(gs_state.map, output.program, output.program_size); + + pipeline->gs_vec4 = gs_state.offset; + pipeline->gs_vertex_count = gp->program.VerticesIn; + + ralloc_free(output.mem_ctx); + + return true; +} + +static bool +brw_codegen_cs_prog(struct brw_context *brw, + struct gl_shader_program *prog, + struct brw_compute_program *cp, + struct brw_cs_prog_key *key, struct anv_pipeline *pipeline) +{ + struct gl_context *ctx = &brw->ctx; + const GLuint *program; + void *mem_ctx = ralloc_context(NULL); + GLuint program_size; + struct brw_cs_prog_data *prog_data = &pipeline->cs_prog_data; + + struct gl_shader *cs = prog->_LinkedShaders[MESA_SHADER_COMPUTE]; + assert (cs); + + memset(prog_data, 0, sizeof(*prog_data)); + + set_binding_table_layout(&prog_data->base, pipeline, VK_SHADER_STAGE_COMPUTE); + + /* Allocate the references to the uniforms that will end up in the + * prog_data associated with the compiled program, and which will be freed + * by the state cache. + */ + int param_count = cs->num_uniform_components; + + /* The backend also sometimes adds params for texture size. */ + param_count += 2 * ctx->Const.Program[MESA_SHADER_COMPUTE].MaxTextureImageUnits; + prog_data->base.param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data->base.pull_param = + rzalloc_array(NULL, const gl_constant_value *, param_count); + prog_data->base.nr_params = param_count; + + program = brw_cs_emit(brw, mem_ctx, key, prog_data, + &cp->program, prog, &program_size); + if (program == NULL) { + ralloc_free(mem_ctx); + return false; + } + + if (unlikely(INTEL_DEBUG & DEBUG_CS)) + fprintf(stderr, "\n"); + + struct anv_state cs_state = anv_state_stream_alloc(&pipeline->program_stream, + program_size, 64); + memcpy(cs_state.map, program, program_size); + + pipeline->cs_simd = cs_state.offset; + + ralloc_free(mem_ctx); + + return true; +} + +static void +brw_cs_populate_key(struct brw_context *brw, + struct brw_compute_program *bcp, struct brw_cs_prog_key *key) +{ + memset(key, 0, sizeof(*key)); + + /* The unique compute program ID */ + key->program_string_id = bcp->id; +} + +static void +fail_on_compile_error(int status, const char *msg) +{ + int source, line, column; + char error[256]; + + if (status) + return; + + if (sscanf(msg, "%d:%d(%d): error: %255[^\n]", &source, &line, &column, error) == 4) + fail_if(!status, "%d:%s\n", line, error); + else + fail_if(!status, "%s\n", msg); +} + +struct anv_compiler { + struct anv_device *device; + struct intel_screen *screen; + struct brw_context *brw; + struct gl_pipeline_object pipeline; +}; + +extern "C" { + +struct anv_compiler * +anv_compiler_create(struct anv_device *device) +{ + const struct brw_device_info *devinfo = &device->info; + struct anv_compiler *compiler; + struct gl_context *ctx; + + compiler = rzalloc(NULL, struct anv_compiler); + if (compiler == NULL) + return NULL; + + compiler->screen = rzalloc(compiler, struct intel_screen); + if (compiler->screen == NULL) + goto fail; + + compiler->brw = rzalloc(compiler, struct brw_context); + if (compiler->brw == NULL) + goto fail; + + compiler->device = device; + + compiler->brw->optionCache.info = NULL; + compiler->brw->bufmgr = NULL; + compiler->brw->gen = devinfo->gen; + compiler->brw->is_g4x = devinfo->is_g4x; + compiler->brw->is_baytrail = devinfo->is_baytrail; + compiler->brw->is_haswell = devinfo->is_haswell; + compiler->brw->is_cherryview = devinfo->is_cherryview; + + /* We need this at least for CS, which will check brw->max_cs_threads + * against the work group size. */ + compiler->brw->max_vs_threads = devinfo->max_vs_threads; + compiler->brw->max_hs_threads = devinfo->max_hs_threads; + compiler->brw->max_ds_threads = devinfo->max_ds_threads; + compiler->brw->max_gs_threads = devinfo->max_gs_threads; + compiler->brw->max_wm_threads = devinfo->max_wm_threads; + compiler->brw->max_cs_threads = devinfo->max_cs_threads; + compiler->brw->urb.size = devinfo->urb.size; + compiler->brw->urb.min_vs_entries = devinfo->urb.min_vs_entries; + compiler->brw->urb.max_vs_entries = devinfo->urb.max_vs_entries; + compiler->brw->urb.max_hs_entries = devinfo->urb.max_hs_entries; + compiler->brw->urb.max_ds_entries = devinfo->urb.max_ds_entries; + compiler->brw->urb.max_gs_entries = devinfo->urb.max_gs_entries; + + compiler->brw->intelScreen = compiler->screen; + compiler->screen->devinfo = &device->info; + + brw_process_intel_debug_variable(compiler->screen); + + compiler->screen->compiler = brw_compiler_create(compiler, &device->info); + + ctx = &compiler->brw->ctx; + _mesa_init_shader_object_functions(&ctx->Driver); + + _mesa_init_constants(&ctx->Const, API_OPENGL_CORE); + + brw_initialize_context_constants(compiler->brw); + + intelInitExtensions(ctx); + + /* Set dd::NewShader */ + brwInitFragProgFuncs(&ctx->Driver); + + ctx->_Shader = &compiler->pipeline; + + compiler->brw->precompile = false; + + return compiler; + + fail: + ralloc_free(compiler); + return NULL; +} + +void +anv_compiler_destroy(struct anv_compiler *compiler) +{ + _mesa_free_errors_data(&compiler->brw->ctx); + ralloc_free(compiler); +} + +/* From gen7_urb.c */ + +/* FIXME: Add to struct intel_device_info */ + +static const int gen8_push_size = 32 * 1024; + +static void +gen7_compute_urb_partition(struct anv_pipeline *pipeline) +{ + const struct brw_device_info *devinfo = &pipeline->device->info; + bool vs_present = pipeline->vs_simd8 != NO_KERNEL; + unsigned vs_size = vs_present ? pipeline->vs_prog_data.base.urb_entry_size : 1; + unsigned vs_entry_size_bytes = vs_size * 64; + bool gs_present = pipeline->gs_vec4 != NO_KERNEL; + unsigned gs_size = gs_present ? pipeline->gs_prog_data.base.urb_entry_size : 1; + unsigned gs_entry_size_bytes = gs_size * 64; + + /* From p35 of the Ivy Bridge PRM (section 1.7.1: 3DSTATE_URB_GS): + * + * VS Number of URB Entries must be divisible by 8 if the VS URB Entry + * Allocation Size is less than 9 512-bit URB entries. + * + * Similar text exists for GS. + */ + unsigned vs_granularity = (vs_size < 9) ? 8 : 1; + unsigned gs_granularity = (gs_size < 9) ? 8 : 1; + + /* URB allocations must be done in 8k chunks. */ + unsigned chunk_size_bytes = 8192; + + /* Determine the size of the URB in chunks. */ + unsigned urb_chunks = devinfo->urb.size * 1024 / chunk_size_bytes; + + /* Reserve space for push constants */ + unsigned push_constant_bytes = gen8_push_size; + unsigned push_constant_chunks = + push_constant_bytes / chunk_size_bytes; + + /* Initially, assign each stage the minimum amount of URB space it needs, + * and make a note of how much additional space it "wants" (the amount of + * additional space it could actually make use of). + */ + + /* VS has a lower limit on the number of URB entries */ + unsigned vs_chunks = + ALIGN(devinfo->urb.min_vs_entries * vs_entry_size_bytes, + chunk_size_bytes) / chunk_size_bytes; + unsigned vs_wants = + ALIGN(devinfo->urb.max_vs_entries * vs_entry_size_bytes, + chunk_size_bytes) / chunk_size_bytes - vs_chunks; + + unsigned gs_chunks = 0; + unsigned gs_wants = 0; + if (gs_present) { + /* There are two constraints on the minimum amount of URB space we can + * allocate: + * + * (1) We need room for at least 2 URB entries, since we always operate + * the GS in DUAL_OBJECT mode. + * + * (2) We can't allocate less than nr_gs_entries_granularity. + */ + gs_chunks = ALIGN(MAX2(gs_granularity, 2) * gs_entry_size_bytes, + chunk_size_bytes) / chunk_size_bytes; + gs_wants = + ALIGN(devinfo->urb.max_gs_entries * gs_entry_size_bytes, + chunk_size_bytes) / chunk_size_bytes - gs_chunks; + } + + /* There should always be enough URB space to satisfy the minimum + * requirements of each stage. + */ + unsigned total_needs = push_constant_chunks + vs_chunks + gs_chunks; + assert(total_needs <= urb_chunks); + + /* Mete out remaining space (if any) in proportion to "wants". */ + unsigned total_wants = vs_wants + gs_wants; + unsigned remaining_space = urb_chunks - total_needs; + if (remaining_space > total_wants) + remaining_space = total_wants; + if (remaining_space > 0) { + unsigned vs_additional = (unsigned) + round(vs_wants * (((double) remaining_space) / total_wants)); + vs_chunks += vs_additional; + remaining_space -= vs_additional; + gs_chunks += remaining_space; + } + + /* Sanity check that we haven't over-allocated. */ + assert(push_constant_chunks + vs_chunks + gs_chunks <= urb_chunks); + + /* Finally, compute the number of entries that can fit in the space + * allocated to each stage. + */ + unsigned nr_vs_entries = vs_chunks * chunk_size_bytes / vs_entry_size_bytes; + unsigned nr_gs_entries = gs_chunks * chunk_size_bytes / gs_entry_size_bytes; + + /* Since we rounded up when computing *_wants, this may be slightly more + * than the maximum allowed amount, so correct for that. + */ + nr_vs_entries = MIN2(nr_vs_entries, devinfo->urb.max_vs_entries); + nr_gs_entries = MIN2(nr_gs_entries, devinfo->urb.max_gs_entries); + + /* Ensure that we program a multiple of the granularity. */ + nr_vs_entries = ROUND_DOWN_TO(nr_vs_entries, vs_granularity); + nr_gs_entries = ROUND_DOWN_TO(nr_gs_entries, gs_granularity); + + /* Finally, sanity check to make sure we have at least the minimum number + * of entries needed for each stage. + */ + assert(nr_vs_entries >= devinfo->urb.min_vs_entries); + if (gs_present) + assert(nr_gs_entries >= 2); + + /* Lay out the URB in the following order: + * - push constants + * - VS + * - GS + */ + pipeline->urb.vs_start = push_constant_chunks; + pipeline->urb.vs_size = vs_size; + pipeline->urb.nr_vs_entries = nr_vs_entries; + + pipeline->urb.gs_start = push_constant_chunks + vs_chunks; + pipeline->urb.gs_size = gs_size; + pipeline->urb.nr_gs_entries = nr_gs_entries; +} + +static const struct { + uint32_t token; + gl_shader_stage stage; + const char *name; +} stage_info[] = { + { GL_VERTEX_SHADER, MESA_SHADER_VERTEX, "vertex" }, + { GL_TESS_CONTROL_SHADER, (gl_shader_stage)-1,"tess control" }, + { GL_TESS_EVALUATION_SHADER, (gl_shader_stage)-1, "tess evaluation" }, + { GL_GEOMETRY_SHADER, MESA_SHADER_GEOMETRY, "geometry" }, + { GL_FRAGMENT_SHADER, MESA_SHADER_FRAGMENT, "fragment" }, + { GL_COMPUTE_SHADER, MESA_SHADER_COMPUTE, "compute" }, +}; + +struct spirv_header{ + uint32_t magic; + uint32_t version; + uint32_t gen_magic; +}; + +static const char * +src_as_glsl(const char *data) +{ + const struct spirv_header *as_spirv = (const struct spirv_header *)data; + + /* Check alignment */ + if ((intptr_t)data & 0x3) { + return data; + } + + if (as_spirv->magic == SPIR_V_MAGIC_NUMBER) { + /* LunarG back-door */ + if (as_spirv->version == 0) + return data + 12; + else + return NULL; + } else { + return data; + } +} + +static void +anv_compile_shader_glsl(struct anv_compiler *compiler, + struct gl_shader_program *program, + struct anv_pipeline *pipeline, uint32_t stage) +{ + struct brw_context *brw = compiler->brw; + struct gl_shader *shader; + int name = 0; + + shader = brw_new_shader(&brw->ctx, name, stage_info[stage].token); + fail_if(shader == NULL, "failed to create %s shader\n", stage_info[stage].name); + + shader->Source = strdup(src_as_glsl(pipeline->shaders[stage]->module->data)); + _mesa_glsl_compile_shader(&brw->ctx, shader, false, false); + fail_on_compile_error(shader->CompileStatus, shader->InfoLog); + + program->Shaders[program->NumShaders] = shader; + program->NumShaders++; +} + +static void +setup_nir_io(struct gl_program *prog, + nir_shader *shader) +{ + foreach_list_typed(nir_variable, var, node, &shader->inputs) { + prog->InputsRead |= BITFIELD64_BIT(var->data.location); + } + + foreach_list_typed(nir_variable, var, node, &shader->outputs) { + prog->OutputsWritten |= BITFIELD64_BIT(var->data.location); + } +} + +static void +anv_compile_shader_spirv(struct anv_compiler *compiler, + struct gl_shader_program *program, + struct anv_pipeline *pipeline, uint32_t stage) +{ + struct brw_context *brw = compiler->brw; + struct anv_shader *shader = pipeline->shaders[stage]; + struct gl_shader *mesa_shader; + int name = 0; + + mesa_shader = brw_new_shader(&brw->ctx, name, stage_info[stage].token); + fail_if(mesa_shader == NULL, + "failed to create %s shader\n", stage_info[stage].name); + + switch (stage) { + case VK_SHADER_STAGE_VERTEX: + mesa_shader->Program = &rzalloc(mesa_shader, struct brw_vertex_program)->program.Base; + break; + case VK_SHADER_STAGE_GEOMETRY: + mesa_shader->Program = &rzalloc(mesa_shader, struct brw_geometry_program)->program.Base; + break; + case VK_SHADER_STAGE_FRAGMENT: + mesa_shader->Program = &rzalloc(mesa_shader, struct brw_fragment_program)->program.Base; + break; + case VK_SHADER_STAGE_COMPUTE: + mesa_shader->Program = &rzalloc(mesa_shader, struct brw_compute_program)->program.Base; + break; + } + + mesa_shader->Program->Parameters = + rzalloc(mesa_shader, struct gl_program_parameter_list); + + mesa_shader->Type = stage_info[stage].token; + mesa_shader->Stage = stage_info[stage].stage; + + assert(shader->module->size % 4 == 0); + + struct gl_shader_compiler_options *glsl_options = + &compiler->screen->compiler->glsl_compiler_options[stage_info[stage].stage]; + + mesa_shader->Program->nir = + spirv_to_nir((uint32_t *)shader->module->data, shader->module->size / 4, + glsl_options->NirOptions); + nir_validate_shader(mesa_shader->Program->nir); + + brw_process_nir(mesa_shader->Program->nir, + compiler->screen->devinfo, + NULL, mesa_shader->Stage); + + setup_nir_io(mesa_shader->Program, mesa_shader->Program->nir); + + fail_if(mesa_shader->Program->nir == NULL, + "failed to translate SPIR-V to NIR\n"); + + program->Shaders[program->NumShaders] = mesa_shader; + program->NumShaders++; +} + +static void +add_compiled_stage(struct anv_pipeline *pipeline, uint32_t stage, + struct brw_stage_prog_data *prog_data) +{ + struct brw_device_info *devinfo = &pipeline->device->info; + uint32_t max_threads[] = { + [VK_SHADER_STAGE_VERTEX] = devinfo->max_vs_threads, + [VK_SHADER_STAGE_TESS_CONTROL] = 0, + [VK_SHADER_STAGE_TESS_EVALUATION] = 0, + [VK_SHADER_STAGE_GEOMETRY] = devinfo->max_gs_threads, + [VK_SHADER_STAGE_FRAGMENT] = devinfo->max_wm_threads, + [VK_SHADER_STAGE_COMPUTE] = devinfo->max_cs_threads, + }; + + pipeline->prog_data[stage] = prog_data; + pipeline->active_stages |= 1 << stage; + pipeline->scratch_start[stage] = pipeline->total_scratch; + pipeline->total_scratch = + align_u32(pipeline->total_scratch, 1024) + + prog_data->total_scratch * max_threads[stage]; +} + +int +anv_compiler_run(struct anv_compiler *compiler, struct anv_pipeline *pipeline) +{ + struct gl_shader_program *program; + int name = 0; + struct brw_context *brw = compiler->brw; + + pipeline->writes_point_size = false; + + /* When we free the pipeline, we detect stages based on the NULL status + * of various prog_data pointers. Make them NULL by default. + */ + memset(pipeline->prog_data, 0, sizeof(pipeline->prog_data)); + memset(pipeline->scratch_start, 0, sizeof(pipeline->scratch_start)); + + brw->use_rep_send = pipeline->use_repclear; + brw->no_simd8 = pipeline->use_repclear; + + program = brw->ctx.Driver.NewShaderProgram(name); + program->Shaders = (struct gl_shader **) + calloc(VK_SHADER_STAGE_NUM, sizeof(struct gl_shader *)); + fail_if(program == NULL || program->Shaders == NULL, + "failed to create program\n"); + + bool all_spirv = true; + for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { + if (pipeline->shaders[i] == NULL) + continue; + + /* You need at least this much for "void main() { }" anyway */ + assert(pipeline->shaders[i]->module->size >= 12); + + if (src_as_glsl(pipeline->shaders[i]->module->data)) { + all_spirv = false; + break; + } + + assert(pipeline->shaders[i]->module->size % 4 == 0); + } + + if (all_spirv) { + for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { + if (pipeline->shaders[i]) + anv_compile_shader_spirv(compiler, program, pipeline, i); + } + + for (unsigned i = 0; i < program->NumShaders; i++) { + struct gl_shader *shader = program->Shaders[i]; + program->_LinkedShaders[shader->Stage] = shader; + } + } else { + for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { + if (pipeline->shaders[i]) + anv_compile_shader_glsl(compiler, program, pipeline, i); + } + + _mesa_glsl_link_shader(&brw->ctx, program); + fail_on_compile_error(program->LinkStatus, + program->InfoLog); + } + + bool success; + pipeline->active_stages = 0; + pipeline->total_scratch = 0; + + if (pipeline->shaders[VK_SHADER_STAGE_VERTEX]) { + struct brw_vs_prog_key vs_key; + struct gl_vertex_program *vp = (struct gl_vertex_program *) + program->_LinkedShaders[MESA_SHADER_VERTEX]->Program; + struct brw_vertex_program *bvp = brw_vertex_program(vp); + + brw_vs_populate_key(brw, bvp, &vs_key); + + success = really_do_vs_prog(brw, program, bvp, &vs_key, pipeline); + fail_if(!success, "do_wm_prog failed\n"); + add_compiled_stage(pipeline, VK_SHADER_STAGE_VERTEX, + &pipeline->vs_prog_data.base.base); + + if (vp->Base.OutputsWritten & VARYING_SLOT_PSIZ) + pipeline->writes_point_size = true; + } else { + memset(&pipeline->vs_prog_data, 0, sizeof(pipeline->vs_prog_data)); + pipeline->vs_simd8 = NO_KERNEL; + } + + + if (pipeline->shaders[VK_SHADER_STAGE_GEOMETRY]) { + struct brw_gs_prog_key gs_key; + struct gl_geometry_program *gp = (struct gl_geometry_program *) + program->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program; + struct brw_geometry_program *bgp = brw_geometry_program(gp); + + brw_gs_populate_key(brw, pipeline, bgp, &gs_key); + + success = really_do_gs_prog(brw, program, bgp, &gs_key, pipeline); + fail_if(!success, "do_gs_prog failed\n"); + add_compiled_stage(pipeline, VK_SHADER_STAGE_GEOMETRY, + &pipeline->gs_prog_data.base.base); + + if (gp->Base.OutputsWritten & VARYING_SLOT_PSIZ) + pipeline->writes_point_size = true; + } else { + pipeline->gs_vec4 = NO_KERNEL; + } + + if (pipeline->shaders[VK_SHADER_STAGE_FRAGMENT]) { + struct brw_wm_prog_key wm_key; + struct gl_fragment_program *fp = (struct gl_fragment_program *) + program->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program; + struct brw_fragment_program *bfp = brw_fragment_program(fp); + + brw_wm_populate_key(brw, bfp, &wm_key); + + success = really_do_wm_prog(brw, program, bfp, &wm_key, pipeline); + fail_if(!success, "do_wm_prog failed\n"); + add_compiled_stage(pipeline, VK_SHADER_STAGE_FRAGMENT, + &pipeline->wm_prog_data.base); + } + + if (pipeline->shaders[VK_SHADER_STAGE_COMPUTE]) { + struct brw_cs_prog_key cs_key; + struct gl_compute_program *cp = (struct gl_compute_program *) + program->_LinkedShaders[MESA_SHADER_COMPUTE]->Program; + struct brw_compute_program *bcp = brw_compute_program(cp); + + brw_cs_populate_key(brw, bcp, &cs_key); + + success = brw_codegen_cs_prog(brw, program, bcp, &cs_key, pipeline); + fail_if(!success, "brw_codegen_cs_prog failed\n"); + add_compiled_stage(pipeline, VK_SHADER_STAGE_COMPUTE, + &pipeline->cs_prog_data.base); + } + + /* XXX: Deleting the shader is broken with our current SPIR-V hacks. We + * need to fix this ASAP. + */ + if (!all_spirv) + brw->ctx.Driver.DeleteShaderProgram(&brw->ctx, program); + + struct anv_device *device = compiler->device; + while (device->scratch_block_pool.bo.size < pipeline->total_scratch) + anv_block_pool_alloc(&device->scratch_block_pool); + + gen7_compute_urb_partition(pipeline); + + return 0; +} + +/* This badly named function frees the struct anv_pipeline data that the compiler + * allocates. Currently just the prog_data structs. + */ +void +anv_compiler_free(struct anv_pipeline *pipeline) +{ + for (uint32_t stage = 0; stage < VK_SHADER_STAGE_NUM; stage++) { + if (pipeline->prog_data[stage]) { + free(pipeline->prog_data[stage]->map_entries); + ralloc_free(pipeline->prog_data[stage]->param); + ralloc_free(pipeline->prog_data[stage]->pull_param); + } + } +} + +} diff --git a/src/vulkan/anv_device.c b/src/vulkan/anv_device.c new file mode 100644 index 00000000000..1847303a1cb --- /dev/null +++ b/src/vulkan/anv_device.c @@ -0,0 +1,2390 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" +#include "mesa/main/git_sha1.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 void +anv_physical_device_finish(struct anv_physical_device *device) +{ + if (device->fd >= 0) + close(device->fd); +} + +static VkResult +anv_physical_device_init(struct anv_physical_device *device, + struct anv_instance *instance, + const char *path) +{ + device->fd = open(path, O_RDWR | O_CLOEXEC); + if (device->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(device->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(device->fd, I915_PARAM_HAS_WAIT_TIMEOUT)) + goto fail; + + if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_EXECBUF2)) + goto fail; + + if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_LLC)) + goto fail; + + if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_EXEC_CONSTANTS)) + goto fail; + + return VK_SUCCESS; + +fail: + anv_physical_device_finish(device); + 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; + + 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; + + *pInstance = anv_instance_to_handle(instance); + + return VK_SUCCESS; +} + +VkResult anv_DestroyInstance( + VkInstance _instance) +{ + ANV_FROM_HANDLE(anv_instance, instance, _instance); + + if (instance->physicalDeviceCount > 0) { + anv_physical_device_finish(&instance->physicalDevice); + } + + instance->pfnFree(instance->pAllocUserData, instance); + + return VK_SUCCESS; +} + +VkResult anv_EnumeratePhysicalDevices( + VkInstance _instance, + uint32_t* pPhysicalDeviceCount, + VkPhysicalDevice* pPhysicalDevices) +{ + ANV_FROM_HANDLE(anv_instance, instance, _instance); + VkResult result; + + if (instance->physicalDeviceCount == 0) { + result = anv_physical_device_init(&instance->physicalDevice, + instance, "/dev/dri/renderD128"); + if (result != VK_SUCCESS) + return result; + + instance->physicalDeviceCount = 1; + } + + /* pPhysicalDeviceCount is an out parameter if pPhysicalDevices is NULL; + * otherwise it's an inout parameter. + * + * The Vulkan spec (git aaed022) says: + * + * pPhysicalDeviceCount is a pointer to an unsigned integer variable + * that is initialized with the number of devices the application is + * prepared to receive handles to. pname:pPhysicalDevices is pointer to + * an array of at least this many VkPhysicalDevice handles [...]. + * + * Upon success, if pPhysicalDevices is NULL, vkEnumeratePhysicalDevices + * overwrites the contents of the variable pointed to by + * pPhysicalDeviceCount with the number of physical devices in in the + * instance; otherwise, vkEnumeratePhysicalDevices overwrites + * pPhysicalDeviceCount with the number of physical handles written to + * pPhysicalDevices. + */ + if (!pPhysicalDevices) { + *pPhysicalDeviceCount = instance->physicalDeviceCount; + } else if (*pPhysicalDeviceCount >= 1) { + pPhysicalDevices[0] = anv_physical_device_to_handle(&instance->physicalDevice); + *pPhysicalDeviceCount = 1; + } else { + *pPhysicalDeviceCount = 0; + } + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceFeatures( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures* pFeatures) +{ + anv_finishme("Get correct values for PhysicalDeviceFeatures"); + + *pFeatures = (VkPhysicalDeviceFeatures) { + .robustBufferAccess = false, + .fullDrawIndexUint32 = false, + .imageCubeArray = false, + .independentBlend = false, + .geometryShader = true, + .tessellationShader = false, + .sampleRateShading = false, + .dualSourceBlend = true, + .logicOp = true, + .instancedDrawIndirect = true, + .depthClip = false, + .depthBiasClamp = false, + .fillModeNonSolid = true, + .depthBounds = false, + .wideLines = true, + .largePoints = true, + .textureCompressionETC2 = true, + .textureCompressionASTC_LDR = true, + .textureCompressionBC = true, + .pipelineStatisticsQuery = true, + .vertexSideEffects = false, + .tessellationSideEffects = false, + .geometrySideEffects = false, + .fragmentSideEffects = false, + .shaderTessellationPointSize = false, + .shaderGeometryPointSize = true, + .shaderTextureGatherExtended = true, + .shaderStorageImageExtendedFormats = false, + .shaderStorageImageMultisample = false, + .shaderStorageBufferArrayConstantIndexing = false, + .shaderStorageImageArrayConstantIndexing = false, + .shaderUniformBufferArrayDynamicIndexing = true, + .shaderSampledImageArrayDynamicIndexing = false, + .shaderStorageBufferArrayDynamicIndexing = false, + .shaderStorageImageArrayDynamicIndexing = false, + .shaderClipDistance = false, + .shaderCullDistance = false, + .shaderFloat64 = false, + .shaderInt64 = false, + .shaderFloat16 = false, + .shaderInt16 = false, + }; + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceLimits( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceLimits* pLimits) +{ + ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); + const struct brw_device_info *devinfo = physical_device->info; + + anv_finishme("Get correct values for PhysicalDeviceLimits"); + + *pLimits = (VkPhysicalDeviceLimits) { + .maxImageDimension1D = (1 << 14), + .maxImageDimension2D = (1 << 14), + .maxImageDimension3D = (1 << 10), + .maxImageDimensionCube = (1 << 14), + .maxImageArrayLayers = (1 << 10), + .maxTexelBufferSize = (1 << 14), + .maxUniformBufferSize = UINT32_MAX, + .maxStorageBufferSize = UINT32_MAX, + .maxPushConstantsSize = 128, + .maxMemoryAllocationCount = UINT32_MAX, + .bufferImageGranularity = 64, /* A cache line */ + .maxBoundDescriptorSets = MAX_SETS, + .maxDescriptorSets = UINT32_MAX, + .maxPerStageDescriptorSamplers = 64, + .maxPerStageDescriptorUniformBuffers = 64, + .maxPerStageDescriptorStorageBuffers = 64, + .maxPerStageDescriptorSampledImages = 64, + .maxPerStageDescriptorStorageImages = 64, + .maxDescriptorSetSamplers = 256, + .maxDescriptorSetUniformBuffers = 256, + .maxDescriptorSetStorageBuffers = 256, + .maxDescriptorSetSampledImages = 256, + .maxDescriptorSetStorageImages = 256, + .maxVertexInputAttributes = 32, + .maxVertexInputAttributeOffset = 256, + .maxVertexInputBindingStride = 256, + .maxVertexOutputComponents = 32, + .maxTessGenLevel = 0, + .maxTessPatchSize = 0, + .maxTessControlPerVertexInputComponents = 0, + .maxTessControlPerVertexOutputComponents = 0, + .maxTessControlPerPatchOutputComponents = 0, + .maxTessControlTotalOutputComponents = 0, + .maxTessEvaluationInputComponents = 0, + .maxTessEvaluationOutputComponents = 0, + .maxGeometryShaderInvocations = 6, + .maxGeometryInputComponents = 16, + .maxGeometryOutputComponents = 16, + .maxGeometryOutputVertices = 16, + .maxGeometryTotalOutputComponents = 16, + .maxFragmentInputComponents = 16, + .maxFragmentOutputBuffers = 8, + .maxFragmentDualSourceBuffers = 2, + .maxFragmentCombinedOutputResources = 8, + .maxComputeSharedMemorySize = 1024, + .maxComputeWorkGroupCount = { + 16 * devinfo->max_cs_threads, + 16 * devinfo->max_cs_threads, + 16 * devinfo->max_cs_threads, + }, + .maxComputeWorkGroupInvocations = 16 * devinfo->max_cs_threads, + .maxComputeWorkGroupSize = { + 16 * devinfo->max_cs_threads, + 16 * devinfo->max_cs_threads, + 16 * devinfo->max_cs_threads, + }, + .subPixelPrecisionBits = 4 /* FIXME */, + .subTexelPrecisionBits = 4 /* FIXME */, + .mipmapPrecisionBits = 4 /* FIXME */, + .maxDrawIndexedIndexValue = UINT32_MAX, + .maxDrawIndirectInstanceCount = UINT32_MAX, + .primitiveRestartForPatches = UINT32_MAX, + .maxSamplerLodBias = 16, + .maxSamplerAnisotropy = 16, + .maxViewports = 16, + .maxDynamicViewportStates = UINT32_MAX, + .maxViewportDimensions = { (1 << 14), (1 << 14) }, + .viewportBoundsRange = { -1.0, 1.0 }, /* FIXME */ + .viewportSubPixelBits = 13, /* We take a float? */ + .minMemoryMapAlignment = 64, /* A cache line */ + .minTexelBufferOffsetAlignment = 1, + .minUniformBufferOffsetAlignment = 1, + .minStorageBufferOffsetAlignment = 1, + .minTexelOffset = 0, /* FIXME */ + .maxTexelOffset = 0, /* FIXME */ + .minTexelGatherOffset = 0, /* FIXME */ + .maxTexelGatherOffset = 0, /* FIXME */ + .minInterpolationOffset = 0, /* FIXME */ + .maxInterpolationOffset = 0, /* FIXME */ + .subPixelInterpolationOffsetBits = 0, /* FIXME */ + .maxFramebufferWidth = (1 << 14), + .maxFramebufferHeight = (1 << 14), + .maxFramebufferLayers = (1 << 10), + .maxFramebufferColorSamples = 8, + .maxFramebufferDepthSamples = 8, + .maxFramebufferStencilSamples = 8, + .maxColorAttachments = MAX_RTS, + .maxSampledImageColorSamples = 8, + .maxSampledImageDepthSamples = 8, + .maxSampledImageIntegerSamples = 1, + .maxStorageImageSamples = 1, + .maxSampleMaskWords = 1, + .timestampFrequency = 1000 * 1000 * 1000 / 80, + .maxClipDistances = 0 /* FIXME */, + .maxCullDistances = 0 /* FIXME */, + .maxCombinedClipAndCullDistances = 0 /* FIXME */, + .pointSizeRange = { 0.125, 255.875 }, + .lineWidthRange = { 0.0, 7.9921875 }, + .pointSizeGranularity = (1.0 / 8.0), + .lineWidthGranularity = (1.0 / 128.0), + }; + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties* pProperties) +{ + ANV_FROM_HANDLE(anv_physical_device, pdevice, physicalDevice); + + *pProperties = (VkPhysicalDeviceProperties) { + .apiVersion = 1, + .driverVersion = 1, + .vendorId = 0x8086, + .deviceId = pdevice->chipset_id, + .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, + }; + + strcpy(pProperties->deviceName, pdevice->name); + snprintf((char *)pProperties->pipelineCacheUUID, VK_UUID_LENGTH, + "anv-%s", MESA_GIT_SHA1 + 4); + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceQueueCount( + VkPhysicalDevice physicalDevice, + uint32_t* pCount) +{ + *pCount = 1; + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceQueueProperties( + VkPhysicalDevice physicalDevice, + uint32_t count, + VkPhysicalDeviceQueueProperties* pQueueProperties) +{ + assert(count == 1); + + *pQueueProperties = (VkPhysicalDeviceQueueProperties) { + .queueFlags = VK_QUEUE_GRAPHICS_BIT | + VK_QUEUE_COMPUTE_BIT | + VK_QUEUE_DMA_BIT, + .queueCount = 1, + .supportsTimestamps = true, + }; + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties* pMemoryProperties) +{ + ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); + + size_t aperture_size; + size_t heap_size; + + if (anv_gem_get_aperture(physical_device, &aperture_size) == -1) + return vk_error(VK_ERROR_UNAVAILABLE); + + /* Reserve some wiggle room for the driver by exposing only 75% of the + * aperture to the heap. + */ + heap_size = 3 * aperture_size / 4; + + /* The property flags below are valid only for llc platforms. */ + pMemoryProperties->memoryTypeCount = 1; + pMemoryProperties->memoryTypes[0] = (VkMemoryType) { + .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .heapIndex = 1, + }; + + pMemoryProperties->memoryHeapCount = 1; + pMemoryProperties->memoryHeaps[0] = (VkMemoryHeap) { + .size = heap_size, + .flags = VK_MEMORY_HEAP_HOST_LOCAL, + }; + + return VK_SUCCESS; +} + +PFN_vkVoidFunction anv_GetInstanceProcAddr( + VkInstance instance, + const char* pName) +{ + return anv_lookup_entrypoint(pName); +} + +PFN_vkVoidFunction anv_GetDeviceProcAddr( + VkDevice device, + 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; + } + } +} + +static VkResult +anv_queue_init(struct anv_device *device, struct anv_queue *queue) +{ + queue->device = device; + queue->pool = &device->surface_state_pool; + + queue->completed_serial = anv_state_pool_alloc(queue->pool, 4, 4); + if (queue->completed_serial.map == NULL) + return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); + + *(uint32_t *)queue->completed_serial.map = 0; + queue->next_serial = 1; + + return VK_SUCCESS; +} + +static void +anv_queue_finish(struct anv_queue *queue) +{ +#ifdef HAVE_VALGRIND + /* This gets torn down with the device so we only need to do this if + * valgrind is present. + */ + anv_state_pool_free(queue->pool, queue->completed_serial); +#endif +} + +static void +anv_device_init_border_colors(struct anv_device *device) +{ + static const VkClearColorValue border_colors[] = { + [VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK] = { .f32 = { 0.0, 0.0, 0.0, 0.0 } }, + [VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK] = { .f32 = { 0.0, 0.0, 0.0, 1.0 } }, + [VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE] = { .f32 = { 1.0, 1.0, 1.0, 1.0 } }, + [VK_BORDER_COLOR_INT_TRANSPARENT_BLACK] = { .u32 = { 0, 0, 0, 0 } }, + [VK_BORDER_COLOR_INT_OPAQUE_BLACK] = { .u32 = { 0, 0, 0, 1 } }, + [VK_BORDER_COLOR_INT_OPAQUE_WHITE] = { .u32 = { 1, 1, 1, 1 } }, + }; + + device->border_colors = + anv_state_pool_alloc(&device->dynamic_state_pool, + sizeof(border_colors), 32); + memcpy(device->border_colors.map, border_colors, sizeof(border_colors)); +} + +static const uint32_t BATCH_SIZE = 8192; + +VkResult anv_CreateDevice( + VkPhysicalDevice physicalDevice, + const VkDeviceCreateInfo* pCreateInfo, + VkDevice* pDevice) +{ + ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); + struct anv_instance *instance = physical_device->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 = physical_device->no_hw; + parse_debug_flags(device); + + device->instance = physical_device->instance; + + /* XXX(chadv): Can we dup() physicalDevice->fd here? */ + device->fd = open(physical_device->path, 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_bo_pool_init(&device->batch_bo_pool, device, BATCH_SIZE); + + anv_block_pool_init(&device->dynamic_state_block_pool, device, 2048); + + anv_state_pool_init(&device->dynamic_state_pool, + &device->dynamic_state_block_pool); + + anv_block_pool_init(&device->instruction_block_pool, device, 2048); + anv_block_pool_init(&device->surface_state_block_pool, device, 2048); + + anv_state_pool_init(&device->surface_state_pool, + &device->surface_state_block_pool); + + anv_block_pool_init(&device->scratch_block_pool, device, 0x10000); + + device->info = *physical_device->info; + + device->compiler = anv_compiler_create(device); + device->aub_writer = NULL; + + pthread_mutex_init(&device->mutex, NULL); + + anv_queue_init(device, &device->queue); + + anv_device_init_meta(device); + + anv_device_init_border_colors(device); + + *pDevice = anv_device_to_handle(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) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + anv_compiler_destroy(device->compiler); + + anv_queue_finish(&device->queue); + + anv_device_finish_meta(device); + +#ifdef HAVE_VALGRIND + /* We only need to free these to prevent valgrind errors. The backing + * BO will go away in a couple of lines so we don't actually leak. + */ + anv_state_pool_free(&device->dynamic_state_pool, device->border_colors); +#endif + + anv_bo_pool_finish(&device->batch_bo_pool); + 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; +} + +static const VkExtensionProperties global_extensions[] = { + { + .extName = "VK_WSI_LunarG", + .specVersion = 3 + } +}; + +VkResult anv_GetGlobalExtensionProperties( + const char* pLayerName, + uint32_t* pCount, + VkExtensionProperties* pProperties) +{ + if (pProperties == NULL) { + *pCount = ARRAY_SIZE(global_extensions); + return VK_SUCCESS; + } + + assert(*pCount < ARRAY_SIZE(global_extensions)); + + *pCount = ARRAY_SIZE(global_extensions); + memcpy(pProperties, global_extensions, sizeof(global_extensions)); + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceExtensionProperties( + VkPhysicalDevice physicalDevice, + const char* pLayerName, + uint32_t* pCount, + VkExtensionProperties* pProperties) +{ + if (pProperties == NULL) { + *pCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return vk_error(VK_ERROR_INVALID_EXTENSION); +} + +VkResult anv_GetGlobalLayerProperties( + uint32_t* pCount, + VkLayerProperties* pProperties) +{ + if (pProperties == NULL) { + *pCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return vk_error(VK_ERROR_INVALID_LAYER); +} + +VkResult anv_GetPhysicalDeviceLayerProperties( + VkPhysicalDevice physicalDevice, + uint32_t* pCount, + VkLayerProperties* pProperties) +{ + if (pProperties == NULL) { + *pCount = 0; + return VK_SUCCESS; + } + + /* None supported at this time */ + return vk_error(VK_ERROR_INVALID_LAYER); +} + +VkResult anv_GetDeviceQueue( + VkDevice _device, + uint32_t queueNodeIndex, + uint32_t queueIndex, + VkQueue* pQueue) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + assert(queueIndex == 0); + + *pQueue = anv_queue_to_handle(&device->queue); + + return VK_SUCCESS; +} + +VkResult anv_QueueSubmit( + VkQueue _queue, + uint32_t cmdBufferCount, + const VkCmdBuffer* pCmdBuffers, + VkFence _fence) +{ + ANV_FROM_HANDLE(anv_queue, queue, _queue); + ANV_FROM_HANDLE(anv_fence, fence, _fence); + struct anv_device *device = queue->device; + int ret; + + for (uint32_t i = 0; i < cmdBufferCount; i++) { + ANV_FROM_HANDLE(anv_cmd_buffer, 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->exec2_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_QueueWaitIdle( + VkQueue _queue) +{ + ANV_FROM_HANDLE(anv_queue, queue, _queue); + + return vkDeviceWaitIdle(anv_device_to_handle(queue->device)); +} + +VkResult anv_DeviceWaitIdle( + VkDevice _device) +{ + ANV_FROM_HANDLE(anv_device, 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.start = batch.next = state.map; + batch.end = state.map + 32; + 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) +{ + if (mem == NULL) + return; + + 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) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_device_memory *mem; + VkResult result; + + assert(pAllocInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO); + + if (pAllocInfo->memoryTypeIndex != 0) { + /* We support exactly one memory heap. */ + return vk_error(VK_ERROR_INVALID_VALUE); + } + + /* FINISHME: Fail if allocation request exceeds heap size. */ + + 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 = anv_device_memory_to_handle(mem); + + return VK_SUCCESS; + + fail: + anv_device_free(device, mem); + + return result; +} + +VkResult anv_FreeMemory( + VkDevice _device, + VkDeviceMemory _mem) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_device_memory, mem, _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_MapMemory( + VkDevice _device, + VkDeviceMemory _mem, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_device_memory, mem, _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) +{ + ANV_FROM_HANDLE(anv_device_memory, mem, _mem); + + anv_gem_munmap(mem->map, mem->map_size); + + return VK_SUCCESS; +} + +VkResult anv_FlushMappedMemoryRanges( + VkDevice device, + uint32_t memRangeCount, + const VkMappedMemoryRange* pMemRanges) +{ + /* clflush here for !llc platforms */ + + return VK_SUCCESS; +} + +VkResult anv_InvalidateMappedMemoryRanges( + VkDevice device, + uint32_t memRangeCount, + const VkMappedMemoryRange* pMemRanges) +{ + return anv_FlushMappedMemoryRanges(device, memRangeCount, pMemRanges); +} + +VkResult anv_GetBufferMemoryRequirements( + VkDevice device, + VkBuffer _buffer, + VkMemoryRequirements* pMemoryRequirements) +{ + ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); + + /* The Vulkan spec (git aaed022) says: + * + * memoryTypeBits is a bitfield and contains one bit set for every + * supported memory type for the resource. The bit `1<memoryTypeBits = 1; + + pMemoryRequirements->size = buffer->size; + pMemoryRequirements->alignment = 16; + + return VK_SUCCESS; +} + +VkResult anv_GetImageMemoryRequirements( + VkDevice device, + VkImage _image, + VkMemoryRequirements* pMemoryRequirements) +{ + ANV_FROM_HANDLE(anv_image, image, _image); + + /* The Vulkan spec (git aaed022) says: + * + * memoryTypeBits is a bitfield and contains one bit set for every + * supported memory type for the resource. The bit `1<memoryTypeBits = 1; + + pMemoryRequirements->size = image->size; + pMemoryRequirements->alignment = image->alignment; + + return VK_SUCCESS; +} + +VkResult anv_GetImageSparseMemoryRequirements( + VkDevice device, + VkImage image, + uint32_t* pNumRequirements, + VkSparseImageMemoryRequirements* pSparseMemoryRequirements) +{ + return vk_error(VK_UNSUPPORTED); +} + +VkResult anv_GetDeviceMemoryCommitment( + VkDevice device, + VkDeviceMemory memory, + VkDeviceSize* pCommittedMemoryInBytes) +{ + *pCommittedMemoryInBytes = 0; + stub_return(VK_SUCCESS); +} + +VkResult anv_BindBufferMemory( + VkDevice device, + VkBuffer _buffer, + VkDeviceMemory _mem, + VkDeviceSize memOffset) +{ + ANV_FROM_HANDLE(anv_device_memory, mem, _mem); + ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); + + buffer->bo = &mem->bo; + buffer->offset = memOffset; + + return VK_SUCCESS; +} + +VkResult anv_BindImageMemory( + VkDevice device, + VkImage _image, + VkDeviceMemory _mem, + VkDeviceSize memOffset) +{ + ANV_FROM_HANDLE(anv_device_memory, mem, _mem); + ANV_FROM_HANDLE(anv_image, image, _image); + + image->bo = &mem->bo; + image->offset = memOffset; + + return VK_SUCCESS; +} + +VkResult anv_QueueBindSparseBufferMemory( + VkQueue queue, + VkBuffer buffer, + uint32_t numBindings, + const VkSparseMemoryBindInfo* pBindInfo) +{ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_QueueBindSparseImageOpaqueMemory( + VkQueue queue, + VkImage image, + uint32_t numBindings, + const VkSparseMemoryBindInfo* pBindInfo) +{ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_QueueBindSparseImageMemory( + VkQueue queue, + VkImage image, + uint32_t numBindings, + const VkSparseImageMemoryBindInfo* pBindInfo) +{ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_CreateFence( + VkDevice _device, + const VkFenceCreateInfo* pCreateInfo, + VkFence* pFence) +{ + ANV_FROM_HANDLE(anv_device, 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 = batch.start = fence->bo.map; + batch.end = fence->bo.map + fence->bo.size; + 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 = anv_fence_to_handle(fence); + + return VK_SUCCESS; + + fail: + anv_device_free(device, fence); + + return result; +} + +VkResult anv_DestroyFence( + VkDevice _device, + VkFence _fence) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_fence, fence, _fence); + + 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; +} + +VkResult anv_ResetFences( + VkDevice _device, + uint32_t fenceCount, + const VkFence* pFences) +{ + for (uint32_t i = 0; i < fenceCount; i++) { + ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); + fence->ready = false; + } + + return VK_SUCCESS; +} + +VkResult anv_GetFenceStatus( + VkDevice _device, + VkFence _fence) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_fence, 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, + VkBool32 waitAll, + uint64_t timeout) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + int64_t t = timeout; + int ret; + + /* FIXME: handle !waitAll */ + + for (uint32_t i = 0; i < fenceCount; i++) { + ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); + ret = anv_gem_wait(device, fence->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_DestroySemaphore( + VkDevice device, + VkSemaphore semaphore) +{ + 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_DestroyEvent( + VkDevice device, + VkEvent event) +{ + 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); +} + +// Buffer functions + +VkResult anv_CreateBuffer( + VkDevice _device, + const VkBufferCreateInfo* pCreateInfo, + VkBuffer* pBuffer) +{ + ANV_FROM_HANDLE(anv_device, 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 = anv_buffer_to_handle(buffer); + + return VK_SUCCESS; +} + +VkResult anv_DestroyBuffer( + VkDevice _device, + VkBuffer _buffer) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); + + anv_device_free(device, buffer); + + return VK_SUCCESS; +} + +// Buffer view functions + +void +anv_fill_buffer_surface_state(void *state, VkFormat format, + uint32_t offset, uint32_t range) +{ + const struct anv_format *info; + + info = anv_format_for_vk_format(format); + /* This assumes RGBA float format. */ + uint32_t stride = 4; + uint32_t num_elements = range / stride; + + struct GEN8_RENDER_SURFACE_STATE surface_state = { + .SurfaceType = SURFTYPE_BUFFER, + .SurfaceArray = false, + .SurfaceFormat = info->surface_format, + .SurfaceVerticalAlignment = VALIGN4, + .SurfaceHorizontalAlignment = HALIGN4, + .TileMode = LINEAR, + .VerticalLineStride = 0, + .VerticalLineStrideOffset = 0, + .SamplerL2BypassModeDisable = true, + .RenderCacheReadWriteMode = WriteOnlyCache, + .MemoryObjectControlState = GEN8_MOCS, + .BaseMipLevel = 0.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.0, + /* FIXME: We assume that the image must be bound at this time. */ + .SurfaceBaseAddress = { NULL, offset }, + }; + + GEN8_RENDER_SURFACE_STATE_pack(NULL, state, &surface_state); +} + +VkResult anv_CreateBufferView( + VkDevice _device, + const VkBufferViewCreateInfo* pCreateInfo, + VkBufferView* pView) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_buffer, buffer, pCreateInfo->buffer); + struct anv_buffer_view *bview; + struct anv_surface_view *view; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO); + + bview = anv_device_alloc(device, sizeof(*view), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (bview == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + view = &bview->view; + 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; + view->range = pCreateInfo->range; + + anv_fill_buffer_surface_state(view->surface_state.map, + pCreateInfo->format, + view->offset, pCreateInfo->range); + + *pView = anv_buffer_view_to_handle(bview); + + return VK_SUCCESS; +} + +VkResult anv_DestroyBufferView( + VkDevice _device, + VkBufferView _bview) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_buffer_view, bview, _bview); + + anv_surface_view_fini(device, &bview->view); + anv_device_free(device, bview); + + return VK_SUCCESS; +} + +// Sampler functions + +VkResult anv_CreateSampler( + VkDevice _device, + const VkSamplerCreateInfo* pCreateInfo, + VkSampler* pSampler) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_sampler *sampler; + uint32_t mag_filter, min_filter, max_anisotropy; + + 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 > 1) { + mag_filter = MAPFILTER_ANISOTROPIC; + min_filter = MAPFILTER_ANISOTROPIC; + max_anisotropy = (pCreateInfo->maxAnisotropy - 2) / 2; + } else { + mag_filter = vk_to_gen_tex_filter[pCreateInfo->magFilter]; + min_filter = vk_to_gen_tex_filter[pCreateInfo->minFilter]; + max_anisotropy = RATIO21; + } + + struct GEN8_SAMPLER_STATE sampler_state = { + .SamplerDisable = false, + .TextureBorderColorMode = DX10OGL, + .LODPreClampMode = 0, + .BaseMipLevel = 0.0, + .MipModeFilter = vk_to_gen_mipmap_mode[pCreateInfo->mipMode], + .MagModeFilter = mag_filter, + .MinModeFilter = min_filter, + .TextureLODBias = pCreateInfo->mipLodBias * 256, + .AnisotropicAlgorithm = EWAApproximation, + .MinLOD = pCreateInfo->minLod, + .MaxLOD = pCreateInfo->maxLod, + .ChromaKeyEnable = 0, + .ChromaKeyIndex = 0, + .ChromaKeyMode = 0, + .ShadowFunction = vk_to_gen_compare_op[pCreateInfo->compareOp], + .CubeSurfaceControlMode = 0, + + .IndirectStatePointer = + device->border_colors.offset + + pCreateInfo->borderColor * sizeof(float) * 4, + + .LODClampMagnificationMode = MIPNONE, + .MaximumAnisotropy = max_anisotropy, + .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 = anv_sampler_to_handle(sampler); + + return VK_SUCCESS; +} + +VkResult anv_DestroySampler( + VkDevice _device, + VkSampler _sampler) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_sampler, sampler, _sampler); + + anv_device_free(device, sampler); + + return VK_SUCCESS; +} + +// Descriptor set functions + +VkResult anv_CreateDescriptorSetLayout( + VkDevice _device, + const VkDescriptorSetLayoutCreateInfo* pCreateInfo, + VkDescriptorSetLayout* pSetLayout) +{ + ANV_FROM_HANDLE(anv_device, 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_SHADER_STAGE_NUM] = { 0, }; + uint32_t surface_count[VK_SHADER_STAGE_NUM] = { 0, }; + uint32_t num_dynamic_buffers = 0; + uint32_t count = 0; + uint32_t stages = 0; + uint32_t s; + + for (uint32_t i = 0; i < pCreateInfo->count; i++) { + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) + sampler_count[s] += pCreateInfo->pBinding[i].arraySize; + break; + default: + break; + } + + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + 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: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) + surface_count[s] += pCreateInfo->pBinding[i].arraySize; + break; + default: + break; + } + + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + num_dynamic_buffers += pCreateInfo->pBinding[i].arraySize; + break; + default: + break; + } + + stages |= pCreateInfo->pBinding[i].stageFlags; + count += pCreateInfo->pBinding[i].arraySize; + } + + uint32_t sampler_total = 0; + uint32_t surface_total = 0; + for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { + sampler_total += sampler_count[s]; + surface_total += surface_count[s]; + } + + size_t size = sizeof(*set_layout) + + (sampler_total + surface_total) * sizeof(set_layout->entries[0]); + set_layout = anv_device_alloc(device, size, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (!set_layout) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + set_layout->num_dynamic_buffers = num_dynamic_buffers; + set_layout->count = count; + set_layout->shader_stages = stages; + + struct anv_descriptor_slot *p = set_layout->entries; + struct anv_descriptor_slot *sampler[VK_SHADER_STAGE_NUM]; + struct anv_descriptor_slot *surface[VK_SHADER_STAGE_NUM]; + for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; 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; + int8_t dynamic_slot = 0; + bool is_dynamic; + for (uint32_t i = 0; i < pCreateInfo->count; i++) { + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) + for (uint32_t j = 0; j < pCreateInfo->pBinding[i].arraySize; j++) { + sampler[s]->index = descriptor + j; + sampler[s]->dynamic_slot = -1; + sampler[s]++; + } + break; + default: + break; + } + + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + is_dynamic = true; + break; + default: + is_dynamic = false; + break; + } + + switch (pCreateInfo->pBinding[i].descriptorType) { + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + 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: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) + for (uint32_t j = 0; j < pCreateInfo->pBinding[i].arraySize; j++) { + surface[s]->index = descriptor + j; + if (is_dynamic) + surface[s]->dynamic_slot = dynamic_slot + j; + else + surface[s]->dynamic_slot = -1; + surface[s]++; + } + break; + default: + break; + } + + if (is_dynamic) + dynamic_slot += pCreateInfo->pBinding[i].arraySize; + + descriptor += pCreateInfo->pBinding[i].arraySize; + } + + *pSetLayout = anv_descriptor_set_layout_to_handle(set_layout); + + return VK_SUCCESS; +} + +VkResult anv_DestroyDescriptorSetLayout( + VkDevice _device, + VkDescriptorSetLayout _set_layout) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout, _set_layout); + + anv_device_free(device, set_layout); + + return VK_SUCCESS; +} + +VkResult anv_CreateDescriptorPool( + VkDevice device, + VkDescriptorPoolUsage poolUsage, + uint32_t maxSets, + const VkDescriptorPoolCreateInfo* pCreateInfo, + VkDescriptorPool* pDescriptorPool) +{ + anv_finishme("VkDescriptorPool is a stub"); + pDescriptorPool->handle = 1; + return VK_SUCCESS; +} + +VkResult anv_DestroyDescriptorPool( + VkDevice _device, + VkDescriptorPool _pool) +{ + anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets"); + return VK_SUCCESS; +} + +VkResult anv_ResetDescriptorPool( + VkDevice device, + VkDescriptorPool descriptorPool) +{ + anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets"); + return VK_SUCCESS; +} + +VkResult +anv_descriptor_set_create(struct anv_device *device, + const struct anv_descriptor_set_layout *layout, + struct anv_descriptor_set **out_set) +{ + struct anv_descriptor_set *set; + size_t size = sizeof(*set) + layout->count * sizeof(set->descriptors[0]); + + set = anv_device_alloc(device, size, 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (!set) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + /* A descriptor set may not be 100% filled. Clear the set so we can can + * later detect holes in it. + */ + memset(set, 0, size); + + *out_set = set; + + return VK_SUCCESS; +} + +void +anv_descriptor_set_destroy(struct anv_device *device, + struct anv_descriptor_set *set) +{ + anv_device_free(device, set); +} + +VkResult anv_AllocDescriptorSets( + VkDevice _device, + VkDescriptorPool descriptorPool, + VkDescriptorSetUsage setUsage, + uint32_t count, + const VkDescriptorSetLayout* pSetLayouts, + VkDescriptorSet* pDescriptorSets, + uint32_t* pCount) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + VkResult result; + struct anv_descriptor_set *set; + + for (uint32_t i = 0; i < count; i++) { + ANV_FROM_HANDLE(anv_descriptor_set_layout, layout, pSetLayouts[i]); + + result = anv_descriptor_set_create(device, layout, &set); + if (result != VK_SUCCESS) { + *pCount = i; + return result; + } + + pDescriptorSets[i] = anv_descriptor_set_to_handle(set); + } + + *pCount = count; + + return VK_SUCCESS; +} + +VkResult anv_UpdateDescriptorSets( + VkDevice device, + uint32_t writeCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t copyCount, + const VkCopyDescriptorSet* pDescriptorCopies) +{ + for (uint32_t i = 0; i < writeCount; i++) { + const VkWriteDescriptorSet *write = &pDescriptorWrites[i]; + ANV_FROM_HANDLE(anv_descriptor_set, set, write->destSet); + + switch (write->descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + for (uint32_t j = 0; j < write->count; j++) { + set->descriptors[write->destBinding + j].sampler = + anv_sampler_from_handle(write->pDescriptors[j].sampler); + } + + if (write->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) + break; + + /* fallthrough */ + + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + for (uint32_t j = 0; j < write->count; j++) { + ANV_FROM_HANDLE(anv_image_view, iview, + write->pDescriptors[j].imageView); + set->descriptors[write->destBinding + j].view = &iview->view; + } + break; + + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + anv_finishme("texel buffers not implemented"); + break; + + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + anv_finishme("input attachments not implemented"); + break; + + 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 (uint32_t j = 0; j < write->count; j++) { + ANV_FROM_HANDLE(anv_buffer_view, bview, + write->pDescriptors[j].bufferView); + set->descriptors[write->destBinding + j].view = &bview->view; + } + + default: + break; + } + } + + for (uint32_t i = 0; i < copyCount; i++) { + const VkCopyDescriptorSet *copy = &pDescriptorCopies[i]; + ANV_FROM_HANDLE(anv_descriptor_set, src, copy->destSet); + ANV_FROM_HANDLE(anv_descriptor_set, dest, copy->destSet); + for (uint32_t j = 0; j < copy->count; j++) { + dest->descriptors[copy->destBinding + j] = + src->descriptors[copy->srcBinding + j]; + } + } + + return VK_SUCCESS; +} + +// 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 VkDynamicViewportStateCreateInfo* pCreateInfo, + VkDynamicViewportState* pState) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_dynamic_vp_state *state; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_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 VkRect2D *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 = anv_dynamic_vp_state_to_handle(state); + + return VK_SUCCESS; +} + +VkResult anv_DestroyDynamicViewportState( + VkDevice _device, + VkDynamicViewportState _vp_state) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_dynamic_vp_state, vp_state, _vp_state); + + anv_state_pool_free(&device->dynamic_state_pool, vp_state->sf_clip_vp); + anv_state_pool_free(&device->dynamic_state_pool, vp_state->cc_vp); + anv_state_pool_free(&device->dynamic_state_pool, vp_state->scissor); + + anv_device_free(device, vp_state); + + return VK_SUCCESS; +} + +VkResult anv_CreateDynamicRasterState( + VkDevice _device, + const VkDynamicRasterStateCreateInfo* pCreateInfo, + VkDynamicRasterState* pState) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_dynamic_rs_state *state; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_RASTER_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); + + struct GEN8_3DSTATE_SF sf = { + GEN8_3DSTATE_SF_header, + .LineWidth = pCreateInfo->lineWidth, + }; + + GEN8_3DSTATE_SF_pack(NULL, state->state_sf, &sf); + + bool enable_bias = pCreateInfo->depthBias != 0.0f || + pCreateInfo->slopeScaledDepthBias != 0.0f; + struct GEN8_3DSTATE_RASTER raster = { + .GlobalDepthOffsetEnableSolid = enable_bias, + .GlobalDepthOffsetEnableWireframe = enable_bias, + .GlobalDepthOffsetEnablePoint = enable_bias, + .GlobalDepthOffsetConstant = pCreateInfo->depthBias, + .GlobalDepthOffsetScale = pCreateInfo->slopeScaledDepthBias, + .GlobalDepthOffsetClamp = pCreateInfo->depthBiasClamp + }; + + GEN8_3DSTATE_RASTER_pack(NULL, state->state_raster, &raster); + + *pState = anv_dynamic_rs_state_to_handle(state); + + return VK_SUCCESS; +} + +VkResult anv_DestroyDynamicRasterState( + VkDevice _device, + VkDynamicRasterState _rs_state) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_dynamic_rs_state, rs_state, _rs_state); + + anv_device_free(device, rs_state); + + return VK_SUCCESS; +} + +VkResult anv_CreateDynamicColorBlendState( + VkDevice _device, + const VkDynamicColorBlendStateCreateInfo* pCreateInfo, + VkDynamicColorBlendState* pState) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_dynamic_cb_state *state; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_COLOR_BLEND_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); + + struct GEN8_COLOR_CALC_STATE color_calc_state = { + .BlendConstantColorRed = pCreateInfo->blendConst[0], + .BlendConstantColorGreen = pCreateInfo->blendConst[1], + .BlendConstantColorBlue = pCreateInfo->blendConst[2], + .BlendConstantColorAlpha = pCreateInfo->blendConst[3] + }; + + GEN8_COLOR_CALC_STATE_pack(NULL, state->state_color_calc, &color_calc_state); + + *pState = anv_dynamic_cb_state_to_handle(state); + + return VK_SUCCESS; +} + +VkResult anv_DestroyDynamicColorBlendState( + VkDevice _device, + VkDynamicColorBlendState _cb_state) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_dynamic_cb_state, cb_state, _cb_state); + + anv_device_free(device, cb_state); + + return VK_SUCCESS; +} + +VkResult anv_CreateDynamicDepthStencilState( + VkDevice _device, + const VkDynamicDepthStencilStateCreateInfo* pCreateInfo, + VkDynamicDepthStencilState* pState) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_dynamic_ds_state *state; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_STENCIL_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); + + struct GEN8_3DSTATE_WM_DEPTH_STENCIL wm_depth_stencil = { + GEN8_3DSTATE_WM_DEPTH_STENCIL_header, + + /* Is this what we need to do? */ + .StencilBufferWriteEnable = pCreateInfo->stencilWriteMask != 0, + + .StencilTestMask = pCreateInfo->stencilReadMask & 0xff, + .StencilWriteMask = pCreateInfo->stencilWriteMask & 0xff, + + .BackfaceStencilTestMask = pCreateInfo->stencilReadMask & 0xff, + .BackfaceStencilWriteMask = pCreateInfo->stencilWriteMask & 0xff, + }; + + GEN8_3DSTATE_WM_DEPTH_STENCIL_pack(NULL, state->state_wm_depth_stencil, + &wm_depth_stencil); + + struct GEN8_COLOR_CALC_STATE color_calc_state = { + .StencilReferenceValue = pCreateInfo->stencilFrontRef, + .BackFaceStencilReferenceValue = pCreateInfo->stencilBackRef + }; + + GEN8_COLOR_CALC_STATE_pack(NULL, state->state_color_calc, &color_calc_state); + + *pState = anv_dynamic_ds_state_to_handle(state); + + return VK_SUCCESS; +} + +VkResult anv_DestroyDynamicDepthStencilState( + VkDevice _device, + VkDynamicDepthStencilState _ds_state) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_dynamic_ds_state, ds_state, _ds_state); + + anv_device_free(device, ds_state); + + return VK_SUCCESS; +} + +// Command buffer functions + +VkResult anv_CreateCommandPool( + VkDevice device, + const VkCmdPoolCreateInfo* pCreateInfo, + VkCmdPool* pCmdPool) +{ + pCmdPool->handle = 7; + + stub_return(VK_SUCCESS); +} + +VkResult anv_DestroyCommandPool( + VkDevice device, + VkCmdPool cmdPool) +{ + stub_return(VK_SUCCESS); +} + +VkResult anv_ResetCommandPool( + VkDevice device, + VkCmdPool cmdPool, + VkCmdPoolResetFlags flags) +{ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_CreateFramebuffer( + VkDevice _device, + const VkFramebufferCreateInfo* pCreateInfo, + VkFramebuffer* pFramebuffer) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_framebuffer *framebuffer; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); + + size_t size = sizeof(*framebuffer) + + sizeof(struct anv_attachment_view *) * pCreateInfo->attachmentCount; + framebuffer = anv_device_alloc(device, size, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (framebuffer == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + framebuffer->attachment_count = pCreateInfo->attachmentCount; + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + ANV_FROM_HANDLE(anv_attachment_view, view, + pCreateInfo->pAttachments[i].view); + + framebuffer->attachments[i] = view; + } + + framebuffer->width = pCreateInfo->width; + framebuffer->height = pCreateInfo->height; + framebuffer->layers = pCreateInfo->layers; + + anv_CreateDynamicViewportState(anv_device_to_handle(device), + &(VkDynamicViewportStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_STATE_CREATE_INFO, + .viewportAndScissorCount = 1, + .pViewports = (VkViewport[]) { + { + .originX = 0, + .originY = 0, + .width = pCreateInfo->width, + .height = pCreateInfo->height, + .minDepth = 0, + .maxDepth = 1 + }, + }, + .pScissors = (VkRect2D[]) { + { { 0, 0 }, + { pCreateInfo->width, pCreateInfo->height } }, + } + }, + &framebuffer->vp_state); + + *pFramebuffer = anv_framebuffer_to_handle(framebuffer); + + return VK_SUCCESS; +} + +VkResult anv_DestroyFramebuffer( + VkDevice _device, + VkFramebuffer _fb) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_framebuffer, fb, _fb); + + anv_DestroyDynamicViewportState(anv_device_to_handle(device), + fb->vp_state); + anv_device_free(device, fb); + + return VK_SUCCESS; +} + +VkResult anv_CreateRenderPass( + VkDevice _device, + const VkRenderPassCreateInfo* pCreateInfo, + VkRenderPass* pRenderPass) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_render_pass *pass; + size_t size; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); + + size = sizeof(*pass) + + pCreateInfo->subpassCount * sizeof(struct anv_subpass); + 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); + + /* Clear the subpasses along with the parent pass. This required because + * each array member of anv_subpass must be a valid pointer if not NULL. + */ + memset(pass, 0, size); + + pass->attachment_count = pCreateInfo->attachmentCount; + pass->subpass_count = pCreateInfo->subpassCount; + + size = pCreateInfo->attachmentCount * sizeof(*pass->attachments); + pass->attachments = anv_device_alloc(device, size, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { + pass->attachments[i].format = pCreateInfo->pAttachments[i].format; + pass->attachments[i].samples = pCreateInfo->pAttachments[i].samples; + pass->attachments[i].load_op = pCreateInfo->pAttachments[i].loadOp; + pass->attachments[i].stencil_load_op = pCreateInfo->pAttachments[i].stencilLoadOp; + // pass->attachments[i].store_op = pCreateInfo->pAttachments[i].storeOp; + // pass->attachments[i].stencil_store_op = pCreateInfo->pAttachments[i].stencilStoreOp; + } + + for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { + const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i]; + struct anv_subpass *subpass = &pass->subpasses[i]; + + subpass->input_count = desc->inputCount; + subpass->color_count = desc->colorCount; + + if (desc->inputCount > 0) { + subpass->input_attachments = + anv_device_alloc(device, desc->inputCount * sizeof(uint32_t), + 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + + for (uint32_t j = 0; j < desc->inputCount; j++) { + subpass->input_attachments[j] + = desc->inputAttachments[j].attachment; + } + } + + if (desc->colorCount > 0) { + subpass->color_attachments = + anv_device_alloc(device, desc->colorCount * sizeof(uint32_t), + 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + + for (uint32_t j = 0; j < desc->colorCount; j++) { + subpass->color_attachments[j] + = desc->colorAttachments[j].attachment; + } + } + + if (desc->resolveAttachments) { + subpass->resolve_attachments = + anv_device_alloc(device, desc->colorCount * sizeof(uint32_t), + 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + + for (uint32_t j = 0; j < desc->colorCount; j++) { + subpass->resolve_attachments[j] + = desc->resolveAttachments[j].attachment; + } + } + + subpass->depth_stencil_attachment = desc->depthStencilAttachment.attachment; + } + + *pRenderPass = anv_render_pass_to_handle(pass); + + return VK_SUCCESS; +} + +VkResult anv_DestroyRenderPass( + VkDevice _device, + VkRenderPass _pass) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_render_pass, pass, _pass); + + anv_device_free(device, pass->attachments); + + for (uint32_t i = 0; i < pass->subpass_count; i++) { + /* In VkSubpassCreateInfo, each of the attachment arrays may be null. + * Don't free the null arrays. + */ + struct anv_subpass *subpass = &pass->subpasses[i]; + + anv_device_free(device, subpass->input_attachments); + anv_device_free(device, subpass->color_attachments); + anv_device_free(device, subpass->resolve_attachments); + } + + anv_device_free(device, pass); + + return VK_SUCCESS; +} + +VkResult anv_GetRenderAreaGranularity( + VkDevice device, + VkRenderPass renderPass, + VkExtent2D* pGranularity) +{ + *pGranularity = (VkExtent2D) { 1, 1 }; + + return VK_SUCCESS; +} + +void vkCmdDbgMarkerBegin( + VkCmdBuffer cmdBuffer, + const char* pMarker) + __attribute__ ((visibility ("default"))); + +void vkCmdDbgMarkerEnd( + VkCmdBuffer cmdBuffer) + __attribute__ ((visibility ("default"))); + +void vkCmdDbgMarkerBegin( + VkCmdBuffer cmdBuffer, + const char* pMarker) +{ +} + +void vkCmdDbgMarkerEnd( + VkCmdBuffer cmdBuffer) +{ +} diff --git a/src/vulkan/anv_entrypoints_gen.py b/src/vulkan/anv_entrypoints_gen.py new file mode 100644 index 00000000000..96c4884d158 --- /dev/null +++ b/src/vulkan/anv_entrypoints_gen.py @@ -0,0 +1,269 @@ +# coding=utf-8 +# +# 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. +# + +import fileinput, re, sys + +# Each function typedef in the vulkan.h header is all on one line and matches +# this regepx. We hope that won't change. + +p = re.compile('typedef ([^ ]*) *\(VKAPI \*PFN_vk([^(]*)\)(.*);') + +entrypoints = [] + +# We generate a static hash table for entry point lookup +# (vkGetProcAddress). We use a linear congruential generator for our hash +# function and a power-of-two size table. The prime numbers are determined +# experimentally. + +none = 0xffff +hash_size = 256 +u32_mask = 2**32 - 1 +hash_mask = hash_size - 1 + +prime_factor = 5024183 +prime_step = 19 + +def hash(name): + h = 0; + for c in name: + h = (h * prime_factor + ord(c)) & u32_mask + + return h + +opt_header = False +opt_code = False + +if (sys.argv[1] == "header"): + opt_header = True + sys.argv.pop() +elif (sys.argv[1] == "code"): + opt_code = True + sys.argv.pop() + +# Parse the entry points in the header + +i = 0 +for line in fileinput.input(): + m = p.match(line) + if (m): + if m.group(2) == 'VoidFunction': + continue + fullname = "vk" + m.group(2) + h = hash(fullname) + entrypoints.append((m.group(1), m.group(2), m.group(3), i, h)) + i = i + 1 + +# For outputting entrypoints.h we generate a anv_EntryPoint() prototype +# per entry point. + +if opt_header: + for type, name, args, num, h in entrypoints: + print "%s anv_%s%s;" % (type, name, args) + print "%s anv_validate_%s%s;" % (type, name, args) + exit() + + + +print """/* + * 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. + */ + +/* DO NOT EDIT! This is a generated file. */ + +#include "anv_private.h" + +struct anv_entrypoint { + uint32_t name; + uint32_t hash; + void *function; + void *validate; +}; + +/* We use a big string constant to avoid lots of reloctions from the entry + * point table to lots of little strings. The entries in the entry point table + * store the index into this big string. + */ + +static const char strings[] =""" + +offsets = [] +i = 0; +for type, name, args, num, h in entrypoints: + print " \"vk%s\\0\"" % name + offsets.append(i) + i += 2 + len(name) + 1 +print """ ; + +/* Weak aliases for all potential validate functions. These will resolve to + * NULL if they're not defined, which lets the resolve_entrypoint() function + * either pick a validate wrapper if available or just plug in the actual + * entry point. + */ +""" + +for type, name, args, num, h in entrypoints: + print "%s anv_validate_%s%s __attribute__ ((weak));" % (type, name, args) + +# Now generate the table of all entry points and their validation functions + +print "\nstatic const struct anv_entrypoint entrypoints[] = {" +for type, name, args, num, h in entrypoints: + print " { %5d, 0x%08x, anv_%s, anv_validate_%s }," % (offsets[num], h, name, name) +print "};\n" + +print """ +#ifdef DEBUG +static bool enable_validate = true; +#else +static bool enable_validate = false; +#endif + +/* We can't use symbols that need resolving (like, oh, getenv) in the resolve + * function. This means that we have to determine whether or not to use the + * validation layer sometime before that. The constructor function attribute asks + * the dynamic linker to invoke determine_validate() at dlopen() time which + * works. + */ +static void __attribute__ ((constructor)) +determine_validate(void) +{ + const char *s = getenv("ANV_VALIDATE"); + + if (s) + enable_validate = atoi(s); +} + +static void * __attribute__ ((noinline)) +resolve_entrypoint(uint32_t index) +{ + if (enable_validate && entrypoints[index].validate) + return entrypoints[index].validate; + + return entrypoints[index].function; +} +""" + +# Now output ifuncs and their resolve helpers for all entry points. The +# resolve helper calls resolve_entrypoint() with the entry point index, which +# lets the resolver look it up in the table. + +for type, name, args, num, h in entrypoints: + print "static void *resolve_%s(void) { return resolve_entrypoint(%d); }" % (name, num) + print "%s vk%s%s\n __attribute__ ((ifunc (\"resolve_%s\"), visibility (\"default\")));\n" % (type, name, args, name) + + +# Now generate the hash table used for entry point look up. This is a +# uint16_t table of entry point indices. We use 0xffff to indicate an entry +# in the hash table is empty. + +map = [none for f in xrange(hash_size)] +collisions = [0 for f in xrange(10)] +for type, name, args, num, h in entrypoints: + level = 0 + while map[h & hash_mask] != none: + h = h + prime_step + level = level + 1 + if level > 9: + collisions[9] += 1 + else: + collisions[level] += 1 + map[h & hash_mask] = num + +print "/* Hash table stats:" +print " * size %d entries" % hash_size +print " * collisions entries" +for i in xrange(10): + if (i == 9): + plus = "+" + else: + plus = " " + + print " * %2d%s %4d" % (i, plus, collisions[i]) +print " */\n" + +print "#define none 0x%04x\n" % none + +print "static const uint16_t map[] = {" +for i in xrange(0, hash_size, 8): + print " ", + for j in xrange(i, i + 8): + if map[j] & 0xffff == 0xffff: + print " none,", + else: + print "0x%04x," % (map[j] & 0xffff), + print + +print "};" + +# Finally we generate the hash table lookup function. The hash function and +# linear probing algorithm matches the hash table generated above. + +print """ +void * +anv_lookup_entrypoint(const char *name) +{ + static const uint32_t prime_factor = %d; + static const uint32_t prime_step = %d; + const struct anv_entrypoint *e; + uint32_t hash, h, i; + const char *p; + + hash = 0; + for (p = name; *p; p++) + hash = hash * prime_factor + *p; + + h = hash; + do { + i = map[h & %d]; + if (i == none) + return NULL; + e = &entrypoints[i]; + h += prime_step; + } while (e->hash != hash); + + if (strcmp(name, strings + e->name) != 0) + return NULL; + + return resolve_entrypoint(i); +} +""" % (prime_factor, prime_step, hash_mask) diff --git a/src/vulkan/anv_formats.c b/src/vulkan/anv_formats.c new file mode 100644 index 00000000000..3cbcff5730f --- /dev/null +++ b/src/vulkan/anv_formats.c @@ -0,0 +1,334 @@ +/* + * 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 "anv_private.h" + +#define UNSUPPORTED 0xffff + +#define fmt(__vk_fmt, ...) \ + [__vk_fmt] = { .name = #__vk_fmt, __VA_ARGS__ } + +static const struct anv_format anv_formats[] = { + fmt(VK_FORMAT_UNDEFINED, RAW, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R4G4_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_R4G4_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_R4G4B4A4_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_R4G4B4A4_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_R5G6B5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_R5G6B5_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_R5G5B5A1_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_R5G5B5A1_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_R8_UNORM, R8_UNORM, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R8_SNORM, R8_SNORM, .cpp = 1, .num_channels = 1,), + fmt(VK_FORMAT_R8_USCALED, R8_USCALED, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R8_SSCALED, R8_SSCALED, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R8_UINT, R8_UINT, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R8_SINT, R8_SINT, .cpp = 1, .num_channels = 1), + fmt(VK_FORMAT_R8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_R8G8_UNORM, R8G8_UNORM, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_SNORM, R8G8_SNORM, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_USCALED, R8G8_USCALED, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_SSCALED, R8G8_SSCALED, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_UINT, R8G8_UINT, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_SINT, R8G8_SINT, .cpp = 2, .num_channels = 2), + fmt(VK_FORMAT_R8G8_SRGB, UNSUPPORTED), /* L8A8_UNORM_SRGB */ + fmt(VK_FORMAT_R8G8B8_UNORM, R8G8B8X8_UNORM, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_SNORM, R8G8B8_SNORM, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_USCALED, R8G8B8_USCALED, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_SSCALED, R8G8B8_SSCALED, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_UINT, R8G8B8_UINT, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_SINT, R8G8B8_SINT, .cpp = 3, .num_channels = 3), + fmt(VK_FORMAT_R8G8B8_SRGB, UNSUPPORTED), /* B8G8R8A8_UNORM_SRGB */ + fmt(VK_FORMAT_R8G8B8A8_UNORM, R8G8B8A8_UNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_SNORM, R8G8B8A8_SNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_USCALED, R8G8B8A8_USCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_SSCALED, R8G8B8A8_SSCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_UINT, R8G8B8A8_UINT, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_SINT, R8G8B8A8_SINT, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R8G8B8A8_SRGB, R8G8B8A8_UNORM_SRGB, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_UNORM, R10G10B10A2_UNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_SNORM, R10G10B10A2_SNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_USCALED, R10G10B10A2_USCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_SSCALED, R10G10B10A2_SSCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_UINT, R10G10B10A2_UINT, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R10G10B10A2_SINT, R10G10B10A2_SINT, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_R16_UNORM, R16_UNORM, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_SNORM, R16_SNORM, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_USCALED, R16_USCALED, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_SSCALED, R16_SSCALED, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_UINT, R16_UINT, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_SINT, R16_SINT, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16_SFLOAT, R16_FLOAT, .cpp = 2, .num_channels = 1), + fmt(VK_FORMAT_R16G16_UNORM, R16G16_UNORM, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_SNORM, R16G16_SNORM, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_USCALED, R16G16_USCALED, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_SSCALED, R16G16_SSCALED, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_UINT, R16G16_UINT, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_SINT, R16G16_SINT, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16_SFLOAT, R16G16_FLOAT, .cpp = 4, .num_channels = 2), + fmt(VK_FORMAT_R16G16B16_UNORM, R16G16B16_UNORM, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_SNORM, R16G16B16_SNORM, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_USCALED, R16G16B16_USCALED, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_SSCALED, R16G16B16_SSCALED, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_UINT, R16G16B16_UINT, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_SINT, R16G16B16_SINT, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16_SFLOAT, R16G16B16_FLOAT, .cpp = 6, .num_channels = 3), + fmt(VK_FORMAT_R16G16B16A16_UNORM, R16G16B16A16_UNORM, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_SNORM, R16G16B16A16_SNORM, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_USCALED, R16G16B16A16_USCALED, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_SSCALED, R16G16B16A16_SSCALED, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_UINT, R16G16B16A16_UINT, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_SINT, R16G16B16A16_SINT, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R16G16B16A16_SFLOAT, R16G16B16A16_FLOAT, .cpp = 8, .num_channels = 4), + fmt(VK_FORMAT_R32_UINT, R32_UINT, .cpp = 4, .num_channels = 1,), + fmt(VK_FORMAT_R32_SINT, R32_SINT, .cpp = 4, .num_channels = 1,), + fmt(VK_FORMAT_R32_SFLOAT, R32_FLOAT, .cpp = 4, .num_channels = 1,), + fmt(VK_FORMAT_R32G32_UINT, R32G32_UINT, .cpp = 8, .num_channels = 2,), + fmt(VK_FORMAT_R32G32_SINT, R32G32_SINT, .cpp = 8, .num_channels = 2,), + fmt(VK_FORMAT_R32G32_SFLOAT, R32G32_FLOAT, .cpp = 8, .num_channels = 2,), + fmt(VK_FORMAT_R32G32B32_UINT, R32G32B32_UINT, .cpp = 12, .num_channels = 3,), + fmt(VK_FORMAT_R32G32B32_SINT, R32G32B32_SINT, .cpp = 12, .num_channels = 3,), + fmt(VK_FORMAT_R32G32B32_SFLOAT, R32G32B32_FLOAT, .cpp = 12, .num_channels = 3,), + fmt(VK_FORMAT_R32G32B32A32_UINT, R32G32B32A32_UINT, .cpp = 16, .num_channels = 4,), + fmt(VK_FORMAT_R32G32B32A32_SINT, R32G32B32A32_SINT, .cpp = 16, .num_channels = 4,), + fmt(VK_FORMAT_R32G32B32A32_SFLOAT, R32G32B32A32_FLOAT, .cpp = 16, .num_channels = 4,), + fmt(VK_FORMAT_R64_SFLOAT, R64_FLOAT, .cpp = 8, .num_channels = 1), + fmt(VK_FORMAT_R64G64_SFLOAT, R64G64_FLOAT, .cpp = 16, .num_channels = 2), + fmt(VK_FORMAT_R64G64B64_SFLOAT, R64G64B64_FLOAT, .cpp = 24, .num_channels = 3), + fmt(VK_FORMAT_R64G64B64A64_SFLOAT, R64G64B64A64_FLOAT, .cpp = 32, .num_channels = 4), + fmt(VK_FORMAT_R11G11B10_UFLOAT, R11G11B10_FLOAT, .cpp = 4, .num_channels = 3), + fmt(VK_FORMAT_R9G9B9E5_UFLOAT, R9G9B9E5_SHAREDEXP, .cpp = 4, .num_channels = 3), + + fmt(VK_FORMAT_D16_UNORM, R16_UNORM, .cpp = 2, .num_channels = 1, .depth_format = D16_UNORM), + fmt(VK_FORMAT_D24_UNORM, R24_UNORM_X8_TYPELESS, .cpp = 4, .num_channels = 1, .depth_format = D24_UNORM_X8_UINT), + fmt(VK_FORMAT_D32_SFLOAT, R32_FLOAT, .cpp = 4, .num_channels = 1, .depth_format = D32_FLOAT), + fmt(VK_FORMAT_S8_UINT, R8_UINT, .cpp = 1, .num_channels = 1, .has_stencil = true), + fmt(VK_FORMAT_D16_UNORM_S8_UINT, R16_UNORM, .cpp = 2, .num_channels = 2, .depth_format = D16_UNORM, .has_stencil = true), + fmt(VK_FORMAT_D24_UNORM_S8_UINT, R24_UNORM_X8_TYPELESS, .cpp = 4, .num_channels = 2, .depth_format = D24_UNORM_X8_UINT, .has_stencil = true), + fmt(VK_FORMAT_D32_SFLOAT_S8_UINT, R32_FLOAT, .cpp = 4, .num_channels = 2, .depth_format = D32_FLOAT, .has_stencil = true), + + fmt(VK_FORMAT_BC1_RGB_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC1_RGB_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_BC1_RGBA_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC1_RGBA_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_BC2_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC2_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_BC3_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC3_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_BC4_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC4_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC5_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC6H_UFLOAT, UNSUPPORTED), + fmt(VK_FORMAT_BC6H_SFLOAT, UNSUPPORTED), + fmt(VK_FORMAT_BC7_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_BC7_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8A1_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8A1_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8A8_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ETC2_R8G8B8A8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_EAC_R11_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_EAC_R11_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_EAC_R11G11_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_EAC_R11G11_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_4x4_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_4x4_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_5x4_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_5x4_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_5x5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_5x5_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_6x5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_6x5_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_6x6_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_6x6_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x5_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x6_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x6_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x8_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_8x8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x5_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x5_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x6_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x6_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x8_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x10_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_10x10_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_12x10_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_12x10_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_12x12_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_ASTC_12x12_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_B4G4R4A4_UNORM, B4G4R4A4_UNORM, .cpp = 2, .num_channels = 4), + fmt(VK_FORMAT_B5G5R5A1_UNORM, B5G5R5A1_UNORM, .cpp = 2, .num_channels = 4), + fmt(VK_FORMAT_B5G6R5_UNORM, B5G6R5_UNORM, .cpp = 2, .num_channels = 3), + fmt(VK_FORMAT_B5G6R5_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_UNORM, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_SSCALED, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_UINT, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_SINT, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8_SRGB, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_UNORM, B8G8R8A8_UNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B8G8R8A8_SNORM, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_USCALED, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_SSCALED, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_UINT, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_SINT, UNSUPPORTED), + fmt(VK_FORMAT_B8G8R8A8_SRGB, B8G8R8A8_UNORM_SRGB, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_UNORM, B10G10R10A2_UNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_SNORM, B10G10R10A2_SNORM, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_USCALED, B10G10R10A2_USCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_SSCALED, B10G10R10A2_SSCALED, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_UINT, B10G10R10A2_UINT, .cpp = 4, .num_channels = 4), + fmt(VK_FORMAT_B10G10R10A2_SINT, B10G10R10A2_SINT, .cpp = 4, .num_channels = 4) +}; + +#undef fmt + +const struct anv_format * +anv_format_for_vk_format(VkFormat format) +{ + return &anv_formats[format]; +} + +bool +anv_is_vk_format_depth_or_stencil(VkFormat format) +{ + const struct anv_format *format_info = + anv_format_for_vk_format(format); + + if (format_info->depth_format != UNSUPPORTED && + format_info->depth_format != 0) + return true; + + return format_info->has_stencil; +} + +// Format capabilities + +struct surface_format_info { + bool exists; + int sampling; + int filtering; + int shadow_compare; + int chroma_key; + int render_target; + int alpha_blend; + int input_vb; + int streamed_output_vb; + int color_processing; +}; + +extern const struct surface_format_info surface_formats[]; + +VkResult anv_validate_GetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat _format, + VkFormatProperties* pFormatProperties) +{ + const struct anv_format *format = anv_format_for_vk_format(_format); + fprintf(stderr, "vkGetFormatProperties(%s)\n", format->name); + return anv_GetPhysicalDeviceFormatProperties(physicalDevice, _format, pFormatProperties); +} + +VkResult anv_GetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat _format, + VkFormatProperties* pFormatProperties) +{ + ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); + const struct surface_format_info *info; + int gen; + + const struct anv_format *format = anv_format_for_vk_format(_format); + if (format == NULL) + return vk_error(VK_ERROR_INVALID_VALUE); + + gen = physical_device->info->gen * 10; + if (physical_device->info->is_haswell) + gen += 5; + + if (format->surface_format == UNSUPPORTED) + goto unsupported; + + info = &surface_formats[format->surface_format]; + if (!info->exists) + goto unsupported; + + uint32_t linear = 0, tiled = 0; + if (info->sampling <= gen) { + linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + } + if (info->render_target <= gen) { + linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + } + if (info->alpha_blend <= gen) { + linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + } + if (info->input_vb <= gen) { + linear |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; + } + + pFormatProperties->linearTilingFeatures = linear; + pFormatProperties->optimalTilingFeatures = tiled; + + return VK_SUCCESS; + + unsupported: + pFormatProperties->linearTilingFeatures = 0; + pFormatProperties->optimalTilingFeatures = 0; + + return VK_SUCCESS; +} + +VkResult anv_GetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageFormatProperties* pImageFormatProperties) +{ + /* TODO: We should do something here. Chad? */ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_GetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + uint32_t samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pNumProperties, + VkSparseImageFormatProperties* pProperties) +{ + stub_return(VK_UNSUPPORTED); +} diff --git a/src/vulkan/anv_gem.c b/src/vulkan/anv_gem.c new file mode 100644 index 00000000000..4ce857e2a5f --- /dev/null +++ b/src/vulkan/anv_gem.c @@ -0,0 +1,279 @@ +/* + * 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. + */ + +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "anv_private.h" + +#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) + +static int +anv_ioctl(int fd, unsigned long request, void *arg) +{ + int ret; + + do { + ret = ioctl(fd, request, arg); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + return ret; +} + +/** + * Wrapper around DRM_IOCTL_I915_GEM_CREATE. + * + * Return gem handle, or 0 on failure. Gem handles are never 0. + */ +uint32_t +anv_gem_create(struct anv_device *device, size_t size) +{ + struct drm_i915_gem_create gem_create; + int ret; + + VG_CLEAR(gem_create); + gem_create.size = size; + + ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create); + if (ret != 0) { + /* FIXME: What do we do if this fails? */ + return 0; + } + + return gem_create.handle; +} + +void +anv_gem_close(struct anv_device *device, int gem_handle) +{ + struct drm_gem_close close; + + VG_CLEAR(close); + close.handle = gem_handle; + anv_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close); +} + +/** + * Wrapper around DRM_IOCTL_I915_GEM_MMAP. + */ +void* +anv_gem_mmap(struct anv_device *device, uint32_t gem_handle, + uint64_t offset, uint64_t size) +{ + struct drm_i915_gem_mmap gem_mmap; + int ret; + + gem_mmap.handle = gem_handle; + VG_CLEAR(gem_mmap.pad); + gem_mmap.offset = offset; + gem_mmap.size = size; + VG_CLEAR(gem_mmap.addr_ptr); + +#ifdef I915_MMAP_WC + gem_mmap.flags = 0; +#endif + + ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_mmap); + if (ret != 0) { + /* FIXME: Is NULL the right error return? Cf MAP_INVALID */ + return NULL; + } + + VG(VALGRIND_MALLOCLIKE_BLOCK(gem_mmap.addr_ptr, gem_mmap.size, 0, 1)); + return (void *)(uintptr_t) gem_mmap.addr_ptr; +} + +/* This is just a wrapper around munmap, but it also notifies valgrind that + * this map is no longer valid. Pair this with anv_gem_mmap(). + */ +void +anv_gem_munmap(void *p, uint64_t size) +{ + VG(VALGRIND_FREELIKE_BLOCK(p, 0)); + munmap(p, size); +} + +int +anv_gem_userptr(struct anv_device *device, void *mem, size_t size) +{ + struct drm_i915_gem_userptr userptr; + int ret; + + VG_CLEAR(userptr); + userptr.user_ptr = (__u64)((unsigned long) mem); + userptr.user_size = size; + userptr.flags = 0; + + ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr); + if (ret == -1) + return 0; + + return userptr.handle; +} + +/** + * On error, \a timeout_ns holds the remaining time. + */ +int +anv_gem_wait(struct anv_device *device, int gem_handle, int64_t *timeout_ns) +{ + struct drm_i915_gem_wait wait; + int ret; + + VG_CLEAR(wait); + wait.bo_handle = gem_handle; + wait.timeout_ns = *timeout_ns; + wait.flags = 0; + + ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_WAIT, &wait); + *timeout_ns = wait.timeout_ns; + + return ret; +} + +int +anv_gem_execbuffer(struct anv_device *device, + struct drm_i915_gem_execbuffer2 *execbuf) +{ + return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); +} + +int +anv_gem_set_tiling(struct anv_device *device, + int gem_handle, uint32_t stride, uint32_t tiling) +{ + struct drm_i915_gem_set_tiling set_tiling; + int ret; + + /* set_tiling overwrites the input on the error path, so we have to open + * code anv_ioctl. + */ + + do { + VG_CLEAR(set_tiling); + set_tiling.handle = gem_handle; + set_tiling.tiling_mode = I915_TILING_X; + set_tiling.stride = stride; + + ret = ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + return ret; +} + +int +anv_gem_get_param(int fd, uint32_t param) +{ + drm_i915_getparam_t gp; + int ret, tmp; + + VG_CLEAR(gp); + gp.param = param; + gp.value = &tmp; + ret = anv_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret == 0) + return tmp; + + return 0; +} + +int +anv_gem_create_context(struct anv_device *device) +{ + struct drm_i915_gem_context_create create; + int ret; + + VG_CLEAR(create); + + ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create); + if (ret == -1) + return -1; + + return create.ctx_id; +} + +int +anv_gem_destroy_context(struct anv_device *device, int context) +{ + struct drm_i915_gem_context_destroy destroy; + + VG_CLEAR(destroy); + destroy.ctx_id = context; + + return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy); +} + +int +anv_gem_get_aperture(struct anv_physical_device *physical_dev, uint64_t *size) +{ + struct drm_i915_gem_get_aperture aperture; + int ret; + + VG_CLEAR(aperture); + ret = anv_ioctl(physical_dev->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); + if (ret == -1) + return -1; + + *size = aperture.aper_available_size; + + return 0; +} + +int +anv_gem_handle_to_fd(struct anv_device *device, int gem_handle) +{ + struct drm_prime_handle args; + int ret; + + VG_CLEAR(args); + args.handle = gem_handle; + args.flags = DRM_CLOEXEC; + + ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); + if (ret == -1) + return -1; + + return args.fd; +} + +int +anv_gem_fd_to_handle(struct anv_device *device, int fd) +{ + struct drm_prime_handle args; + int ret; + + VG_CLEAR(args); + args.fd = fd; + + ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); + if (ret == -1) + return 0; + + return args.handle; +} diff --git a/src/vulkan/anv_image.c b/src/vulkan/anv_image.c new file mode 100644 index 00000000000..21099cb7730 --- /dev/null +++ b/src/vulkan/anv_image.c @@ -0,0 +1,745 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" + +struct anv_image_view_info { + uint8_t surface_type; /**< RENDER_SURFACE_STATE.SurfaceType */ + bool is_array:1; /**< RENDER_SURFACE_STATE.SurfaceArray */ + bool is_cube:1; /**< RENDER_SURFACE_STATE.CubeFaceEnable* */ +}; + +static const uint8_t anv_halign[] = { + [4] = HALIGN4, + [8] = HALIGN8, + [16] = HALIGN16, +}; + +static const uint8_t anv_valign[] = { + [4] = VALIGN4, + [8] = VALIGN8, + [16] = VALIGN16, +}; + +static const uint8_t anv_surf_type_from_image_type[] = { + [VK_IMAGE_TYPE_1D] = SURFTYPE_1D, + [VK_IMAGE_TYPE_2D] = SURFTYPE_2D, + [VK_IMAGE_TYPE_3D] = SURFTYPE_3D, + +}; + +static const struct anv_image_view_info +anv_image_view_info_table[] = { + #define INFO(s, ...) { .surface_type = s, __VA_ARGS__ } + [VK_IMAGE_VIEW_TYPE_1D] = INFO(SURFTYPE_1D), + [VK_IMAGE_VIEW_TYPE_2D] = INFO(SURFTYPE_2D), + [VK_IMAGE_VIEW_TYPE_3D] = INFO(SURFTYPE_3D), + [VK_IMAGE_VIEW_TYPE_CUBE] = INFO(SURFTYPE_CUBE, .is_cube = 1), + [VK_IMAGE_VIEW_TYPE_1D_ARRAY] = INFO(SURFTYPE_1D, .is_array = 1), + [VK_IMAGE_VIEW_TYPE_2D_ARRAY] = INFO(SURFTYPE_2D, .is_array = 1), + [VK_IMAGE_VIEW_TYPE_CUBE_ARRAY] = INFO(SURFTYPE_CUBE, .is_array = 1, .is_cube = 1), + #undef INFO +}; + +static const struct anv_surf_type_limits { + int32_t width; + int32_t height; + int32_t depth; +} anv_surf_type_limits[] = { + [SURFTYPE_1D] = {16384, 0, 2048}, + [SURFTYPE_2D] = {16384, 16384, 2048}, + [SURFTYPE_3D] = {2048, 2048, 2048}, + [SURFTYPE_CUBE] = {16384, 16384, 340}, + [SURFTYPE_BUFFER] = {128, 16384, 64}, + [SURFTYPE_STRBUF] = {128, 16384, 64}, +}; + +static const struct anv_tile_info { + uint32_t width; + uint32_t height; + + /** + * Alignment for RENDER_SURFACE_STATE.SurfaceBaseAddress. + * + * To simplify calculations, the alignments defined in the table are + * sometimes larger than required. For example, Skylake requires that X and + * Y tiled buffers be aligned to 4K, but Broadwell permits smaller + * alignment. We choose 4K to accomodate both chipsets. The alignment of + * a linear buffer depends on its element type and usage. Linear depth + * buffers have the largest alignment, 64B, so we choose that for all linear + * buffers. + */ + uint32_t surface_alignment; +} anv_tile_info_table[] = { + [LINEAR] = { 1, 1, 64 }, + [XMAJOR] = { 512, 8, 4096 }, + [YMAJOR] = { 128, 32, 4096 }, + [WMAJOR] = { 128, 32, 4096 }, +}; + +static uint32_t +anv_image_choose_tile_mode(const struct anv_image_create_info *anv_info) +{ + if (anv_info->force_tile_mode) + return anv_info->tile_mode; + + if (anv_info->vk_info->format == VK_FORMAT_S8_UINT) + return WMAJOR; + + switch (anv_info->vk_info->tiling) { + case VK_IMAGE_TILING_LINEAR: + return LINEAR; + case VK_IMAGE_TILING_OPTIMAL: + return YMAJOR; + default: + assert(!"bad VKImageTiling"); + return LINEAR; + } +} + +static VkResult +anv_image_make_surface(const struct anv_image_create_info *create_info, + uint64_t *inout_image_size, + uint32_t *inout_image_alignment, + struct anv_surface *out_surface) +{ + /* See RENDER_SURFACE_STATE.SurfaceQPitch */ + static const uint16_t min_qpitch UNUSED = 0x4; + static const uint16_t max_qpitch UNUSED = 0x1ffc; + + const VkExtent3D *restrict extent = &create_info->vk_info->extent; + const uint32_t levels = create_info->vk_info->mipLevels; + const uint32_t array_size = create_info->vk_info->arraySize; + + const uint8_t tile_mode = anv_image_choose_tile_mode(create_info); + + const struct anv_tile_info *tile_info = + &anv_tile_info_table[tile_mode]; + + const struct anv_format *format_info = + anv_format_for_vk_format(create_info->vk_info->format); + + const uint32_t i = 4; /* FINISHME: Stop hardcoding subimage alignment */ + const uint32_t j = 4; /* FINISHME: Stop hardcoding subimage alignment */ + const uint32_t w0 = align_u32(extent->width, i); + const uint32_t h0 = align_u32(extent->height, j); + + uint16_t qpitch; + uint32_t mt_width; + uint32_t mt_height; + + if (levels == 1 && array_size == 1) { + qpitch = min_qpitch; + mt_width = w0; + mt_height = h0; + } else { + uint32_t w1 = align_u32(anv_minify(extent->width, 1), i); + uint32_t h1 = align_u32(anv_minify(extent->height, 1), j); + uint32_t w2 = align_u32(anv_minify(extent->width, 2), i); + + qpitch = h0 + h1 + 11 * j; + mt_width = MAX(w0, w1 + w2); + mt_height = array_size * qpitch; + } + + assert(qpitch >= min_qpitch); + if (qpitch > max_qpitch) { + anv_loge("image qpitch > 0x%x\n", max_qpitch); + return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); + } + + /* From the Broadwell PRM, RENDER_SURFACE_STATE.SurfaceQpitch: + * + * This field must be set an integer multiple of the Surface Vertical + * Alignment. + */ + assert(anv_is_aligned(qpitch, j)); + + const uint32_t stride = align_u32(mt_width * format_info->cpp, + tile_info->width); + const uint32_t size = stride * align_u32(mt_height, tile_info->height); + const uint32_t offset = align_u32(*inout_image_size, + tile_info->surface_alignment); + + *inout_image_size = offset + size; + *inout_image_alignment = MAX(*inout_image_alignment, + tile_info->surface_alignment); + + *out_surface = (struct anv_surface) { + .offset = offset, + .stride = stride, + .tile_mode = tile_mode, + .qpitch = qpitch, + .h_align = i, + .v_align = j, + }; + + return VK_SUCCESS; +} + +VkResult +anv_image_create(VkDevice _device, + const struct anv_image_create_info *create_info, + VkImage *pImage) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + const VkImageCreateInfo *pCreateInfo = create_info->vk_info; + const VkExtent3D *restrict extent = &pCreateInfo->extent; + struct anv_image *image = NULL; + VkResult r; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + + /* XXX: We don't handle any of these */ + anv_assert(pCreateInfo->imageType == VK_IMAGE_TYPE_2D); + anv_assert(pCreateInfo->mipLevels > 0); + anv_assert(pCreateInfo->arraySize > 0); + anv_assert(pCreateInfo->samples == 1); + anv_assert(pCreateInfo->extent.width > 0); + anv_assert(pCreateInfo->extent.height > 0); + anv_assert(pCreateInfo->extent.depth > 0); + + /* TODO(chadv): How should we validate inputs? */ + const uint8_t surf_type = + anv_surf_type_from_image_type[pCreateInfo->imageType]; + + const struct anv_surf_type_limits *limits = + &anv_surf_type_limits[surf_type]; + + if (extent->width > limits->width || + extent->height > limits->height || + extent->depth > limits->depth) { + /* TODO(chadv): What is the correct error? */ + anv_loge("image extent is too large"); + return vk_error(VK_ERROR_INVALID_MEMORY_SIZE); + } + + const struct anv_format *format_info = + anv_format_for_vk_format(pCreateInfo->format); + + image = anv_device_alloc(device, sizeof(*image), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (!image) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + memset(image, 0, sizeof(*image)); + image->type = pCreateInfo->imageType; + image->extent = pCreateInfo->extent; + image->format = pCreateInfo->format; + image->levels = pCreateInfo->mipLevels; + image->array_size = pCreateInfo->arraySize; + image->surf_type = surf_type; + + if (likely(!format_info->has_stencil || format_info->depth_format)) { + /* The image's primary surface is a color or depth surface. */ + r = anv_image_make_surface(create_info, &image->size, &image->alignment, + &image->primary_surface); + if (r != VK_SUCCESS) + goto fail; + } + + if (format_info->has_stencil) { + /* From the GPU's perspective, the depth buffer and stencil buffer are + * separate buffers. From Vulkan's perspective, though, depth and + * stencil reside in the same image. To satisfy Vulkan and the GPU, we + * place the depth and stencil buffers in the same bo. + */ + VkImageCreateInfo stencil_info = *pCreateInfo; + stencil_info.format = VK_FORMAT_S8_UINT; + + r = anv_image_make_surface( + &(struct anv_image_create_info) { + .vk_info = &stencil_info, + }, + &image->size, &image->alignment, &image->stencil_surface); + + if (r != VK_SUCCESS) + goto fail; + } + + *pImage = anv_image_to_handle(image); + + return VK_SUCCESS; + +fail: + if (image) + anv_device_free(device, image); + + return r; +} + +VkResult +anv_CreateImage(VkDevice device, + const VkImageCreateInfo *pCreateInfo, + VkImage *pImage) +{ + return anv_image_create(device, + &(struct anv_image_create_info) { + .vk_info = pCreateInfo, + }, + pImage); +} + +VkResult +anv_DestroyImage(VkDevice _device, VkImage _image) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + anv_device_free(device, anv_image_from_handle(_image)); + + return VK_SUCCESS; +} + +VkResult anv_GetImageSubresourceLayout( + VkDevice device, + VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout) +{ + stub_return(VK_UNSUPPORTED); +} + +void +anv_surface_view_fini(struct anv_device *device, + struct anv_surface_view *view) +{ + anv_state_pool_free(&device->surface_state_pool, view->surface_state); +} + +void +anv_image_view_init(struct anv_image_view *iview, + struct anv_device *device, + const VkImageViewCreateInfo* pCreateInfo, + struct anv_cmd_buffer *cmd_buffer) +{ + ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); + + const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange; + struct anv_surface_view *view = &iview->view; + struct anv_surface *surface; + + const struct anv_format *format_info = + anv_format_for_vk_format(pCreateInfo->format); + + const struct anv_image_view_info *view_type_info + = &anv_image_view_info_table[pCreateInfo->viewType]; + + if (pCreateInfo->viewType != VK_IMAGE_VIEW_TYPE_2D) + anv_finishme("non-2D image views"); + + switch (pCreateInfo->subresourceRange.aspect) { + case VK_IMAGE_ASPECT_STENCIL: + anv_finishme("stencil image views"); + abort(); + break; + case VK_IMAGE_ASPECT_DEPTH: + case VK_IMAGE_ASPECT_COLOR: + view->offset = image->offset; + surface = &image->primary_surface; + break; + default: + unreachable(""); + break; + } + + view->bo = image->bo; + view->offset = image->offset + surface->offset; + view->format = pCreateInfo->format; + + iview->extent = (VkExtent3D) { + .width = anv_minify(image->extent.width, range->baseMipLevel), + .height = anv_minify(image->extent.height, range->baseMipLevel), + .depth = anv_minify(image->extent.depth, range->baseMipLevel), + }; + + uint32_t depth = 1; + if (range->arraySize > 1) { + depth = range->arraySize; + } else if (image->extent.depth > 1) { + depth = image->extent.depth; + } + + static const uint32_t vk_to_gen_swizzle[] = { + [VK_CHANNEL_SWIZZLE_ZERO] = SCS_ZERO, + [VK_CHANNEL_SWIZZLE_ONE] = SCS_ONE, + [VK_CHANNEL_SWIZZLE_R] = SCS_RED, + [VK_CHANNEL_SWIZZLE_G] = SCS_GREEN, + [VK_CHANNEL_SWIZZLE_B] = SCS_BLUE, + [VK_CHANNEL_SWIZZLE_A] = SCS_ALPHA + }; + + struct GEN8_RENDER_SURFACE_STATE surface_state = { + .SurfaceType = view_type_info->surface_type, + .SurfaceArray = image->array_size > 1, + .SurfaceFormat = format_info->surface_format, + .SurfaceVerticalAlignment = anv_valign[surface->v_align], + .SurfaceHorizontalAlignment = anv_halign[surface->h_align], + .TileMode = surface->tile_mode, + .VerticalLineStride = 0, + .VerticalLineStrideOffset = 0, + .SamplerL2BypassModeDisable = true, + .RenderCacheReadWriteMode = WriteOnlyCache, + .MemoryObjectControlState = GEN8_MOCS, + + /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in + * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have + * both Base Mip Level fields nonzero". + */ + .BaseMipLevel = 0.0, + + .SurfaceQPitch = surface->qpitch >> 2, + .Height = image->extent.height - 1, + .Width = image->extent.width - 1, + .Depth = depth - 1, + .SurfacePitch = surface->stride - 1, + .MinimumArrayElement = range->baseArraySlice, + .NumberofMultisamples = MULTISAMPLECOUNT_1, + .XOffset = 0, + .YOffset = 0, + + /* For sampler surfaces, the hardware interprets field MIPCount/LOD as + * MIPCount. The range of levels accessible by the sampler engine is + * [SurfaceMinLOD, SurfaceMinLOD + MIPCountLOD]. + */ + .MIPCountLOD = range->mipLevels - 1, + .SurfaceMinLOD = range->baseMipLevel, + + .AuxiliarySurfaceMode = AUX_NONE, + .RedClearColor = 0, + .GreenClearColor = 0, + .BlueClearColor = 0, + .AlphaClearColor = 0, + .ShaderChannelSelectRed = vk_to_gen_swizzle[pCreateInfo->channels.r], + .ShaderChannelSelectGreen = vk_to_gen_swizzle[pCreateInfo->channels.g], + .ShaderChannelSelectBlue = vk_to_gen_swizzle[pCreateInfo->channels.b], + .ShaderChannelSelectAlpha = vk_to_gen_swizzle[pCreateInfo->channels.a], + .ResourceMinLOD = 0.0, + .SurfaceBaseAddress = { NULL, view->offset }, + }; + + if (cmd_buffer) { + view->surface_state = + anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64); + } else { + view->surface_state = + anv_state_pool_alloc(&device->surface_state_pool, 64, 64); + } + + GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state); +} + +VkResult +anv_validate_CreateImageView(VkDevice _device, + const VkImageViewCreateInfo *pCreateInfo, + VkImageView *pView) +{ + ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); + const VkImageSubresourceRange *subresource; + const struct anv_image_view_info *view_info; + const struct anv_format *view_format_info; + const struct anv_format *image_format_info; + + /* Validate structure type before dereferencing it. */ + assert(pCreateInfo); + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); + subresource = &pCreateInfo->subresourceRange; + + /* Validate viewType is in range before using it. */ + assert(pCreateInfo->viewType >= VK_IMAGE_VIEW_TYPE_BEGIN_RANGE); + assert(pCreateInfo->viewType <= VK_IMAGE_VIEW_TYPE_END_RANGE); + view_info = &anv_image_view_info_table[pCreateInfo->viewType]; + + /* Validate format is in range before using it. */ + assert(pCreateInfo->format >= VK_FORMAT_BEGIN_RANGE); + assert(pCreateInfo->format <= VK_FORMAT_END_RANGE); + image_format_info = anv_format_for_vk_format(image->format); + view_format_info = anv_format_for_vk_format(pCreateInfo->format); + + /* Validate channel swizzles. */ + assert(pCreateInfo->channels.r >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); + assert(pCreateInfo->channels.r <= VK_CHANNEL_SWIZZLE_END_RANGE); + assert(pCreateInfo->channels.g >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); + assert(pCreateInfo->channels.g <= VK_CHANNEL_SWIZZLE_END_RANGE); + assert(pCreateInfo->channels.b >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); + assert(pCreateInfo->channels.b <= VK_CHANNEL_SWIZZLE_END_RANGE); + assert(pCreateInfo->channels.a >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); + assert(pCreateInfo->channels.a <= VK_CHANNEL_SWIZZLE_END_RANGE); + + /* Validate subresource. */ + assert(subresource->aspect >= VK_IMAGE_ASPECT_BEGIN_RANGE); + assert(subresource->aspect <= VK_IMAGE_ASPECT_END_RANGE); + assert(subresource->mipLevels > 0); + assert(subresource->arraySize > 0); + assert(subresource->baseMipLevel < image->levels); + assert(subresource->baseMipLevel + subresource->mipLevels <= image->levels); + assert(subresource->baseArraySlice < image->array_size); + assert(subresource->baseArraySlice + subresource->arraySize <= image->array_size); + assert(pView); + + if (view_info->is_cube) { + assert(subresource->baseArraySlice % 6 == 0); + assert(subresource->arraySize % 6 == 0); + } + + /* Validate format. */ + switch (subresource->aspect) { + case VK_IMAGE_ASPECT_COLOR: + assert(!image_format_info->depth_format); + assert(!image_format_info->has_stencil); + assert(!view_format_info->depth_format); + assert(!view_format_info->has_stencil); + assert(view_format_info->cpp == image_format_info->cpp); + break; + case VK_IMAGE_ASPECT_DEPTH: + assert(image_format_info->depth_format); + assert(view_format_info->depth_format); + assert(view_format_info->cpp == image_format_info->cpp); + break; + case VK_IMAGE_ASPECT_STENCIL: + /* FINISHME: Is it legal to have an R8 view of S8? */ + assert(image_format_info->has_stencil); + assert(view_format_info->has_stencil); + break; + default: + assert(!"bad VkImageAspect"); + break; + } + + return anv_CreateImageView(_device, pCreateInfo, pView); +} + +VkResult +anv_CreateImageView(VkDevice _device, + const VkImageViewCreateInfo *pCreateInfo, + VkImageView *pView) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_image_view *view; + + 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); + + anv_image_view_init(view, device, pCreateInfo, NULL); + + *pView = anv_image_view_to_handle(view); + + return VK_SUCCESS; +} + +VkResult +anv_DestroyImageView(VkDevice _device, VkImageView _iview) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_image_view, iview, _iview); + + anv_surface_view_fini(device, &iview->view); + anv_device_free(device, iview); + + return VK_SUCCESS; +} + +void +anv_color_attachment_view_init(struct anv_color_attachment_view *aview, + struct anv_device *device, + const VkAttachmentViewCreateInfo* pCreateInfo, + struct anv_cmd_buffer *cmd_buffer) +{ + ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); + struct anv_surface_view *view = &aview->view; + struct anv_surface *surface = &image->primary_surface; + const struct anv_format *format_info = + anv_format_for_vk_format(pCreateInfo->format); + + aview->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_COLOR; + + anv_assert(pCreateInfo->arraySize > 0); + anv_assert(pCreateInfo->mipLevel < image->levels); + anv_assert(pCreateInfo->baseArraySlice + pCreateInfo->arraySize <= image->array_size); + + view->bo = image->bo; + view->offset = image->offset + surface->offset; + view->format = pCreateInfo->format; + + aview->base.extent = (VkExtent3D) { + .width = anv_minify(image->extent.width, pCreateInfo->mipLevel), + .height = anv_minify(image->extent.height, pCreateInfo->mipLevel), + .depth = anv_minify(image->extent.depth, pCreateInfo->mipLevel), + }; + + uint32_t depth = 1; + if (pCreateInfo->arraySize > 1) { + depth = pCreateInfo->arraySize; + } else if (image->extent.depth > 1) { + depth = image->extent.depth; + } + + if (cmd_buffer) { + view->surface_state = + anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64); + } else { + view->surface_state = + anv_state_pool_alloc(&device->surface_state_pool, 64, 64); + } + + struct GEN8_RENDER_SURFACE_STATE surface_state = { + .SurfaceType = SURFTYPE_2D, + .SurfaceArray = image->array_size > 1, + .SurfaceFormat = format_info->surface_format, + .SurfaceVerticalAlignment = anv_valign[surface->v_align], + .SurfaceHorizontalAlignment = anv_halign[surface->h_align], + .TileMode = surface->tile_mode, + .VerticalLineStride = 0, + .VerticalLineStrideOffset = 0, + .SamplerL2BypassModeDisable = true, + .RenderCacheReadWriteMode = WriteOnlyCache, + .MemoryObjectControlState = GEN8_MOCS, + + /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in + * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have + * both Base Mip Level fields nonzero". + */ + .BaseMipLevel = 0.0, + + .SurfaceQPitch = surface->qpitch >> 2, + .Height = image->extent.height - 1, + .Width = image->extent.width - 1, + .Depth = depth - 1, + .SurfacePitch = surface->stride - 1, + .MinimumArrayElement = pCreateInfo->baseArraySlice, + .NumberofMultisamples = MULTISAMPLECOUNT_1, + .XOffset = 0, + .YOffset = 0, + + /* For render target surfaces, the hardware interprets field MIPCount/LOD as + * LOD. The Broadwell PRM says: + * + * MIPCountLOD defines the LOD that will be rendered into. + * SurfaceMinLOD is ignored. + */ + .SurfaceMinLOD = 0, + .MIPCountLOD = pCreateInfo->mipLevel, + + .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.0, + .SurfaceBaseAddress = { NULL, view->offset }, + }; + + GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state); +} + +static void +anv_depth_stencil_view_init(struct anv_depth_stencil_view *view, + const VkAttachmentViewCreateInfo *pCreateInfo) +{ + ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); + struct anv_surface *depth_surface = &image->primary_surface; + struct anv_surface *stencil_surface = &image->stencil_surface; + const struct anv_format *format = + anv_format_for_vk_format(image->format); + + view->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_DEPTH_STENCIL; + + /* XXX: We don't handle any of these */ + anv_assert(pCreateInfo->mipLevel == 0); + anv_assert(pCreateInfo->baseArraySlice == 0); + anv_assert(pCreateInfo->arraySize == 1); + + view->bo = image->bo; + + view->depth_stride = depth_surface->stride; + view->depth_offset = image->offset + depth_surface->offset; + view->depth_format = format->depth_format; + view->depth_qpitch = 0; /* FINISHME: QPitch */ + + view->stencil_stride = stencil_surface->stride; + view->stencil_offset = image->offset + stencil_surface->offset; + view->stencil_qpitch = 0; /* FINISHME: QPitch */ +} + +VkResult +anv_CreateAttachmentView(VkDevice _device, + const VkAttachmentViewCreateInfo *pCreateInfo, + VkAttachmentView *pView) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO); + + if (anv_is_vk_format_depth_or_stencil(pCreateInfo->format)) { + struct anv_depth_stencil_view *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); + + anv_depth_stencil_view_init(view, pCreateInfo); + + *pView = anv_attachment_view_to_handle(&view->base); + } else { + struct anv_color_attachment_view *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); + + anv_color_attachment_view_init(view, device, pCreateInfo, NULL); + + *pView = anv_attachment_view_to_handle(&view->base); + } + + return VK_SUCCESS; +} + +VkResult +anv_DestroyAttachmentView(VkDevice _device, VkAttachmentView _view) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_attachment_view, view, _view); + + if (view->attachment_type == ANV_ATTACHMENT_VIEW_TYPE_COLOR) { + struct anv_color_attachment_view *aview = + (struct anv_color_attachment_view *)view; + + anv_surface_view_fini(device, &aview->view); + } + + anv_device_free(device, view); + + return VK_SUCCESS; +} diff --git a/src/vulkan/anv_intel.c b/src/vulkan/anv_intel.c new file mode 100644 index 00000000000..9fc06aef6f8 --- /dev/null +++ b/src/vulkan/anv_intel.c @@ -0,0 +1,97 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" + +VkResult anv_CreateDmaBufImageINTEL( + VkDevice _device, + const VkDmaBufImageCreateInfo* pCreateInfo, + VkDeviceMemory* pMem, + VkImage* pImage) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_device_memory *mem; + struct anv_image *image; + VkResult result; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL); + + 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); + + mem->bo.gem_handle = anv_gem_fd_to_handle(device, pCreateInfo->fd); + if (!mem->bo.gem_handle) { + result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); + goto fail; + } + + mem->bo.map = NULL; + mem->bo.index = 0; + mem->bo.offset = 0; + mem->bo.size = pCreateInfo->strideInBytes * pCreateInfo->extent.height; + + image = anv_device_alloc(device, sizeof(*image), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (image == NULL) { + result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + goto fail_mem; + } + + *image = (struct anv_image) { + .bo = &mem->bo, + .offset = 0, + .type = VK_IMAGE_TYPE_2D, + .extent = pCreateInfo->extent, + .size = mem->bo.size, + + .primary_surface = { + .offset = 0, + .stride = pCreateInfo->strideInBytes, + .tile_mode = XMAJOR, + }, + }; + + assert(image->extent.width > 0); + assert(image->extent.height > 0); + assert(image->extent.depth == 1); + + *pMem = anv_device_memory_to_handle(mem); + *pImage = anv_image_to_handle(image); + + return VK_SUCCESS; + + fail_mem: + anv_gem_close(device, mem->bo.gem_handle); + fail: + anv_device_free(device, mem); + + return result; +} diff --git a/src/vulkan/anv_meta.c b/src/vulkan/anv_meta.c new file mode 100644 index 00000000000..f2629156f3c --- /dev/null +++ b/src/vulkan/anv_meta.c @@ -0,0 +1,1449 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" +#include "anv_meta_spirv.h" + +static void +anv_device_init_meta_clear_state(struct anv_device *device) +{ + /* We don't use a vertex shader for clearing, but instead build and pass + * the VUEs directly to the rasterization backend. + */ + VkShaderModule fsm = GLSL_VK_SHADER_MODULE(device, FRAGMENT, + out vec4 f_color; + flat in vec4 v_color; + void main() + { + f_color = v_color; + } + ); + + VkShader fs; + anv_CreateShader(anv_device_to_handle(device), + &(VkShaderCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, + .module = fsm, + .pName = "main", + }, &fs); + + /* We use instanced rendering to clear multiple render targets. We have two + * vertex buffers: the first vertex buffer holds per-vertex data and + * provides the vertices for the clear rectangle. The second one holds + * per-instance data, which consists of the VUE header (which selects the + * layer) and the color (Vulkan supports per-RT clear colors). + */ + VkPipelineVertexInputStateCreateInfo vi_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .bindingCount = 2, + .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { + { + .binding = 0, + .strideInBytes = 8, + .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX + }, + { + .binding = 1, + .strideInBytes = 32, + .stepRate = VK_VERTEX_INPUT_STEP_RATE_INSTANCE + }, + }, + .attributeCount = 3, + .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { + { + /* VUE Header */ + .location = 0, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_UINT, + .offsetInBytes = 0 + }, + { + /* Position */ + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offsetInBytes = 0 + }, + { + /* Color */ + .location = 2, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offsetInBytes = 16 + } + } + }; + + anv_pipeline_create(anv_device_to_handle(device), + &(VkGraphicsPipelineCreateInfo) { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 1, + .pStages = &(VkPipelineShaderStageCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT, + .shader = fs, + .pSpecializationInfo = NULL, + }, + .pVertexInputState = &vi_create_info, + .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + .primitiveRestartEnable = false, + }, + .pRasterState = &(VkPipelineRasterStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, + .depthClipEnable = true, + .rasterizerDiscardEnable = false, + .fillMode = VK_FILL_MODE_SOLID, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CCW + }, + .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = (VkPipelineColorBlendAttachmentState []) { + { .channelWriteMask = VK_CHANNEL_A_BIT | + VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT }, + } + }, + .flags = 0, + }, + &(struct anv_pipeline_create_info) { + .use_repclear = true, + .disable_viewport = true, + .use_rectlist = true + }, + &device->meta_state.clear.pipeline); + + anv_DestroyShader(anv_device_to_handle(device), fs); +} + +#define NUM_VB_USED 2 +struct anv_saved_state { + struct anv_vertex_binding old_vertex_bindings[NUM_VB_USED]; + struct anv_descriptor_set *old_descriptor_set0; + struct anv_pipeline *old_pipeline; + VkDynamicColorBlendState cb_state; +}; + +static void +anv_cmd_buffer_save(struct anv_cmd_buffer *cmd_buffer, + struct anv_saved_state *state) +{ + state->old_pipeline = cmd_buffer->state.pipeline; + state->old_descriptor_set0 = cmd_buffer->state.descriptors[0].set; + memcpy(state->old_vertex_bindings, cmd_buffer->state.vertex_bindings, + sizeof(state->old_vertex_bindings)); +} + +static void +anv_cmd_buffer_restore(struct anv_cmd_buffer *cmd_buffer, + const struct anv_saved_state *state) +{ + cmd_buffer->state.pipeline = state->old_pipeline; + cmd_buffer->state.descriptors[0].set = state->old_descriptor_set0; + memcpy(cmd_buffer->state.vertex_bindings, state->old_vertex_bindings, + sizeof(state->old_vertex_bindings)); + + cmd_buffer->state.vb_dirty |= (1 << NUM_VB_USED) - 1; + cmd_buffer->state.dirty |= ANV_CMD_BUFFER_PIPELINE_DIRTY; + cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_VERTEX_BIT; +} + +struct vue_header { + uint32_t Reserved; + uint32_t RTAIndex; + uint32_t ViewportIndex; + float PointWidth; +}; + +struct clear_instance_data { + struct vue_header vue_header; + VkClearColorValue color; +}; + +static void +meta_emit_clear(struct anv_cmd_buffer *cmd_buffer, + int num_instances, + struct clear_instance_data *instance_data) +{ + struct anv_device *device = cmd_buffer->device; + struct anv_framebuffer *fb = cmd_buffer->state.framebuffer; + struct anv_state state; + uint32_t size; + + const float vertex_data[] = { + /* Rect-list coordinates */ + 0.0, 0.0, + fb->width, 0.0, + fb->width, fb->height, + + /* Align to 16 bytes */ + 0.0, 0.0, + }; + + size = sizeof(vertex_data) + num_instances * sizeof(*instance_data); + state = anv_state_stream_alloc(&cmd_buffer->surface_state_stream, size, 16); + + /* Copy in the vertex and instance data */ + memcpy(state.map, vertex_data, sizeof(vertex_data)); + memcpy(state.map + sizeof(vertex_data), instance_data, + num_instances * sizeof(*instance_data)); + + struct anv_buffer vertex_buffer = { + .device = cmd_buffer->device, + .size = size, + .bo = &device->surface_state_block_pool.bo, + .offset = state.offset + }; + + anv_CmdBindVertexBuffers(anv_cmd_buffer_to_handle(cmd_buffer), 0, 2, + (VkBuffer[]) { + anv_buffer_to_handle(&vertex_buffer), + anv_buffer_to_handle(&vertex_buffer) + }, + (VkDeviceSize[]) { + 0, + sizeof(vertex_data) + }); + + if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(device->meta_state.clear.pipeline)) + anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer), + VK_PIPELINE_BIND_POINT_GRAPHICS, + device->meta_state.clear.pipeline); + + /* We don't need anything here, only set if not already set. */ + if (cmd_buffer->state.rs_state == NULL) + anv_CmdBindDynamicRasterState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.rs_state); + + if (cmd_buffer->state.vp_state == NULL) + anv_CmdBindDynamicViewportState(anv_cmd_buffer_to_handle(cmd_buffer), + cmd_buffer->state.framebuffer->vp_state); + + if (cmd_buffer->state.ds_state == NULL) + anv_CmdBindDynamicDepthStencilState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.ds_state); + + if (cmd_buffer->state.cb_state == NULL) + anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.cb_state); + + anv_CmdDraw(anv_cmd_buffer_to_handle(cmd_buffer), 0, 3, 0, num_instances); +} + +void +anv_cmd_buffer_clear_attachments(struct anv_cmd_buffer *cmd_buffer, + struct anv_render_pass *pass, + const VkClearValue *clear_values) +{ + struct anv_saved_state saved_state; + + int num_clear_layers = 0; + for (uint32_t i = 0; i < pass->attachment_count; i++) { + if (pass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { + if (anv_is_vk_format_depth_or_stencil(pass->attachments[i].format)) { + anv_finishme("Can't clear depth-stencil yet"); + continue; + } + num_clear_layers++; + } + } + + if (num_clear_layers == 0) + return; + + struct clear_instance_data instance_data[num_clear_layers]; + uint32_t color_attachments[num_clear_layers]; + + int layer = 0; + for (uint32_t i = 0; i < pass->attachment_count; i++) { + if (pass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR && + !anv_is_vk_format_depth_or_stencil(pass->attachments[i].format)) { + instance_data[layer] = (struct clear_instance_data) { + .vue_header = { + .RTAIndex = i, + .ViewportIndex = 0, + .PointWidth = 0.0 + }, + .color = clear_values[i].color, + }; + color_attachments[layer] = i; + layer++; + } + } + + anv_cmd_buffer_save(cmd_buffer, &saved_state); + + struct anv_subpass subpass = { + .input_count = 0, + .color_count = num_clear_layers, + .color_attachments = color_attachments, + .depth_stencil_attachment = VK_ATTACHMENT_UNUSED, + }; + + anv_cmd_buffer_begin_subpass(cmd_buffer, &subpass); + + meta_emit_clear(cmd_buffer, num_clear_layers, instance_data); + + /* Restore API state */ + anv_cmd_buffer_restore(cmd_buffer, &saved_state); +} + +static void +anv_device_init_meta_blit_state(struct anv_device *device) +{ + /* We don't use a vertex shader for clearing, but instead build and pass + * the VUEs directly to the rasterization backend. However, we do need + * to provide GLSL source for the vertex shader so that the compiler + * does not dead-code our inputs. + */ + VkShaderModule vsm = GLSL_VK_SHADER_MODULE(device, VERTEX, + in vec2 a_pos; + in vec2 a_tex_coord; + out vec4 v_tex_coord; + void main() + { + v_tex_coord = vec4(a_tex_coord, 0, 1); + gl_Position = vec4(a_pos, 0, 1); + } + ); + + VkShaderModule fsm = GLSL_VK_SHADER_MODULE(device, FRAGMENT, + out vec4 f_color; + in vec4 v_tex_coord; + layout(set = 0, binding = 0) uniform sampler2D u_tex; + void main() + { + f_color = texture(u_tex, v_tex_coord.xy); + } + ); + + VkShader vs; + anv_CreateShader(anv_device_to_handle(device), + &(VkShaderCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, + .module = vsm, + .pName = "main", + }, &vs); + + VkShader fs; + anv_CreateShader(anv_device_to_handle(device), + &(VkShaderCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, + .module = fsm, + .pName = "main", + }, &fs); + + VkPipelineVertexInputStateCreateInfo vi_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .bindingCount = 2, + .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { + { + .binding = 0, + .strideInBytes = 0, + .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX + }, + { + .binding = 1, + .strideInBytes = 16, + .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX + }, + }, + .attributeCount = 3, + .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { + { + /* VUE Header */ + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_UINT, + .offsetInBytes = 0 + }, + { + /* Position */ + .location = 1, + .binding = 1, + .format = VK_FORMAT_R32G32_SFLOAT, + .offsetInBytes = 0 + }, + { + /* Texture Coordinate */ + .location = 2, + .binding = 1, + .format = VK_FORMAT_R32G32_SFLOAT, + .offsetInBytes = 8 + } + } + }; + + VkDescriptorSetLayoutCreateInfo ds_layout_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .count = 1, + .pBinding = (VkDescriptorSetLayoutBinding[]) { + { + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .arraySize = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = NULL + }, + } + }; + anv_CreateDescriptorSetLayout(anv_device_to_handle(device), &ds_layout_info, + &device->meta_state.blit.ds_layout); + + anv_CreatePipelineLayout(anv_device_to_handle(device), + &(VkPipelineLayoutCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .descriptorSetCount = 1, + .pSetLayouts = &device->meta_state.blit.ds_layout, + }, + &device->meta_state.blit.pipeline_layout); + + anv_pipeline_create(anv_device_to_handle(device), + &(VkGraphicsPipelineCreateInfo) { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = (VkPipelineShaderStageCreateInfo[]) { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX, + .shader = vs, + .pSpecializationInfo = NULL + }, { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT, + .shader = fs, + .pSpecializationInfo = NULL + }, + }, + .pVertexInputState = &vi_create_info, + .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + .primitiveRestartEnable = false, + }, + .pRasterState = &(VkPipelineRasterStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, + .depthClipEnable = true, + .rasterizerDiscardEnable = false, + .fillMode = VK_FILL_MODE_SOLID, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CCW + }, + .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = (VkPipelineColorBlendAttachmentState []) { + { .channelWriteMask = VK_CHANNEL_A_BIT | + VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT }, + } + }, + .flags = 0, + .layout = device->meta_state.blit.pipeline_layout, + }, + &(struct anv_pipeline_create_info) { + .use_repclear = false, + .disable_viewport = true, + .disable_scissor = true, + .disable_vs = true, + .use_rectlist = true + }, + &device->meta_state.blit.pipeline); + + anv_DestroyShader(anv_device_to_handle(device), vs); + anv_DestroyShader(anv_device_to_handle(device), fs); +} + +static void +meta_prepare_blit(struct anv_cmd_buffer *cmd_buffer, + struct anv_saved_state *saved_state) +{ + struct anv_device *device = cmd_buffer->device; + + anv_cmd_buffer_save(cmd_buffer, saved_state); + + if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(device->meta_state.blit.pipeline)) + anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer), + VK_PIPELINE_BIND_POINT_GRAPHICS, + device->meta_state.blit.pipeline); + + /* We don't need anything here, only set if not already set. */ + if (cmd_buffer->state.rs_state == NULL) + anv_CmdBindDynamicRasterState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.rs_state); + if (cmd_buffer->state.ds_state == NULL) + anv_CmdBindDynamicDepthStencilState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.ds_state); + + saved_state->cb_state = anv_dynamic_cb_state_to_handle(cmd_buffer->state.cb_state); + anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), + device->meta_state.shared.cb_state); +} + +struct blit_region { + VkOffset3D src_offset; + VkExtent3D src_extent; + VkOffset3D dest_offset; + VkExtent3D dest_extent; +}; + +static void +meta_emit_blit(struct anv_cmd_buffer *cmd_buffer, + struct anv_image_view *src, + VkOffset3D src_offset, + VkExtent3D src_extent, + struct anv_color_attachment_view *dest, + VkOffset3D dest_offset, + VkExtent3D dest_extent) +{ + struct anv_device *device = cmd_buffer->device; + VkDescriptorPool dummy_desc_pool = { .handle = 1 }; + + struct blit_vb_data { + float pos[2]; + float tex_coord[2]; + } *vb_data; + + unsigned vb_size = sizeof(struct vue_header) + 3 * sizeof(*vb_data); + + struct anv_state vb_state = + anv_state_stream_alloc(&cmd_buffer->surface_state_stream, vb_size, 16); + memset(vb_state.map, 0, sizeof(struct vue_header)); + vb_data = vb_state.map + sizeof(struct vue_header); + + vb_data[0] = (struct blit_vb_data) { + .pos = { + dest_offset.x + dest_extent.width, + dest_offset.y + dest_extent.height, + }, + .tex_coord = { + (float)(src_offset.x + src_extent.width) / (float)src->extent.width, + (float)(src_offset.y + src_extent.height) / (float)src->extent.height, + }, + }; + + vb_data[1] = (struct blit_vb_data) { + .pos = { + dest_offset.x, + dest_offset.y + dest_extent.height, + }, + .tex_coord = { + (float)src_offset.x / (float)src->extent.width, + (float)(src_offset.y + src_extent.height) / (float)src->extent.height, + }, + }; + + vb_data[2] = (struct blit_vb_data) { + .pos = { + dest_offset.x, + dest_offset.y, + }, + .tex_coord = { + (float)src_offset.x / (float)src->extent.width, + (float)src_offset.y / (float)src->extent.height, + }, + }; + + struct anv_buffer vertex_buffer = { + .device = device, + .size = vb_size, + .bo = &device->surface_state_block_pool.bo, + .offset = vb_state.offset, + }; + + anv_CmdBindVertexBuffers(anv_cmd_buffer_to_handle(cmd_buffer), 0, 2, + (VkBuffer[]) { + anv_buffer_to_handle(&vertex_buffer), + anv_buffer_to_handle(&vertex_buffer) + }, + (VkDeviceSize[]) { + 0, + sizeof(struct vue_header), + }); + + uint32_t count; + VkDescriptorSet set; + anv_AllocDescriptorSets(anv_device_to_handle(device), dummy_desc_pool, + VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, + 1, &device->meta_state.blit.ds_layout, &set, &count); + anv_UpdateDescriptorSets(anv_device_to_handle(device), + 1, /* writeCount */ + (VkWriteDescriptorSet[]) { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .destSet = set, + .destBinding = 0, + .destArrayElement = 0, + .count = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pDescriptors = (VkDescriptorInfo[]) { + { + .imageView = anv_image_view_to_handle(src), + .imageLayout = VK_IMAGE_LAYOUT_GENERAL + }, + } + } + }, 0, NULL); + + VkFramebuffer fb; + anv_CreateFramebuffer(anv_device_to_handle(device), + &(VkFramebufferCreateInfo) { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = (VkAttachmentBindInfo[]) { + { + .view = anv_attachment_view_to_handle(&dest->base), + .layout = VK_IMAGE_LAYOUT_GENERAL + } + }, + .width = dest->base.extent.width, + .height = dest->base.extent.height, + .layers = 1 + }, &fb); + + VkRenderPass pass; + anv_CreateRenderPass(anv_device_to_handle(device), + &(VkRenderPassCreateInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &(VkAttachmentDescription) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, + .format = dest->view.format, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_GENERAL, + .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + }, + .subpassCount = 1, + .pSubpasses = &(VkSubpassDescription) { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputCount = 0, + .colorCount = 1, + .colorAttachments = &(VkAttachmentReference) { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + .resolveAttachments = NULL, + .depthStencilAttachment = (VkAttachmentReference) { + .attachment = VK_ATTACHMENT_UNUSED, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + .preserveCount = 1, + .preserveAttachments = &(VkAttachmentReference) { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + }, + .dependencyCount = 0, + }, &pass); + + anv_CmdBeginRenderPass(anv_cmd_buffer_to_handle(cmd_buffer), + &(VkRenderPassBeginInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = pass, + .framebuffer = fb, + .renderArea = { + .offset = { dest_offset.x, dest_offset.y }, + .extent = { dest_extent.width, dest_extent.height }, + }, + .attachmentCount = 1, + .pAttachmentClearValues = NULL, + }, VK_RENDER_PASS_CONTENTS_INLINE); + + anv_CmdBindDynamicViewportState(anv_cmd_buffer_to_handle(cmd_buffer), + anv_framebuffer_from_handle(fb)->vp_state); + + anv_CmdBindDescriptorSets(anv_cmd_buffer_to_handle(cmd_buffer), + VK_PIPELINE_BIND_POINT_GRAPHICS, + device->meta_state.blit.pipeline_layout, 0, 1, + &set, 0, NULL); + + anv_CmdDraw(anv_cmd_buffer_to_handle(cmd_buffer), 0, 3, 0, 1); + + anv_CmdEndRenderPass(anv_cmd_buffer_to_handle(cmd_buffer)); + + /* At the point where we emit the draw call, all data from the + * descriptor sets, etc. has been used. We are free to delete it. + */ + anv_descriptor_set_destroy(device, anv_descriptor_set_from_handle(set)); + anv_DestroyFramebuffer(anv_device_to_handle(device), fb); + anv_DestroyRenderPass(anv_device_to_handle(device), pass); +} + +static void +meta_finish_blit(struct anv_cmd_buffer *cmd_buffer, + const struct anv_saved_state *saved_state) +{ + anv_cmd_buffer_restore(cmd_buffer, saved_state); + anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), + saved_state->cb_state); +} + +static VkFormat +vk_format_for_cpp(int cpp) +{ + switch (cpp) { + case 1: return VK_FORMAT_R8_UINT; + case 2: return VK_FORMAT_R8G8_UINT; + case 3: return VK_FORMAT_R8G8B8_UINT; + case 4: return VK_FORMAT_R8G8B8A8_UINT; + case 6: return VK_FORMAT_R16G16B16_UINT; + case 8: return VK_FORMAT_R16G16B16A16_UINT; + case 12: return VK_FORMAT_R32G32B32_UINT; + case 16: return VK_FORMAT_R32G32B32A32_UINT; + default: + unreachable("Invalid format cpp"); + } +} + +static void +do_buffer_copy(struct anv_cmd_buffer *cmd_buffer, + struct anv_bo *src, uint64_t src_offset, + struct anv_bo *dest, uint64_t dest_offset, + int width, int height, VkFormat copy_format) +{ + VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); + + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = copy_format, + .extent = { + .width = width, + .height = height, + .depth = 1, + }, + .mipLevels = 1, + .arraySize = 1, + .samples = 1, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT, + .flags = 0, + }; + + VkImage src_image, dest_image; + anv_CreateImage(vk_device, &image_info, &src_image); + anv_CreateImage(vk_device, &image_info, &dest_image); + + /* We could use a vk call to bind memory, but that would require + * creating a dummy memory object etc. so there's really no point. + */ + anv_image_from_handle(src_image)->bo = src; + anv_image_from_handle(src_image)->offset = src_offset; + anv_image_from_handle(dest_image)->bo = dest; + anv_image_from_handle(dest_image)->offset = dest_offset; + + struct anv_image_view src_view; + anv_image_view_init(&src_view, cmd_buffer->device, + &(VkImageViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = src_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = copy_format, + .channels = { + VK_CHANNEL_SWIZZLE_R, + VK_CHANNEL_SWIZZLE_G, + VK_CHANNEL_SWIZZLE_B, + VK_CHANNEL_SWIZZLE_A + }, + .subresourceRange = { + .aspect = VK_IMAGE_ASPECT_COLOR, + .baseMipLevel = 0, + .mipLevels = 1, + .baseArraySlice = 0, + .arraySize = 1 + }, + }, + cmd_buffer); + + struct anv_color_attachment_view dest_view; + anv_color_attachment_view_init(&dest_view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = dest_image, + .format = copy_format, + .mipLevel = 0, + .baseArraySlice = 0, + .arraySize = 1, + }, + cmd_buffer); + + meta_emit_blit(cmd_buffer, + &src_view, + (VkOffset3D) { 0, 0, 0 }, + (VkExtent3D) { width, height, 1 }, + &dest_view, + (VkOffset3D) { 0, 0, 0 }, + (VkExtent3D) { width, height, 1 }); + + anv_DestroyImage(vk_device, src_image); + anv_DestroyImage(vk_device, dest_image); +} + +void anv_CmdCopyBuffer( + VkCmdBuffer cmdBuffer, + VkBuffer srcBuffer, + VkBuffer destBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_buffer, src_buffer, srcBuffer); + ANV_FROM_HANDLE(anv_buffer, dest_buffer, destBuffer); + + struct anv_saved_state saved_state; + + meta_prepare_blit(cmd_buffer, &saved_state); + + for (unsigned r = 0; r < regionCount; r++) { + uint64_t src_offset = src_buffer->offset + pRegions[r].srcOffset; + uint64_t dest_offset = dest_buffer->offset + pRegions[r].destOffset; + uint64_t copy_size = pRegions[r].copySize; + + /* First, we compute the biggest format that can be used with the + * given offsets and size. + */ + int cpp = 16; + + int fs = ffs(src_offset) - 1; + if (fs != -1) + cpp = MIN2(cpp, 1 << fs); + assert(src_offset % cpp == 0); + + fs = ffs(dest_offset) - 1; + if (fs != -1) + cpp = MIN2(cpp, 1 << fs); + assert(dest_offset % cpp == 0); + + fs = ffs(pRegions[r].copySize) - 1; + if (fs != -1) + cpp = MIN2(cpp, 1 << fs); + assert(pRegions[r].copySize % cpp == 0); + + VkFormat copy_format = vk_format_for_cpp(cpp); + + /* This is maximum possible width/height our HW can handle */ + uint64_t max_surface_dim = 1 << 14; + + /* First, we make a bunch of max-sized copies */ + uint64_t max_copy_size = max_surface_dim * max_surface_dim * cpp; + while (copy_size > max_copy_size) { + do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, + dest_buffer->bo, dest_offset, + max_surface_dim, max_surface_dim, copy_format); + copy_size -= max_copy_size; + src_offset += max_copy_size; + dest_offset += max_copy_size; + } + + uint64_t height = copy_size / (max_surface_dim * cpp); + assert(height < max_surface_dim); + if (height != 0) { + uint64_t rect_copy_size = height * max_surface_dim * cpp; + do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, + dest_buffer->bo, dest_offset, + max_surface_dim, height, copy_format); + copy_size -= rect_copy_size; + src_offset += rect_copy_size; + dest_offset += rect_copy_size; + } + + if (copy_size != 0) { + do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, + dest_buffer->bo, dest_offset, + copy_size / cpp, 1, copy_format); + } + } + + meta_finish_blit(cmd_buffer, &saved_state); +} + +void anv_CmdCopyImage( + VkCmdBuffer cmdBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_image, src_image, srcImage); + + struct anv_saved_state saved_state; + + meta_prepare_blit(cmd_buffer, &saved_state); + + for (unsigned r = 0; r < regionCount; r++) { + struct anv_image_view src_view; + anv_image_view_init(&src_view, cmd_buffer->device, + &(VkImageViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = srcImage, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = src_image->format, + .channels = { + VK_CHANNEL_SWIZZLE_R, + VK_CHANNEL_SWIZZLE_G, + VK_CHANNEL_SWIZZLE_B, + VK_CHANNEL_SWIZZLE_A + }, + .subresourceRange = { + .aspect = pRegions[r].srcSubresource.aspect, + .baseMipLevel = pRegions[r].srcSubresource.mipLevel, + .mipLevels = 1, + .baseArraySlice = pRegions[r].srcSubresource.arraySlice, + .arraySize = 1 + }, + }, + cmd_buffer); + + struct anv_color_attachment_view dest_view; + anv_color_attachment_view_init(&dest_view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = destImage, + .format = src_image->format, + .mipLevel = pRegions[r].destSubresource.mipLevel, + .baseArraySlice = pRegions[r].destSubresource.arraySlice, + .arraySize = 1, + }, + cmd_buffer); + + meta_emit_blit(cmd_buffer, + &src_view, + pRegions[r].srcOffset, + pRegions[r].extent, + &dest_view, + pRegions[r].destOffset, + pRegions[r].extent); + } + + meta_finish_blit(cmd_buffer, &saved_state); +} + +void anv_CmdBlitImage( + VkCmdBuffer cmdBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkTexFilter filter) + +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_image, src_image, srcImage); + ANV_FROM_HANDLE(anv_image, dest_image, destImage); + + struct anv_saved_state saved_state; + + anv_finishme("respect VkTexFilter"); + + meta_prepare_blit(cmd_buffer, &saved_state); + + for (unsigned r = 0; r < regionCount; r++) { + struct anv_image_view src_view; + anv_image_view_init(&src_view, cmd_buffer->device, + &(VkImageViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = srcImage, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = src_image->format, + .channels = { + VK_CHANNEL_SWIZZLE_R, + VK_CHANNEL_SWIZZLE_G, + VK_CHANNEL_SWIZZLE_B, + VK_CHANNEL_SWIZZLE_A + }, + .subresourceRange = { + .aspect = pRegions[r].srcSubresource.aspect, + .baseMipLevel = pRegions[r].srcSubresource.mipLevel, + .mipLevels = 1, + .baseArraySlice = pRegions[r].srcSubresource.arraySlice, + .arraySize = 1 + }, + }, + cmd_buffer); + + struct anv_color_attachment_view dest_view; + anv_color_attachment_view_init(&dest_view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = destImage, + .format = dest_image->format, + .mipLevel = pRegions[r].destSubresource.mipLevel, + .baseArraySlice = pRegions[r].destSubresource.arraySlice, + .arraySize = 1, + }, + cmd_buffer); + + meta_emit_blit(cmd_buffer, + &src_view, + pRegions[r].srcOffset, + pRegions[r].srcExtent, + &dest_view, + pRegions[r].destOffset, + pRegions[r].destExtent); + } + + meta_finish_blit(cmd_buffer, &saved_state); +} + +void anv_CmdCopyBufferToImage( + VkCmdBuffer cmdBuffer, + VkBuffer srcBuffer, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_buffer, src_buffer, srcBuffer); + ANV_FROM_HANDLE(anv_image, dest_image, destImage); + VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); + struct anv_saved_state saved_state; + + meta_prepare_blit(cmd_buffer, &saved_state); + + for (unsigned r = 0; r < regionCount; r++) { + if (pRegions[r].bufferRowLength != 0) + anv_finishme("bufferRowLength not supported in CopyBufferToImage"); + if (pRegions[r].bufferImageHeight != 0) + anv_finishme("bufferImageHeight not supported in CopyBufferToImage"); + + VkImage srcImage; + anv_CreateImage(vk_device, + &(VkImageCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = dest_image->format, + .extent = { + .width = pRegions[r].imageExtent.width, + .height = pRegions[r].imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arraySize = 1, + .samples = 1, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT, + .flags = 0, + }, &srcImage); + + ANV_FROM_HANDLE(anv_image, src_image, srcImage); + + /* We could use a vk call to bind memory, but that would require + * creating a dummy memory object etc. so there's really no point. + */ + src_image->bo = src_buffer->bo; + src_image->offset = src_buffer->offset + pRegions[r].bufferOffset; + + struct anv_image_view src_view; + anv_image_view_init(&src_view, cmd_buffer->device, + &(VkImageViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = anv_image_to_handle(src_image), + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = dest_image->format, + .channels = { + VK_CHANNEL_SWIZZLE_R, + VK_CHANNEL_SWIZZLE_G, + VK_CHANNEL_SWIZZLE_B, + VK_CHANNEL_SWIZZLE_A + }, + .subresourceRange = { + .aspect = pRegions[r].imageSubresource.aspect, + .baseMipLevel = 0, + .mipLevels = 1, + .baseArraySlice = 0, + .arraySize = 1 + }, + }, + cmd_buffer); + + struct anv_color_attachment_view dest_view; + anv_color_attachment_view_init(&dest_view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = anv_image_to_handle(dest_image), + .format = dest_image->format, + .mipLevel = pRegions[r].imageSubresource.mipLevel, + .baseArraySlice = pRegions[r].imageSubresource.arraySlice, + .arraySize = 1, + }, + cmd_buffer); + + meta_emit_blit(cmd_buffer, + &src_view, + (VkOffset3D) { 0, 0, 0 }, + pRegions[r].imageExtent, + &dest_view, + pRegions[r].imageOffset, + pRegions[r].imageExtent); + + anv_DestroyImage(vk_device, srcImage); + } + + meta_finish_blit(cmd_buffer, &saved_state); +} + +void anv_CmdCopyImageToBuffer( + VkCmdBuffer cmdBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer destBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_image, src_image, srcImage); + ANV_FROM_HANDLE(anv_buffer, dest_buffer, destBuffer); + VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); + struct anv_saved_state saved_state; + + meta_prepare_blit(cmd_buffer, &saved_state); + + for (unsigned r = 0; r < regionCount; r++) { + if (pRegions[r].bufferRowLength != 0) + anv_finishme("bufferRowLength not supported in CopyBufferToImage"); + if (pRegions[r].bufferImageHeight != 0) + anv_finishme("bufferImageHeight not supported in CopyBufferToImage"); + + struct anv_image_view src_view; + anv_image_view_init(&src_view, cmd_buffer->device, + &(VkImageViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = srcImage, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = src_image->format, + .channels = { + VK_CHANNEL_SWIZZLE_R, + VK_CHANNEL_SWIZZLE_G, + VK_CHANNEL_SWIZZLE_B, + VK_CHANNEL_SWIZZLE_A + }, + .subresourceRange = { + .aspect = pRegions[r].imageSubresource.aspect, + .baseMipLevel = pRegions[r].imageSubresource.mipLevel, + .mipLevels = 1, + .baseArraySlice = pRegions[r].imageSubresource.arraySlice, + .arraySize = 1 + }, + }, + cmd_buffer); + + VkImage destImage; + anv_CreateImage(vk_device, + &(VkImageCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = src_image->format, + .extent = { + .width = pRegions[r].imageExtent.width, + .height = pRegions[r].imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arraySize = 1, + .samples = 1, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT, + .flags = 0, + }, &destImage); + + ANV_FROM_HANDLE(anv_image, dest_image, destImage); + + /* We could use a vk call to bind memory, but that would require + * creating a dummy memory object etc. so there's really no point. + */ + dest_image->bo = dest_buffer->bo; + dest_image->offset = dest_buffer->offset + pRegions[r].bufferOffset; + + struct anv_color_attachment_view dest_view; + anv_color_attachment_view_init(&dest_view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = destImage, + .format = src_image->format, + .mipLevel = 0, + .baseArraySlice = 0, + .arraySize = 1, + }, + cmd_buffer); + + meta_emit_blit(cmd_buffer, + &src_view, + pRegions[r].imageOffset, + pRegions[r].imageExtent, + &dest_view, + (VkOffset3D) { 0, 0, 0 }, + pRegions[r].imageExtent); + + anv_DestroyImage(vk_device, destImage); + } + + meta_finish_blit(cmd_buffer, &saved_state); +} + +void anv_CmdUpdateBuffer( + VkCmdBuffer cmdBuffer, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize dataSize, + const uint32_t* pData) +{ + stub(); +} + +void anv_CmdFillBuffer( + VkCmdBuffer cmdBuffer, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize fillSize, + uint32_t data) +{ + stub(); +} + +void anv_CmdClearColorImage( + VkCmdBuffer cmdBuffer, + VkImage _image, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_image, image, _image); + struct anv_saved_state saved_state; + + anv_cmd_buffer_save(cmd_buffer, &saved_state); + + for (uint32_t r = 0; r < rangeCount; r++) { + for (uint32_t l = 0; l < pRanges[r].mipLevels; l++) { + for (uint32_t s = 0; s < pRanges[r].arraySize; s++) { + struct anv_color_attachment_view view; + anv_color_attachment_view_init(&view, cmd_buffer->device, + &(VkAttachmentViewCreateInfo) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, + .image = _image, + .format = image->format, + .mipLevel = pRanges[r].baseMipLevel + l, + .baseArraySlice = pRanges[r].baseArraySlice + s, + .arraySize = 1, + }, + cmd_buffer); + + VkFramebuffer fb; + anv_CreateFramebuffer(anv_device_to_handle(cmd_buffer->device), + &(VkFramebufferCreateInfo) { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = (VkAttachmentBindInfo[]) { + { + .view = anv_attachment_view_to_handle(&view.base), + .layout = VK_IMAGE_LAYOUT_GENERAL + } + }, + .width = view.base.extent.width, + .height = view.base.extent.height, + .layers = 1 + }, &fb); + + VkRenderPass pass; + anv_CreateRenderPass(anv_device_to_handle(cmd_buffer->device), + &(VkRenderPassCreateInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &(VkAttachmentDescription) { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, + .format = view.view.format, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_GENERAL, + .finalLayout = VK_IMAGE_LAYOUT_GENERAL, + }, + .subpassCount = 1, + .pSubpasses = &(VkSubpassDescription) { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputCount = 0, + .colorCount = 1, + .colorAttachments = &(VkAttachmentReference) { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + .resolveAttachments = NULL, + .depthStencilAttachment = (VkAttachmentReference) { + .attachment = VK_ATTACHMENT_UNUSED, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + .preserveCount = 1, + .preserveAttachments = &(VkAttachmentReference) { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_GENERAL, + }, + }, + .dependencyCount = 0, + }, &pass); + + anv_CmdBeginRenderPass(anv_cmd_buffer_to_handle(cmd_buffer), + &(VkRenderPassBeginInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderArea = { + .offset = { 0, 0, }, + .extent = { + .width = view.base.extent.width, + .height = view.base.extent.height, + }, + }, + .renderPass = pass, + .framebuffer = fb, + .attachmentCount = 1, + .pAttachmentClearValues = NULL, + }, VK_RENDER_PASS_CONTENTS_INLINE); + + struct clear_instance_data instance_data = { + .vue_header = { + .RTAIndex = 0, + .ViewportIndex = 0, + .PointWidth = 0.0 + }, + .color = *pColor, + }; + + meta_emit_clear(cmd_buffer, 1, &instance_data); + + anv_CmdEndRenderPass(anv_cmd_buffer_to_handle(cmd_buffer)); + } + } + } + + /* Restore API state */ + anv_cmd_buffer_restore(cmd_buffer, &saved_state); +} + +void anv_CmdClearDepthStencilImage( + VkCmdBuffer cmdBuffer, + VkImage image, + VkImageLayout imageLayout, + float depth, + uint32_t stencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges) +{ + stub(); +} + +void anv_CmdClearColorAttachment( + VkCmdBuffer cmdBuffer, + uint32_t colorAttachment, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rectCount, + const VkRect3D* pRects) +{ + stub(); +} + +void anv_CmdClearDepthStencilAttachment( + VkCmdBuffer cmdBuffer, + VkImageAspectFlags imageAspectMask, + VkImageLayout imageLayout, + float depth, + uint32_t stencil, + uint32_t rectCount, + const VkRect3D* pRects) +{ + stub(); +} + +void anv_CmdResolveImage( + VkCmdBuffer cmdBuffer, + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage destImage, + VkImageLayout destImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions) +{ + stub(); +} + +void +anv_device_init_meta(struct anv_device *device) +{ + anv_device_init_meta_clear_state(device); + anv_device_init_meta_blit_state(device); + + anv_CreateDynamicRasterState(anv_device_to_handle(device), + &(VkDynamicRasterStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DYNAMIC_RASTER_STATE_CREATE_INFO, + }, + &device->meta_state.shared.rs_state); + + anv_CreateDynamicColorBlendState(anv_device_to_handle(device), + &(VkDynamicColorBlendStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DYNAMIC_COLOR_BLEND_STATE_CREATE_INFO + }, + &device->meta_state.shared.cb_state); + + anv_CreateDynamicDepthStencilState(anv_device_to_handle(device), + &(VkDynamicDepthStencilStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_STENCIL_STATE_CREATE_INFO + }, + &device->meta_state.shared.ds_state); +} + +void +anv_device_finish_meta(struct anv_device *device) +{ + /* Clear */ + anv_DestroyPipeline(anv_device_to_handle(device), + device->meta_state.clear.pipeline); + + /* Blit */ + anv_DestroyPipeline(anv_device_to_handle(device), + device->meta_state.blit.pipeline); + anv_DestroyPipelineLayout(anv_device_to_handle(device), + device->meta_state.blit.pipeline_layout); + anv_DestroyDescriptorSetLayout(anv_device_to_handle(device), + device->meta_state.blit.ds_layout); + + /* Shared */ + anv_DestroyDynamicRasterState(anv_device_to_handle(device), + device->meta_state.shared.rs_state); + anv_DestroyDynamicColorBlendState(anv_device_to_handle(device), + device->meta_state.shared.cb_state); + anv_DestroyDynamicDepthStencilState(anv_device_to_handle(device), + device->meta_state.shared.ds_state); +} diff --git a/src/vulkan/anv_pipeline.c b/src/vulkan/anv_pipeline.c new file mode 100644 index 00000000000..817b644eefb --- /dev/null +++ b/src/vulkan/anv_pipeline.c @@ -0,0 +1,950 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" + +// Shader functions + +VkResult anv_CreateShaderModule( + VkDevice _device, + const VkShaderModuleCreateInfo* pCreateInfo, + VkShaderModule* pShaderModule) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_shader_module *module; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); + assert(pCreateInfo->flags == 0); + + module = anv_device_alloc(device, sizeof(*module) + pCreateInfo->codeSize, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (module == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + module->size = pCreateInfo->codeSize; + memcpy(module->data, pCreateInfo->pCode, module->size); + + *pShaderModule = anv_shader_module_to_handle(module); + + return VK_SUCCESS; +} + +VkResult anv_DestroyShaderModule( + VkDevice _device, + VkShaderModule _module) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_shader_module, module, _module); + + anv_device_free(device, module); + + return VK_SUCCESS; +} + +VkResult anv_CreateShader( + VkDevice _device, + const VkShaderCreateInfo* pCreateInfo, + VkShader* pShader) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_shader_module, module, pCreateInfo->module); + struct anv_shader *shader; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_CREATE_INFO); + assert(pCreateInfo->flags == 0); + + size_t name_len = strlen(pCreateInfo->pName); + + if (strcmp(pCreateInfo->pName, "main") != 0) { + anv_finishme("Multiple shaders per module not really supported"); + } + + shader = anv_device_alloc(device, sizeof(*shader) + name_len + 1, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (shader == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + shader->module = module; + memcpy(shader->entrypoint, pCreateInfo->pName, name_len + 1); + + *pShader = anv_shader_to_handle(shader); + + return VK_SUCCESS; +} + +VkResult anv_DestroyShader( + VkDevice _device, + VkShader _shader) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_shader, shader, _shader); + + anv_device_free(device, shader); + + return VK_SUCCESS; +} + + +VkResult anv_CreatePipelineCache( + VkDevice device, + const VkPipelineCacheCreateInfo* pCreateInfo, + VkPipelineCache* pPipelineCache) +{ + pPipelineCache->handle = 1; + + stub_return(VK_SUCCESS); +} + +VkResult anv_DestroyPipelineCache( + VkDevice _device, + VkPipelineCache _cache) +{ + /* VkPipelineCache is a dummy object. */ + return VK_SUCCESS; +} + +size_t anv_GetPipelineCacheSize( + VkDevice device, + VkPipelineCache pipelineCache) +{ + stub_return(0); +} + +VkResult anv_GetPipelineCacheData( + VkDevice device, + VkPipelineCache pipelineCache, + void* pData) +{ + stub_return(VK_UNSUPPORTED); +} + +VkResult anv_MergePipelineCaches( + VkDevice device, + VkPipelineCache destCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches) +{ + stub_return(VK_UNSUPPORTED); +} + +// Pipeline functions + +static void +emit_vertex_input(struct anv_pipeline *pipeline, + const VkPipelineVertexInputStateCreateInfo *info) +{ + const uint32_t num_dwords = 1 + info->attributeCount * 2; + uint32_t *p; + bool instancing_enable[32]; + + pipeline->vb_used = 0; + for (uint32_t i = 0; i < info->bindingCount; i++) { + const VkVertexInputBindingDescription *desc = + &info->pVertexBindingDescriptions[i]; + + pipeline->vb_used |= 1 << desc->binding; + pipeline->binding_stride[desc->binding] = desc->strideInBytes; + + /* Step rate is programmed per vertex element (attribute), not + * binding. Set up a map of which bindings step per instance, for + * reference by vertex element setup. */ + switch (desc->stepRate) { + default: + case VK_VERTEX_INPUT_STEP_RATE_VERTEX: + instancing_enable[desc->binding] = false; + break; + case VK_VERTEX_INPUT_STEP_RATE_INSTANCE: + instancing_enable[desc->binding] = true; + break; + } + } + + p = anv_batch_emitn(&pipeline->batch, num_dwords, + GEN8_3DSTATE_VERTEX_ELEMENTS); + + for (uint32_t i = 0; i < info->attributeCount; i++) { + const VkVertexInputAttributeDescription *desc = + &info->pVertexAttributeDescriptions[i]; + const struct anv_format *format = anv_format_for_vk_format(desc->format); + + struct GEN8_VERTEX_ELEMENT_STATE element = { + .VertexBufferIndex = desc->binding, + .Valid = true, + .SourceElementFormat = format->surface_format, + .EdgeFlagEnable = false, + .SourceElementOffset = desc->offsetInBytes, + .Component0Control = VFCOMP_STORE_SRC, + .Component1Control = format->num_channels >= 2 ? VFCOMP_STORE_SRC : VFCOMP_STORE_0, + .Component2Control = format->num_channels >= 3 ? VFCOMP_STORE_SRC : VFCOMP_STORE_0, + .Component3Control = format->num_channels >= 4 ? VFCOMP_STORE_SRC : VFCOMP_STORE_1_FP + }; + GEN8_VERTEX_ELEMENT_STATE_pack(NULL, &p[1 + i * 2], &element); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_INSTANCING, + .InstancingEnable = instancing_enable[desc->binding], + .VertexElementIndex = i, + /* Vulkan so far doesn't have an instance divisor, so + * this is always 1 (ignored if not instancing). */ + .InstanceDataStepRate = 1); + } + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_SGVS, + .VertexIDEnable = pipeline->vs_prog_data.uses_vertexid, + .VertexIDComponentNumber = 2, + .VertexIDElementOffset = info->bindingCount, + .InstanceIDEnable = pipeline->vs_prog_data.uses_instanceid, + .InstanceIDComponentNumber = 3, + .InstanceIDElementOffset = info->bindingCount); +} + +static void +emit_ia_state(struct anv_pipeline *pipeline, + const VkPipelineInputAssemblyStateCreateInfo *info, + const struct anv_pipeline_create_info *extra) +{ + static const uint32_t vk_to_gen_primitive_type[] = { + [VK_PRIMITIVE_TOPOLOGY_POINT_LIST] = _3DPRIM_POINTLIST, + [VK_PRIMITIVE_TOPOLOGY_LINE_LIST] = _3DPRIM_LINELIST, + [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP] = _3DPRIM_LINESTRIP, + [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST] = _3DPRIM_TRILIST, + [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP] = _3DPRIM_TRISTRIP, + [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN] = _3DPRIM_TRIFAN, + [VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ] = _3DPRIM_LINELIST_ADJ, + [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ] = _3DPRIM_LINESTRIP_ADJ, + [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ] = _3DPRIM_TRILIST_ADJ, + [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ] = _3DPRIM_TRISTRIP_ADJ, + [VK_PRIMITIVE_TOPOLOGY_PATCH] = _3DPRIM_PATCHLIST_1 + }; + uint32_t topology = vk_to_gen_primitive_type[info->topology]; + + if (extra && extra->use_rectlist) + topology = _3DPRIM_RECTLIST; + + struct GEN8_3DSTATE_VF vf = { + GEN8_3DSTATE_VF_header, + .IndexedDrawCutIndexEnable = info->primitiveRestartEnable, + }; + GEN8_3DSTATE_VF_pack(NULL, pipeline->state_vf, &vf); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_TOPOLOGY, + .PrimitiveTopologyType = topology); +} + +static void +emit_rs_state(struct anv_pipeline *pipeline, + const VkPipelineRasterStateCreateInfo *info, + const struct anv_pipeline_create_info *extra) +{ + static const uint32_t vk_to_gen_cullmode[] = { + [VK_CULL_MODE_NONE] = CULLMODE_NONE, + [VK_CULL_MODE_FRONT] = CULLMODE_FRONT, + [VK_CULL_MODE_BACK] = CULLMODE_BACK, + [VK_CULL_MODE_FRONT_AND_BACK] = CULLMODE_BOTH + }; + + static const uint32_t vk_to_gen_fillmode[] = { + [VK_FILL_MODE_POINTS] = RASTER_POINT, + [VK_FILL_MODE_WIREFRAME] = RASTER_WIREFRAME, + [VK_FILL_MODE_SOLID] = RASTER_SOLID + }; + + static const uint32_t vk_to_gen_front_face[] = { + [VK_FRONT_FACE_CCW] = CounterClockwise, + [VK_FRONT_FACE_CW] = Clockwise + }; + + struct GEN8_3DSTATE_SF sf = { + GEN8_3DSTATE_SF_header, + .ViewportTransformEnable = !(extra && extra->disable_viewport), + .TriangleStripListProvokingVertexSelect = 0, + .LineStripListProvokingVertexSelect = 0, + .TriangleFanProvokingVertexSelect = 0, + .PointWidthSource = pipeline->writes_point_size ? Vertex : State, + .PointWidth = 1.0, + }; + + /* FINISHME: VkBool32 rasterizerDiscardEnable; */ + + GEN8_3DSTATE_SF_pack(NULL, pipeline->state_sf, &sf); + + struct GEN8_3DSTATE_RASTER raster = { + GEN8_3DSTATE_RASTER_header, + .FrontWinding = vk_to_gen_front_face[info->frontFace], + .CullMode = vk_to_gen_cullmode[info->cullMode], + .FrontFaceFillMode = vk_to_gen_fillmode[info->fillMode], + .BackFaceFillMode = vk_to_gen_fillmode[info->fillMode], + .ScissorRectangleEnable = !(extra && extra->disable_scissor), + .ViewportZClipTestEnable = info->depthClipEnable + }; + + GEN8_3DSTATE_RASTER_pack(NULL, pipeline->state_raster, &raster); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SBE, + .ForceVertexURBEntryReadLength = false, + .ForceVertexURBEntryReadOffset = false, + .PointSpriteTextureCoordinateOrigin = UPPERLEFT, + .NumberofSFOutputAttributes = + pipeline->wm_prog_data.num_varying_inputs); + +} + +static void +emit_cb_state(struct anv_pipeline *pipeline, + const VkPipelineColorBlendStateCreateInfo *info) +{ + struct anv_device *device = pipeline->device; + + static const uint32_t vk_to_gen_logic_op[] = { + [VK_LOGIC_OP_COPY] = LOGICOP_COPY, + [VK_LOGIC_OP_CLEAR] = LOGICOP_CLEAR, + [VK_LOGIC_OP_AND] = LOGICOP_AND, + [VK_LOGIC_OP_AND_REVERSE] = LOGICOP_AND_REVERSE, + [VK_LOGIC_OP_AND_INVERTED] = LOGICOP_AND_INVERTED, + [VK_LOGIC_OP_NOOP] = LOGICOP_NOOP, + [VK_LOGIC_OP_XOR] = LOGICOP_XOR, + [VK_LOGIC_OP_OR] = LOGICOP_OR, + [VK_LOGIC_OP_NOR] = LOGICOP_NOR, + [VK_LOGIC_OP_EQUIV] = LOGICOP_EQUIV, + [VK_LOGIC_OP_INVERT] = LOGICOP_INVERT, + [VK_LOGIC_OP_OR_REVERSE] = LOGICOP_OR_REVERSE, + [VK_LOGIC_OP_COPY_INVERTED] = LOGICOP_COPY_INVERTED, + [VK_LOGIC_OP_OR_INVERTED] = LOGICOP_OR_INVERTED, + [VK_LOGIC_OP_NAND] = LOGICOP_NAND, + [VK_LOGIC_OP_SET] = LOGICOP_SET, + }; + + static const uint32_t vk_to_gen_blend[] = { + [VK_BLEND_ZERO] = BLENDFACTOR_ZERO, + [VK_BLEND_ONE] = BLENDFACTOR_ONE, + [VK_BLEND_SRC_COLOR] = BLENDFACTOR_SRC_COLOR, + [VK_BLEND_ONE_MINUS_SRC_COLOR] = BLENDFACTOR_INV_SRC_COLOR, + [VK_BLEND_DEST_COLOR] = BLENDFACTOR_DST_COLOR, + [VK_BLEND_ONE_MINUS_DEST_COLOR] = BLENDFACTOR_INV_DST_COLOR, + [VK_BLEND_SRC_ALPHA] = BLENDFACTOR_SRC_ALPHA, + [VK_BLEND_ONE_MINUS_SRC_ALPHA] = BLENDFACTOR_INV_SRC_ALPHA, + [VK_BLEND_DEST_ALPHA] = BLENDFACTOR_DST_ALPHA, + [VK_BLEND_ONE_MINUS_DEST_ALPHA] = BLENDFACTOR_INV_DST_ALPHA, + [VK_BLEND_CONSTANT_COLOR] = BLENDFACTOR_CONST_COLOR, + [VK_BLEND_ONE_MINUS_CONSTANT_COLOR] = BLENDFACTOR_INV_CONST_COLOR, + [VK_BLEND_CONSTANT_ALPHA] = BLENDFACTOR_CONST_ALPHA, + [VK_BLEND_ONE_MINUS_CONSTANT_ALPHA] = BLENDFACTOR_INV_CONST_ALPHA, + [VK_BLEND_SRC_ALPHA_SATURATE] = BLENDFACTOR_SRC_ALPHA_SATURATE, + [VK_BLEND_SRC1_COLOR] = BLENDFACTOR_SRC1_COLOR, + [VK_BLEND_ONE_MINUS_SRC1_COLOR] = BLENDFACTOR_INV_SRC1_COLOR, + [VK_BLEND_SRC1_ALPHA] = BLENDFACTOR_SRC1_ALPHA, + [VK_BLEND_ONE_MINUS_SRC1_ALPHA] = BLENDFACTOR_INV_SRC1_ALPHA, + }; + + static const uint32_t vk_to_gen_blend_op[] = { + [VK_BLEND_OP_ADD] = BLENDFUNCTION_ADD, + [VK_BLEND_OP_SUBTRACT] = BLENDFUNCTION_SUBTRACT, + [VK_BLEND_OP_REVERSE_SUBTRACT] = BLENDFUNCTION_REVERSE_SUBTRACT, + [VK_BLEND_OP_MIN] = BLENDFUNCTION_MIN, + [VK_BLEND_OP_MAX] = BLENDFUNCTION_MAX, + }; + + uint32_t num_dwords = 1 + info->attachmentCount * 2; + pipeline->blend_state = + anv_state_pool_alloc(&device->dynamic_state_pool, num_dwords * 4, 64); + + struct GEN8_BLEND_STATE blend_state = { + .AlphaToCoverageEnable = info->alphaToCoverageEnable, + }; + + uint32_t *state = pipeline->blend_state.map; + GEN8_BLEND_STATE_pack(NULL, state, &blend_state); + + for (uint32_t i = 0; i < info->attachmentCount; i++) { + const VkPipelineColorBlendAttachmentState *a = &info->pAttachments[i]; + + struct GEN8_BLEND_STATE_ENTRY entry = { + .LogicOpEnable = info->logicOpEnable, + .LogicOpFunction = vk_to_gen_logic_op[info->logicOp], + .ColorBufferBlendEnable = a->blendEnable, + .PreBlendSourceOnlyClampEnable = false, + .PreBlendColorClampEnable = false, + .PostBlendColorClampEnable = false, + .SourceBlendFactor = vk_to_gen_blend[a->srcBlendColor], + .DestinationBlendFactor = vk_to_gen_blend[a->destBlendColor], + .ColorBlendFunction = vk_to_gen_blend_op[a->blendOpColor], + .SourceAlphaBlendFactor = vk_to_gen_blend[a->srcBlendAlpha], + .DestinationAlphaBlendFactor = vk_to_gen_blend[a->destBlendAlpha], + .AlphaBlendFunction = vk_to_gen_blend_op[a->blendOpAlpha], + .WriteDisableAlpha = !(a->channelWriteMask & VK_CHANNEL_A_BIT), + .WriteDisableRed = !(a->channelWriteMask & VK_CHANNEL_R_BIT), + .WriteDisableGreen = !(a->channelWriteMask & VK_CHANNEL_G_BIT), + .WriteDisableBlue = !(a->channelWriteMask & VK_CHANNEL_B_BIT), + }; + + GEN8_BLEND_STATE_ENTRY_pack(NULL, state + i * 2 + 1, &entry); + } + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_BLEND_STATE_POINTERS, + .BlendStatePointer = pipeline->blend_state.offset, + .BlendStatePointerValid = true); +} + +static const uint32_t vk_to_gen_compare_op[] = { + [VK_COMPARE_OP_NEVER] = COMPAREFUNCTION_NEVER, + [VK_COMPARE_OP_LESS] = COMPAREFUNCTION_LESS, + [VK_COMPARE_OP_EQUAL] = COMPAREFUNCTION_EQUAL, + [VK_COMPARE_OP_LESS_EQUAL] = COMPAREFUNCTION_LEQUAL, + [VK_COMPARE_OP_GREATER] = COMPAREFUNCTION_GREATER, + [VK_COMPARE_OP_NOT_EQUAL] = COMPAREFUNCTION_NOTEQUAL, + [VK_COMPARE_OP_GREATER_EQUAL] = COMPAREFUNCTION_GEQUAL, + [VK_COMPARE_OP_ALWAYS] = COMPAREFUNCTION_ALWAYS, +}; + +static const uint32_t vk_to_gen_stencil_op[] = { + [VK_STENCIL_OP_KEEP] = 0, + [VK_STENCIL_OP_ZERO] = 0, + [VK_STENCIL_OP_REPLACE] = 0, + [VK_STENCIL_OP_INC_CLAMP] = 0, + [VK_STENCIL_OP_DEC_CLAMP] = 0, + [VK_STENCIL_OP_INVERT] = 0, + [VK_STENCIL_OP_INC_WRAP] = 0, + [VK_STENCIL_OP_DEC_WRAP] = 0 +}; + +static void +emit_ds_state(struct anv_pipeline *pipeline, + const VkPipelineDepthStencilStateCreateInfo *info) +{ + if (info == NULL) { + /* We're going to OR this together with the dynamic state. We need + * to make sure it's initialized to something useful. + */ + memset(pipeline->state_wm_depth_stencil, 0, + sizeof(pipeline->state_wm_depth_stencil)); + return; + } + + /* VkBool32 depthBoundsEnable; // optional (depth_bounds_test) */ + + struct GEN8_3DSTATE_WM_DEPTH_STENCIL wm_depth_stencil = { + .DepthTestEnable = info->depthTestEnable, + .DepthBufferWriteEnable = info->depthWriteEnable, + .DepthTestFunction = vk_to_gen_compare_op[info->depthCompareOp], + .DoubleSidedStencilEnable = true, + + .StencilTestEnable = info->stencilTestEnable, + .StencilFailOp = vk_to_gen_stencil_op[info->front.stencilFailOp], + .StencilPassDepthPassOp = vk_to_gen_stencil_op[info->front.stencilPassOp], + .StencilPassDepthFailOp = vk_to_gen_stencil_op[info->front.stencilDepthFailOp], + .StencilTestFunction = vk_to_gen_compare_op[info->front.stencilCompareOp], + .BackfaceStencilFailOp = vk_to_gen_stencil_op[info->back.stencilFailOp], + .BackfaceStencilPassDepthPassOp = vk_to_gen_stencil_op[info->back.stencilPassOp], + .BackfaceStencilPassDepthFailOp =vk_to_gen_stencil_op[info->back.stencilDepthFailOp], + .BackfaceStencilTestFunction = vk_to_gen_compare_op[info->back.stencilCompareOp], + }; + + GEN8_3DSTATE_WM_DEPTH_STENCIL_pack(NULL, pipeline->state_wm_depth_stencil, &wm_depth_stencil); +} + +VkResult +anv_pipeline_create( + VkDevice _device, + const VkGraphicsPipelineCreateInfo* pCreateInfo, + const struct anv_pipeline_create_info * extra, + VkPipeline* pPipeline) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_pipeline *pipeline; + VkResult result; + uint32_t offset, length; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO); + + pipeline = anv_device_alloc(device, sizeof(*pipeline), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (pipeline == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + pipeline->device = device; + pipeline->layout = anv_pipeline_layout_from_handle(pCreateInfo->layout); + memset(pipeline->shaders, 0, sizeof(pipeline->shaders)); + + result = anv_reloc_list_init(&pipeline->batch.relocs, device); + if (result != VK_SUCCESS) { + anv_device_free(device, pipeline); + return result; + } + pipeline->batch.next = pipeline->batch.start = pipeline->batch_data; + pipeline->batch.end = pipeline->batch.start + sizeof(pipeline->batch_data); + + anv_state_stream_init(&pipeline->program_stream, + &device->instruction_block_pool); + + for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { + pipeline->shaders[pCreateInfo->pStages[i].stage] = + anv_shader_from_handle(pCreateInfo->pStages[i].shader); + } + + if (pCreateInfo->pTessellationState) + anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO"); + if (pCreateInfo->pViewportState) + anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO"); + if (pCreateInfo->pMultisampleState) + anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO"); + + pipeline->use_repclear = extra && extra->use_repclear; + + anv_compiler_run(device->compiler, pipeline); + + /* FIXME: The compiler dead-codes FS inputs when we don't have a VS, so we + * hard code this to num_attributes - 2. This is because the attributes + * include VUE header and position, which aren't counted as varying + * inputs. */ + if (pipeline->vs_simd8 == NO_KERNEL) { + pipeline->wm_prog_data.num_varying_inputs = + pCreateInfo->pVertexInputState->attributeCount - 2; + } + + assert(pCreateInfo->pVertexInputState); + emit_vertex_input(pipeline, pCreateInfo->pVertexInputState); + assert(pCreateInfo->pInputAssemblyState); + emit_ia_state(pipeline, pCreateInfo->pInputAssemblyState, extra); + assert(pCreateInfo->pRasterState); + emit_rs_state(pipeline, pCreateInfo->pRasterState, extra); + emit_ds_state(pipeline, pCreateInfo->pDepthStencilState); + emit_cb_state(pipeline, pCreateInfo->pColorBlendState); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_STATISTICS, + .StatisticsEnable = true); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_HS, .Enable = false); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_TE, .TEEnable = false); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_DS, .FunctionEnable = false); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_STREAMOUT, .SOFunctionEnable = false); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_VS, + .ConstantBufferOffset = 0, + .ConstantBufferSize = 4); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_GS, + .ConstantBufferOffset = 4, + .ConstantBufferSize = 4); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_PS, + .ConstantBufferOffset = 8, + .ConstantBufferSize = 4); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_WM_CHROMAKEY, + .ChromaKeyKillEnable = false); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SBE_SWIZ); + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_AA_LINE_PARAMETERS); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_CLIP, + .ClipEnable = true, + .ViewportXYClipTestEnable = !(extra && extra->disable_viewport), + .MinimumPointWidth = 0.125, + .MaximumPointWidth = 255.875); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_WM, + .StatisticsEnable = true, + .LineEndCapAntialiasingRegionWidth = _05pixels, + .LineAntialiasingRegionWidth = _10pixels, + .EarlyDepthStencilControl = NORMAL, + .ForceThreadDispatchEnable = NORMAL, + .PointRasterizationRule = RASTRULE_UPPER_RIGHT, + .BarycentricInterpolationMode = + pipeline->wm_prog_data.barycentric_interp_modes); + + uint32_t samples = 1; + uint32_t log2_samples = __builtin_ffs(samples) - 1; + bool enable_sampling = samples > 1 ? true : false; + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_MULTISAMPLE, + .PixelPositionOffsetEnable = enable_sampling, + .PixelLocation = CENTER, + .NumberofMultisamples = log2_samples); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SAMPLE_MASK, + .SampleMask = 0xffff); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_VS, + .VSURBStartingAddress = pipeline->urb.vs_start, + .VSURBEntryAllocationSize = pipeline->urb.vs_size - 1, + .VSNumberofURBEntries = pipeline->urb.nr_vs_entries); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_GS, + .GSURBStartingAddress = pipeline->urb.gs_start, + .GSURBEntryAllocationSize = pipeline->urb.gs_size - 1, + .GSNumberofURBEntries = pipeline->urb.nr_gs_entries); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_HS, + .HSURBStartingAddress = pipeline->urb.vs_start, + .HSURBEntryAllocationSize = 0, + .HSNumberofURBEntries = 0); + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_DS, + .DSURBStartingAddress = pipeline->urb.vs_start, + .DSURBEntryAllocationSize = 0, + .DSNumberofURBEntries = 0); + + const struct brw_gs_prog_data *gs_prog_data = &pipeline->gs_prog_data; + offset = 1; + length = (gs_prog_data->base.vue_map.num_slots + 1) / 2 - offset; + + if (pipeline->gs_vec4 == NO_KERNEL) + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_GS, .Enable = false); + else + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_GS, + .SingleProgramFlow = false, + .KernelStartPointer = pipeline->gs_vec4, + .VectorMaskEnable = Vmask, + .SamplerCount = 0, + .BindingTableEntryCount = 0, + .ExpectedVertexCount = pipeline->gs_vertex_count, + + .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_GEOMETRY], + .PerThreadScratchSpace = ffs(gs_prog_data->base.base.total_scratch / 2048), + + .OutputVertexSize = gs_prog_data->output_vertex_size_hwords * 2 - 1, + .OutputTopology = gs_prog_data->output_topology, + .VertexURBEntryReadLength = gs_prog_data->base.urb_read_length, + .DispatchGRFStartRegisterForURBData = + gs_prog_data->base.base.dispatch_grf_start_reg, + + .MaximumNumberofThreads = device->info.max_gs_threads, + .ControlDataHeaderSize = gs_prog_data->control_data_header_size_hwords, + //pipeline->gs_prog_data.dispatch_mode | + .StatisticsEnable = true, + .IncludePrimitiveID = gs_prog_data->include_primitive_id, + .ReorderMode = TRAILING, + .Enable = true, + + .ControlDataFormat = gs_prog_data->control_data_format, + + /* FIXME: mesa sets this based on ctx->Transform.ClipPlanesEnabled: + * UserClipDistanceClipTestEnableBitmask_3DSTATE_GS(v) + * UserClipDistanceCullTestEnableBitmask(v) + */ + + .VertexURBEntryOutputReadOffset = offset, + .VertexURBEntryOutputLength = length); + + const struct brw_vue_prog_data *vue_prog_data = &pipeline->vs_prog_data.base; + /* Skip the VUE header and position slots */ + offset = 1; + length = (vue_prog_data->vue_map.num_slots + 1) / 2 - offset; + + if (pipeline->vs_simd8 == NO_KERNEL || (extra && extra->disable_vs)) + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VS, + .FunctionEnable = false, + .VertexURBEntryOutputReadOffset = 1, + /* Even if VS is disabled, SBE still gets the amount of + * vertex data to read from this field. We use attribute + * count - 1, as we don't count the VUE header here. */ + .VertexURBEntryOutputLength = + DIV_ROUND_UP(pCreateInfo->pVertexInputState->attributeCount - 1, 2)); + else + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VS, + .KernelStartPointer = pipeline->vs_simd8, + .SingleVertexDispatch = Multiple, + .VectorMaskEnable = Dmask, + .SamplerCount = 0, + .BindingTableEntryCount = + vue_prog_data->base.binding_table.size_bytes / 4, + .ThreadDispatchPriority = Normal, + .FloatingPointMode = IEEE754, + .IllegalOpcodeExceptionEnable = false, + .AccessesUAV = false, + .SoftwareExceptionEnable = false, + + .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_VERTEX], + .PerThreadScratchSpace = ffs(vue_prog_data->base.total_scratch / 2048), + + .DispatchGRFStartRegisterForURBData = + vue_prog_data->base.dispatch_grf_start_reg, + .VertexURBEntryReadLength = vue_prog_data->urb_read_length, + .VertexURBEntryReadOffset = 0, + + .MaximumNumberofThreads = device->info.max_vs_threads - 1, + .StatisticsEnable = false, + .SIMD8DispatchEnable = true, + .VertexCacheDisable = false, + .FunctionEnable = true, + + .VertexURBEntryOutputReadOffset = offset, + .VertexURBEntryOutputLength = length, + .UserClipDistanceClipTestEnableBitmask = 0, + .UserClipDistanceCullTestEnableBitmask = 0); + + const struct brw_wm_prog_data *wm_prog_data = &pipeline->wm_prog_data; + uint32_t ksp0, ksp2, grf_start0, grf_start2; + + ksp2 = 0; + grf_start2 = 0; + if (pipeline->ps_simd8 != NO_KERNEL) { + ksp0 = pipeline->ps_simd8; + grf_start0 = wm_prog_data->base.dispatch_grf_start_reg; + if (pipeline->ps_simd16 != NO_KERNEL) { + ksp2 = pipeline->ps_simd16; + grf_start2 = wm_prog_data->dispatch_grf_start_reg_16; + } + } else if (pipeline->ps_simd16 != NO_KERNEL) { + ksp0 = pipeline->ps_simd16; + grf_start0 = wm_prog_data->dispatch_grf_start_reg_16; + } else { + unreachable("no ps shader"); + } + + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PS, + .KernelStartPointer0 = ksp0, + + .SingleProgramFlow = false, + .VectorMaskEnable = true, + .SamplerCount = 1, + + .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_FRAGMENT], + .PerThreadScratchSpace = ffs(wm_prog_data->base.total_scratch / 2048), + + .MaximumNumberofThreadsPerPSD = 64 - 2, + .PositionXYOffsetSelect = wm_prog_data->uses_pos_offset ? + POSOFFSET_SAMPLE: POSOFFSET_NONE, + .PushConstantEnable = wm_prog_data->base.nr_params > 0, + ._8PixelDispatchEnable = pipeline->ps_simd8 != NO_KERNEL, + ._16PixelDispatchEnable = pipeline->ps_simd16 != NO_KERNEL, + ._32PixelDispatchEnable = false, + + .DispatchGRFStartRegisterForConstantSetupData0 = grf_start0, + .DispatchGRFStartRegisterForConstantSetupData1 = 0, + .DispatchGRFStartRegisterForConstantSetupData2 = grf_start2, + + .KernelStartPointer1 = 0, + .KernelStartPointer2 = ksp2); + + bool per_sample_ps = false; + anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PS_EXTRA, + .PixelShaderValid = true, + .PixelShaderKillsPixel = wm_prog_data->uses_kill, + .PixelShaderComputedDepthMode = wm_prog_data->computed_depth_mode, + .AttributeEnable = wm_prog_data->num_varying_inputs > 0, + .oMaskPresenttoRenderTarget = wm_prog_data->uses_omask, + .PixelShaderIsPerSample = per_sample_ps); + + *pPipeline = anv_pipeline_to_handle(pipeline); + + return VK_SUCCESS; +} + +VkResult anv_DestroyPipeline( + VkDevice _device, + VkPipeline _pipeline) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_pipeline, pipeline, _pipeline); + + anv_compiler_free(pipeline); + anv_reloc_list_finish(&pipeline->batch.relocs, pipeline->device); + anv_state_stream_finish(&pipeline->program_stream); + anv_state_pool_free(&device->dynamic_state_pool, pipeline->blend_state); + anv_device_free(pipeline->device, pipeline); + + return VK_SUCCESS; +} + +VkResult anv_CreateGraphicsPipelines( + VkDevice _device, + VkPipelineCache pipelineCache, + uint32_t count, + const VkGraphicsPipelineCreateInfo* pCreateInfos, + VkPipeline* pPipelines) +{ + VkResult result = VK_SUCCESS; + + unsigned i = 0; + for (; i < count; i++) { + result = anv_pipeline_create(_device, &pCreateInfos[i], + NULL, &pPipelines[i]); + if (result != VK_SUCCESS) { + for (unsigned j = 0; j < i; j++) { + anv_DestroyPipeline(_device, pPipelines[j]); + } + + return result; + } + } + + return VK_SUCCESS; +} + +static VkResult anv_compute_pipeline_create( + VkDevice _device, + const VkComputePipelineCreateInfo* pCreateInfo, + VkPipeline* pPipeline) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_pipeline *pipeline; + VkResult result; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO); + + pipeline = anv_device_alloc(device, sizeof(*pipeline), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (pipeline == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + pipeline->device = device; + pipeline->layout = anv_pipeline_layout_from_handle(pCreateInfo->layout); + + result = anv_reloc_list_init(&pipeline->batch.relocs, device); + if (result != VK_SUCCESS) { + anv_device_free(device, pipeline); + return result; + } + pipeline->batch.next = pipeline->batch.start = pipeline->batch_data; + pipeline->batch.end = pipeline->batch.start + sizeof(pipeline->batch_data); + + anv_state_stream_init(&pipeline->program_stream, + &device->instruction_block_pool); + + memset(pipeline->shaders, 0, sizeof(pipeline->shaders)); + + pipeline->shaders[VK_SHADER_STAGE_COMPUTE] = + anv_shader_from_handle(pCreateInfo->cs.shader); + + pipeline->use_repclear = false; + + anv_compiler_run(device->compiler, pipeline); + + const struct brw_cs_prog_data *cs_prog_data = &pipeline->cs_prog_data; + + anv_batch_emit(&pipeline->batch, GEN8_MEDIA_VFE_STATE, + .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_FRAGMENT], + .PerThreadScratchSpace = ffs(cs_prog_data->base.total_scratch / 2048), + .ScratchSpaceBasePointerHigh = 0, + .StackSize = 0, + + .MaximumNumberofThreads = device->info.max_cs_threads - 1, + .NumberofURBEntries = 2, + .ResetGatewayTimer = true, + .BypassGatewayControl = true, + .URBEntryAllocationSize = 2, + .CURBEAllocationSize = 0); + + struct brw_cs_prog_data *prog_data = &pipeline->cs_prog_data; + uint32_t group_size = prog_data->local_size[0] * + prog_data->local_size[1] * prog_data->local_size[2]; + pipeline->cs_thread_width_max = DIV_ROUND_UP(group_size, prog_data->simd_size); + uint32_t remainder = group_size & (prog_data->simd_size - 1); + + if (remainder > 0) + pipeline->cs_right_mask = ~0u >> (32 - remainder); + else + pipeline->cs_right_mask = ~0u >> (32 - prog_data->simd_size); + + + *pPipeline = anv_pipeline_to_handle(pipeline); + + return VK_SUCCESS; +} + +VkResult anv_CreateComputePipelines( + VkDevice _device, + VkPipelineCache pipelineCache, + uint32_t count, + const VkComputePipelineCreateInfo* pCreateInfos, + VkPipeline* pPipelines) +{ + VkResult result = VK_SUCCESS; + + unsigned i = 0; + for (; i < count; i++) { + result = anv_compute_pipeline_create(_device, &pCreateInfos[i], + &pPipelines[i]); + if (result != VK_SUCCESS) { + for (unsigned j = 0; j < i; j++) { + anv_DestroyPipeline(_device, pPipelines[j]); + } + + return result; + } + } + + return VK_SUCCESS; +} + +// Pipeline layout functions + +VkResult anv_CreatePipelineLayout( + VkDevice _device, + const VkPipelineLayoutCreateInfo* pCreateInfo, + VkPipelineLayout* pPipelineLayout) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + struct anv_pipeline_layout *layout; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); + + layout = anv_device_alloc(device, sizeof(*layout), 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (layout == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + layout->num_sets = pCreateInfo->descriptorSetCount; + + uint32_t surface_start[VK_SHADER_STAGE_NUM] = { 0, }; + uint32_t sampler_start[VK_SHADER_STAGE_NUM] = { 0, }; + + for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { + layout->stage[s].surface_count = 0; + layout->stage[s].sampler_count = 0; + } + + for (uint32_t i = 0; i < pCreateInfo->descriptorSetCount; i++) { + ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout, + pCreateInfo->pSetLayouts[i]); + + layout->set[i].layout = set_layout; + for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { + layout->set[i].surface_start[s] = surface_start[s]; + surface_start[s] += set_layout->stage[s].surface_count; + layout->set[i].sampler_start[s] = sampler_start[s]; + sampler_start[s] += set_layout->stage[s].sampler_count; + + layout->stage[s].surface_count += set_layout->stage[s].surface_count; + layout->stage[s].sampler_count += set_layout->stage[s].sampler_count; + } + } + + *pPipelineLayout = anv_pipeline_layout_to_handle(layout); + + return VK_SUCCESS; +} + +VkResult anv_DestroyPipelineLayout( + VkDevice _device, + VkPipelineLayout _pipelineLayout) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_pipeline_layout, pipeline_layout, _pipelineLayout); + + anv_device_free(device, pipeline_layout); + + return VK_SUCCESS; +} diff --git a/src/vulkan/anv_private.h b/src/vulkan/anv_private.h new file mode 100644 index 00000000000..be24b514f30 --- /dev/null +++ b/src/vulkan/anv_private.h @@ -0,0 +1,1081 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_VALGRIND +#include +#include +#define VG(x) x +#define __gen_validate_value(x) VALGRIND_CHECK_MEM_IS_DEFINED(&(x), sizeof(x)) +#else +#define VG(x) +#endif + +#include "brw_device_info.h" +#include "util/macros.h" + +#define VK_PROTOTYPES +#include +#include +#include + +#include "anv_entrypoints.h" + +#include "brw_context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define anv_noreturn __attribute__((__noreturn__)) +#define anv_printflike(a, b) __attribute__((__format__(__printf__, a, b))) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +static inline uint32_t +align_u32(uint32_t v, uint32_t a) +{ + return (v + a - 1) & ~(a - 1); +} + +static inline int32_t +align_i32(int32_t v, int32_t a) +{ + return (v + a - 1) & ~(a - 1); +} + +/** Alignment must be a power of 2. */ +static inline bool +anv_is_aligned(uintmax_t n, uintmax_t a) +{ + assert(a == (a & -a)); + return (n & (a - 1)) == 0; +} + +static inline uint32_t +anv_minify(uint32_t n, uint32_t levels) +{ + if (unlikely(n == 0)) + return 0; + else + return MAX(n >> levels, 1); +} + +static inline bool +anv_clear_mask(uint32_t *inout_mask, uint32_t clear_mask) +{ + if (*inout_mask & clear_mask) { + *inout_mask &= ~clear_mask; + return true; + } else { + return false; + } +} + +#define for_each_bit(b, dword) \ + for (uint32_t __dword = (dword); \ + (b) = __builtin_ffs(__dword) - 1, __dword; \ + __dword &= ~(1 << (b))) + +/* Define no kernel as 1, since that's an illegal offset for a kernel */ +#define NO_KERNEL 1 + +struct anv_common { + VkStructureType sType; + const void* pNext; +}; + +/* Whenever we generate an error, pass it through this function. Useful for + * debugging, where we can break on it. Only call at error site, not when + * propagating errors. Might be useful to plug in a stack trace here. + */ + +static inline VkResult +vk_error(VkResult error) +{ +#ifdef DEBUG + fprintf(stderr, "vk_error: %x\n", error); +#endif + + return error; +} + +void __anv_finishme(const char *file, int line, const char *format, ...) + anv_printflike(3, 4); +void anv_loge(const char *format, ...) anv_printflike(1, 2); +void anv_loge_v(const char *format, va_list va); + +/** + * Print a FINISHME message, including its source location. + */ +#define anv_finishme(format, ...) \ + __anv_finishme(__FILE__, __LINE__, format, ##__VA_ARGS__); + +/* A non-fatal assert. Useful for debugging. */ +#ifdef DEBUG +#define anv_assert(x) ({ \ + if (unlikely(!(x))) \ + fprintf(stderr, "%s:%d ASSERT: %s\n", __FILE__, __LINE__, #x); \ +}) +#else +#define anv_assert(x) +#endif + +void anv_abortf(const char *format, ...) anv_noreturn anv_printflike(1, 2); +void anv_abortfv(const char *format, va_list va) anv_noreturn; + +#define stub_return(v) \ + do { \ + anv_finishme("stub %s", __func__); \ + return (v); \ + } while (0) + +#define stub() \ + do { \ + anv_finishme("stub %s", __func__); \ + return; \ + } while (0) + +/** + * A dynamically growable, circular buffer. Elements are added at head and + * removed from tail. head and tail are free-running uint32_t indices and we + * only compute the modulo with size when accessing the array. This way, + * number of bytes in the queue is always head - tail, even in case of + * wraparound. + */ + +struct anv_vector { + uint32_t head; + uint32_t tail; + uint32_t element_size; + uint32_t size; + void *data; +}; + +int anv_vector_init(struct anv_vector *queue, uint32_t element_size, uint32_t size); +void *anv_vector_add(struct anv_vector *queue); +void *anv_vector_remove(struct anv_vector *queue); + +static inline int +anv_vector_length(struct anv_vector *queue) +{ + return (queue->head - queue->tail) / queue->element_size; +} + +static inline void +anv_vector_finish(struct anv_vector *queue) +{ + free(queue->data); +} + +#define anv_vector_foreach(elem, queue) \ + static_assert(__builtin_types_compatible_p(__typeof__(queue), struct anv_vector *), ""); \ + for (uint32_t __anv_vector_offset = (queue)->tail; \ + elem = (queue)->data + (__anv_vector_offset & ((queue)->size - 1)), __anv_vector_offset < (queue)->head; \ + __anv_vector_offset += (queue)->element_size) + +struct anv_bo { + int gem_handle; + uint32_t index; + uint64_t offset; + uint64_t size; + + /* This field is here for the benefit of the aub dumper. It can (and for + * userptr bos it must) be set to the cpu map of the buffer. Destroying + * the bo won't clean up the mmap, it's still the responsibility of the bo + * user to do that. */ + void *map; +}; + +/* Represents a lock-free linked list of "free" things. This is used by + * both the block pool and the state pools. Unfortunately, in order to + * solve the ABA problem, we can't use a single uint32_t head. + */ +union anv_free_list { + struct { + uint32_t offset; + + /* A simple count that is incremented every time the head changes. */ + uint32_t count; + }; + uint64_t u64; +}; + +#define ANV_FREE_LIST_EMPTY ((union anv_free_list) { { 1, 0 } }) + +struct anv_block_pool { + struct anv_device *device; + + struct anv_bo bo; + void *map; + int fd; + uint32_t size; + + /** + * Array of mmaps and gem handles owned by the block pool, reclaimed when + * the block pool is destroyed. + */ + struct anv_vector mmap_cleanups; + + uint32_t block_size; + + uint32_t next_block; + union anv_free_list free_list; +}; + +struct anv_block_state { + union { + struct { + uint32_t next; + uint32_t end; + }; + uint64_t u64; + }; +}; + +struct anv_state { + uint32_t offset; + uint32_t alloc_size; + void *map; +}; + +struct anv_fixed_size_state_pool { + size_t state_size; + union anv_free_list free_list; + struct anv_block_state block; +}; + +#define ANV_MIN_STATE_SIZE_LOG2 6 +#define ANV_MAX_STATE_SIZE_LOG2 10 + +#define ANV_STATE_BUCKETS (ANV_MAX_STATE_SIZE_LOG2 - ANV_MIN_STATE_SIZE_LOG2) + +struct anv_state_pool { + struct anv_block_pool *block_pool; + struct anv_fixed_size_state_pool buckets[ANV_STATE_BUCKETS]; +}; + +struct anv_state_stream { + struct anv_block_pool *block_pool; + uint32_t next; + uint32_t current_block; + uint32_t end; +}; + +void anv_block_pool_init(struct anv_block_pool *pool, + struct anv_device *device, uint32_t block_size); +void anv_block_pool_finish(struct anv_block_pool *pool); +uint32_t anv_block_pool_alloc(struct anv_block_pool *pool); +void anv_block_pool_free(struct anv_block_pool *pool, uint32_t offset); +void anv_state_pool_init(struct anv_state_pool *pool, + struct anv_block_pool *block_pool); +struct anv_state anv_state_pool_alloc(struct anv_state_pool *pool, + size_t state_size, size_t alignment); +void anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state); +void anv_state_stream_init(struct anv_state_stream *stream, + struct anv_block_pool *block_pool); +void anv_state_stream_finish(struct anv_state_stream *stream); +struct anv_state anv_state_stream_alloc(struct anv_state_stream *stream, + uint32_t size, uint32_t alignment); + +/** + * Implements a pool of re-usable BOs. The interface is identical to that + * of block_pool except that each block is its own BO. + */ +struct anv_bo_pool { + struct anv_device *device; + + uint32_t bo_size; + + void *free_list; +}; + +void anv_bo_pool_init(struct anv_bo_pool *pool, + struct anv_device *device, uint32_t block_size); +void anv_bo_pool_finish(struct anv_bo_pool *pool); +VkResult anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo); +void anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo); + +struct anv_physical_device { + struct anv_instance * instance; + uint32_t chipset_id; + bool no_hw; + const char * path; + const char * name; + const struct brw_device_info * info; + int fd; +}; + +struct anv_instance { + void * pAllocUserData; + PFN_vkAllocFunction pfnAlloc; + PFN_vkFreeFunction pfnFree; + uint32_t apiVersion; + uint32_t physicalDeviceCount; + struct anv_physical_device physicalDevice; +}; + +struct anv_meta_state { + struct { + VkPipeline pipeline; + } clear; + + struct { + VkPipeline pipeline; + VkPipelineLayout pipeline_layout; + VkDescriptorSetLayout ds_layout; + } blit; + + struct { + VkDynamicRasterState rs_state; + VkDynamicColorBlendState cb_state; + VkDynamicDepthStencilState ds_state; + } shared; +}; + +struct anv_queue { + struct anv_device * device; + + struct anv_state_pool * pool; + + /** + * Serial number of the most recently completed batch executed on the + * engine. + */ + struct anv_state completed_serial; + + /** + * The next batch submitted to the engine will be assigned this serial + * number. + */ + uint32_t next_serial; + + uint32_t last_collected_serial; +}; + +struct anv_device { + struct anv_instance * instance; + uint32_t chipset_id; + struct brw_device_info info; + int context_id; + int fd; + bool no_hw; + bool dump_aub; + + struct anv_bo_pool batch_bo_pool; + + struct anv_block_pool dynamic_state_block_pool; + struct anv_state_pool dynamic_state_pool; + + struct anv_block_pool instruction_block_pool; + struct anv_block_pool surface_state_block_pool; + struct anv_state_pool surface_state_pool; + + struct anv_meta_state meta_state; + + struct anv_state border_colors; + + struct anv_queue queue; + + struct anv_block_pool scratch_block_pool; + + struct anv_compiler * compiler; + struct anv_aub_writer * aub_writer; + pthread_mutex_t mutex; +}; + +void * +anv_device_alloc(struct anv_device * device, + size_t size, + size_t alignment, + VkSystemAllocType allocType); + +void +anv_device_free(struct anv_device * device, + void * mem); + +void* anv_gem_mmap(struct anv_device *device, + uint32_t gem_handle, uint64_t offset, uint64_t size); +void anv_gem_munmap(void *p, uint64_t size); +uint32_t anv_gem_create(struct anv_device *device, size_t size); +void anv_gem_close(struct anv_device *device, int gem_handle); +int anv_gem_userptr(struct anv_device *device, void *mem, size_t size); +int anv_gem_wait(struct anv_device *device, int gem_handle, int64_t *timeout_ns); +int anv_gem_execbuffer(struct anv_device *device, + struct drm_i915_gem_execbuffer2 *execbuf); +int anv_gem_set_tiling(struct anv_device *device, int gem_handle, + uint32_t stride, uint32_t tiling); +int anv_gem_create_context(struct anv_device *device); +int anv_gem_destroy_context(struct anv_device *device, int context); +int anv_gem_get_param(int fd, uint32_t param); +int anv_gem_get_aperture(struct anv_physical_device *physical_dev, uint64_t *size); +int anv_gem_handle_to_fd(struct anv_device *device, int gem_handle); +int anv_gem_fd_to_handle(struct anv_device *device, int fd); +int anv_gem_userptr(struct anv_device *device, void *mem, size_t size); + +VkResult anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size); + +struct anv_reloc_list { + size_t num_relocs; + size_t array_length; + struct drm_i915_gem_relocation_entry * relocs; + struct anv_bo ** reloc_bos; +}; + +VkResult anv_reloc_list_init(struct anv_reloc_list *list, + struct anv_device *device); +void anv_reloc_list_finish(struct anv_reloc_list *list, + struct anv_device *device); + +uint64_t anv_reloc_list_add(struct anv_reloc_list *list, + struct anv_device *device, + uint32_t offset, struct anv_bo *target_bo, + uint32_t delta); + +struct anv_batch_bo { + struct anv_bo bo; + + /* Bytes actually consumed in this batch BO */ + size_t length; + + /* These offsets reference the per-batch reloc list */ + size_t first_reloc; + size_t num_relocs; + + struct anv_batch_bo * prev_batch_bo; +}; + +struct anv_batch { + struct anv_device * device; + + void * start; + void * end; + void * next; + + struct anv_reloc_list relocs; + + /* This callback is called (with the associated user data) in the event + * that the batch runs out of space. + */ + VkResult (*extend_cb)(struct anv_batch *, void *); + void * user_data; +}; + +void *anv_batch_emit_dwords(struct anv_batch *batch, int num_dwords); +void anv_batch_emit_batch(struct anv_batch *batch, struct anv_batch *other); +uint64_t anv_batch_emit_reloc(struct anv_batch *batch, + void *location, struct anv_bo *bo, uint32_t offset); + +struct anv_address { + struct anv_bo *bo; + uint32_t offset; +}; + +#define __gen_address_type struct anv_address +#define __gen_user_data struct anv_batch + +static inline uint64_t +__gen_combine_address(struct anv_batch *batch, void *location, + const struct anv_address address, uint32_t delta) +{ + if (address.bo == NULL) { + return delta; + } else { + assert(batch->start <= location && location < batch->end); + + return anv_batch_emit_reloc(batch, location, address.bo, address.offset + delta); + } +} + +#include "gen7_pack.h" +#include "gen75_pack.h" +#undef GEN8_3DSTATE_MULTISAMPLE +#include "gen8_pack.h" + +#define anv_batch_emit(batch, cmd, ...) do { \ + struct cmd __template = { \ + cmd ## _header, \ + __VA_ARGS__ \ + }; \ + void *__dst = anv_batch_emit_dwords(batch, cmd ## _length); \ + cmd ## _pack(batch, __dst, &__template); \ + } while (0) + +#define anv_batch_emitn(batch, n, cmd, ...) ({ \ + struct cmd __template = { \ + cmd ## _header, \ + .DwordLength = n - cmd ## _length_bias, \ + __VA_ARGS__ \ + }; \ + void *__dst = anv_batch_emit_dwords(batch, n); \ + cmd ## _pack(batch, __dst, &__template); \ + __dst; \ + }) + +#define anv_batch_emit_merge(batch, dwords0, dwords1) \ + do { \ + uint32_t *dw; \ + \ + assert(ARRAY_SIZE(dwords0) == ARRAY_SIZE(dwords1)); \ + dw = anv_batch_emit_dwords((batch), ARRAY_SIZE(dwords0)); \ + for (uint32_t i = 0; i < ARRAY_SIZE(dwords0); i++) \ + dw[i] = (dwords0)[i] | (dwords1)[i]; \ + VG(VALGRIND_CHECK_MEM_IS_DEFINED(dw, ARRAY_SIZE(dwords0) * 4));\ + } while (0) + +#define GEN8_MOCS { \ + .MemoryTypeLLCeLLCCacheabilityControl = WB, \ + .TargetCache = L3DefertoPATforLLCeLLCselection, \ + .AgeforQUADLRU = 0 \ + } + +struct anv_device_memory { + struct anv_bo bo; + VkDeviceSize map_size; + void * map; +}; + +struct anv_dynamic_vp_state { + struct anv_state sf_clip_vp; + struct anv_state cc_vp; + struct anv_state scissor; +}; + +struct anv_dynamic_rs_state { + uint32_t state_sf[GEN8_3DSTATE_SF_length]; + uint32_t state_raster[GEN8_3DSTATE_RASTER_length]; +}; + +struct anv_dynamic_ds_state { + uint32_t state_wm_depth_stencil[GEN8_3DSTATE_WM_DEPTH_STENCIL_length]; + uint32_t state_color_calc[GEN8_COLOR_CALC_STATE_length]; +}; + +struct anv_dynamic_cb_state { + uint32_t state_color_calc[GEN8_COLOR_CALC_STATE_length]; + +}; + +struct anv_descriptor_slot { + int8_t dynamic_slot; + uint8_t index; +}; + +struct anv_descriptor_set_layout { + struct { + uint32_t surface_count; + struct anv_descriptor_slot *surface_start; + uint32_t sampler_count; + struct anv_descriptor_slot *sampler_start; + } stage[VK_SHADER_STAGE_NUM]; + + uint32_t count; + uint32_t num_dynamic_buffers; + uint32_t shader_stages; + struct anv_descriptor_slot entries[0]; +}; + +struct anv_descriptor { + struct anv_sampler *sampler; + struct anv_surface_view *view; +}; + +struct anv_descriptor_set { + struct anv_descriptor descriptors[0]; +}; + +VkResult +anv_descriptor_set_create(struct anv_device *device, + const struct anv_descriptor_set_layout *layout, + struct anv_descriptor_set **out_set); + +void +anv_descriptor_set_destroy(struct anv_device *device, + struct anv_descriptor_set *set); + +#define MAX_VBS 32 +#define MAX_SETS 8 +#define MAX_RTS 8 + +struct anv_pipeline_layout { + struct { + struct anv_descriptor_set_layout *layout; + uint32_t surface_start[VK_SHADER_STAGE_NUM]; + uint32_t sampler_start[VK_SHADER_STAGE_NUM]; + } set[MAX_SETS]; + + uint32_t num_sets; + + struct { + uint32_t surface_count; + uint32_t sampler_count; + } stage[VK_SHADER_STAGE_NUM]; +}; + +struct anv_buffer { + struct anv_device * device; + VkDeviceSize size; + + /* Set when bound */ + struct anv_bo * bo; + VkDeviceSize offset; +}; + +#define ANV_CMD_BUFFER_PIPELINE_DIRTY (1 << 0) +#define ANV_CMD_BUFFER_RS_DIRTY (1 << 2) +#define ANV_CMD_BUFFER_DS_DIRTY (1 << 3) +#define ANV_CMD_BUFFER_CB_DIRTY (1 << 4) +#define ANV_CMD_BUFFER_VP_DIRTY (1 << 5) +#define ANV_CMD_BUFFER_INDEX_BUFFER_DIRTY (1 << 6) + +struct anv_vertex_binding { + struct anv_buffer * buffer; + VkDeviceSize offset; +}; + +struct anv_descriptor_set_binding { + struct anv_descriptor_set * set; + uint32_t dynamic_offsets[128]; +}; + +/** State required while building cmd buffer */ +struct anv_cmd_state { + uint32_t current_pipeline; + uint32_t vb_dirty; + uint32_t dirty; + uint32_t compute_dirty; + uint32_t descriptors_dirty; + uint32_t scratch_size; + struct anv_pipeline * pipeline; + struct anv_pipeline * compute_pipeline; + struct anv_framebuffer * framebuffer; + struct anv_render_pass * pass; + struct anv_subpass * subpass; + struct anv_dynamic_rs_state * rs_state; + struct anv_dynamic_ds_state * ds_state; + struct anv_dynamic_vp_state * vp_state; + struct anv_dynamic_cb_state * cb_state; + uint32_t state_vf[GEN8_3DSTATE_VF_length]; + struct anv_vertex_binding vertex_bindings[MAX_VBS]; + struct anv_descriptor_set_binding descriptors[MAX_SETS]; +}; + +VkResult anv_cmd_state_init(struct anv_cmd_state *state); +void anv_cmd_state_fini(struct anv_cmd_state *state); + +struct anv_cmd_buffer { + struct anv_device * device; + + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 * exec2_objects; + uint32_t exec2_bo_count; + struct anv_bo ** exec2_bos; + uint32_t exec2_array_length; + bool need_reloc; + uint32_t serial; + + struct anv_batch batch; + struct anv_batch_bo * last_batch_bo; + struct anv_batch_bo * surface_batch_bo; + uint32_t surface_next; + struct anv_reloc_list surface_relocs; + struct anv_state_stream surface_state_stream; + struct anv_state_stream dynamic_state_stream; + + struct anv_cmd_state state; +}; + +struct anv_state +anv_cmd_buffer_alloc_surface_state(struct anv_cmd_buffer *cmd_buffer, + uint32_t size, uint32_t alignment); +struct anv_state +anv_cmd_buffer_alloc_dynamic_state(struct anv_cmd_buffer *cmd_buffer, + uint32_t size, uint32_t alignment); + +VkResult anv_cmd_buffer_new_surface_state_bo(struct anv_cmd_buffer *cmd_buffer); + +void anv_cmd_buffer_emit_state_base_address(struct anv_cmd_buffer *cmd_buffer); + +void anv_cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer, + struct anv_subpass *subpass); + +void anv_cmd_buffer_clear_attachments(struct anv_cmd_buffer *cmd_buffer, + struct anv_render_pass *pass, + const VkClearValue *clear_values); + +void anv_cmd_buffer_dump(struct anv_cmd_buffer *cmd_buffer); +void anv_aub_writer_destroy(struct anv_aub_writer *writer); + +struct anv_fence { + struct anv_bo bo; + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec2_objects[1]; + bool ready; +}; + +struct anv_shader_module { + uint32_t size; + char data[0]; +}; + +struct anv_shader { + struct anv_shader_module * module; + char entrypoint[0]; +}; + +struct anv_pipeline { + struct anv_device * device; + struct anv_batch batch; + uint32_t batch_data[256]; + struct anv_shader * shaders[VK_SHADER_STAGE_NUM]; + struct anv_pipeline_layout * layout; + bool use_repclear; + + struct brw_vs_prog_data vs_prog_data; + struct brw_wm_prog_data wm_prog_data; + struct brw_gs_prog_data gs_prog_data; + struct brw_cs_prog_data cs_prog_data; + bool writes_point_size; + struct brw_stage_prog_data * prog_data[VK_SHADER_STAGE_NUM]; + uint32_t scratch_start[VK_SHADER_STAGE_NUM]; + uint32_t total_scratch; + struct { + uint32_t vs_start; + uint32_t vs_size; + uint32_t nr_vs_entries; + uint32_t gs_start; + uint32_t gs_size; + uint32_t nr_gs_entries; + } urb; + + uint32_t active_stages; + struct anv_state_stream program_stream; + struct anv_state blend_state; + uint32_t vs_simd8; + uint32_t ps_simd8; + uint32_t ps_simd16; + uint32_t gs_vec4; + uint32_t gs_vertex_count; + uint32_t cs_simd; + + uint32_t vb_used; + uint32_t binding_stride[MAX_VBS]; + + uint32_t state_sf[GEN8_3DSTATE_SF_length]; + uint32_t state_vf[GEN8_3DSTATE_VF_length]; + uint32_t state_raster[GEN8_3DSTATE_RASTER_length]; + uint32_t state_wm_depth_stencil[GEN8_3DSTATE_WM_DEPTH_STENCIL_length]; + + uint32_t cs_thread_width_max; + uint32_t cs_right_mask; +}; + +struct anv_pipeline_create_info { + bool use_repclear; + bool disable_viewport; + bool disable_scissor; + bool disable_vs; + bool use_rectlist; +}; + +VkResult +anv_pipeline_create(VkDevice device, + const VkGraphicsPipelineCreateInfo *pCreateInfo, + const struct anv_pipeline_create_info *extra, + VkPipeline *pPipeline); + +struct anv_compiler *anv_compiler_create(struct anv_device *device); +void anv_compiler_destroy(struct anv_compiler *compiler); +int anv_compiler_run(struct anv_compiler *compiler, struct anv_pipeline *pipeline); +void anv_compiler_free(struct anv_pipeline *pipeline); + +struct anv_format { + const char *name; + uint16_t surface_format; /**< RENDER_SURFACE_STATE.SurfaceFormat */ + uint8_t cpp; /**< Bytes-per-pixel of anv_format::surface_format. */ + uint8_t num_channels; + uint16_t depth_format; /**< 3DSTATE_DEPTH_BUFFER.SurfaceFormat */ + bool has_stencil; +}; + +const struct anv_format * +anv_format_for_vk_format(VkFormat format); +bool anv_is_vk_format_depth_or_stencil(VkFormat format); + +/** + * A proxy for the color surfaces, depth surfaces, and stencil surfaces. + */ +struct anv_surface { + /** + * Offset from VkImage's base address, as bound by vkBindImageMemory(). + */ + uint32_t offset; + + uint32_t stride; /**< RENDER_SURFACE_STATE.SurfacePitch */ + uint16_t qpitch; /**< RENDER_SURFACE_STATE.QPitch */ + + /** + * \name Alignment of miptree images, in units of pixels. + * + * These fields contain the real alignment values, not the values to be + * given to the GPU. For example, if h_align is 4, then program the GPU + * with HALIGN_4. + * \{ + */ + uint8_t h_align; /**< RENDER_SURFACE_STATE.SurfaceHorizontalAlignment */ + uint8_t v_align; /**< RENDER_SURFACE_STATE.SurfaceVerticalAlignment */ + /** \} */ + + uint8_t tile_mode; /**< RENDER_SURFACE_STATE.TileMode */ +}; + +struct anv_image { + VkImageType type; + VkExtent3D extent; + VkFormat format; + uint32_t levels; + uint32_t array_size; + + VkDeviceSize size; + uint32_t alignment; + + /* Set when bound */ + struct anv_bo *bo; + VkDeviceSize offset; + + struct anv_swap_chain *swap_chain; + + /** RENDER_SURFACE_STATE.SurfaceType */ + uint8_t surf_type; + + /** Primary surface is either color or depth. */ + struct anv_surface primary_surface; + + /** Stencil surface is optional. */ + struct anv_surface stencil_surface; +}; + +struct anv_surface_view { + struct anv_state surface_state; /**< RENDER_SURFACE_STATE */ + struct anv_bo *bo; + uint32_t offset; /**< VkBufferCreateInfo::offset */ + uint32_t range; /**< VkBufferCreateInfo::range */ + VkFormat format; /**< VkBufferCreateInfo::format */ +}; + +struct anv_buffer_view { + struct anv_surface_view view; +}; + +struct anv_image_view { + struct anv_surface_view view; + VkExtent3D extent; +}; + +enum anv_attachment_view_type { + ANV_ATTACHMENT_VIEW_TYPE_COLOR, + ANV_ATTACHMENT_VIEW_TYPE_DEPTH_STENCIL, +}; + +struct anv_attachment_view { + enum anv_attachment_view_type attachment_type; + VkExtent3D extent; +}; + +struct anv_color_attachment_view { + struct anv_attachment_view base; + struct anv_surface_view view; +}; + +struct anv_depth_stencil_view { + struct anv_attachment_view base; + + struct anv_bo *bo; + + uint32_t depth_offset; /**< Offset into bo. */ + uint32_t depth_stride; /**< 3DSTATE_DEPTH_BUFFER.SurfacePitch */ + uint32_t depth_format; /**< 3DSTATE_DEPTH_BUFFER.SurfaceFormat */ + uint16_t depth_qpitch; /**< 3DSTATE_DEPTH_BUFFER.SurfaceQPitch */ + + uint32_t stencil_offset; /**< Offset into bo. */ + uint32_t stencil_stride; /**< 3DSTATE_STENCIL_BUFFER.SurfacePitch */ + uint16_t stencil_qpitch; /**< 3DSTATE_STENCIL_BUFFER.SurfaceQPitch */ +}; + +struct anv_image_create_info { + const VkImageCreateInfo *vk_info; + bool force_tile_mode; + uint8_t tile_mode; +}; + +VkResult anv_image_create(VkDevice _device, + const struct anv_image_create_info *info, + VkImage *pImage); + +void anv_image_view_init(struct anv_image_view *view, + struct anv_device *device, + const VkImageViewCreateInfo* pCreateInfo, + struct anv_cmd_buffer *cmd_buffer); + +void anv_color_attachment_view_init(struct anv_color_attachment_view *view, + struct anv_device *device, + const VkAttachmentViewCreateInfo* pCreateInfo, + struct anv_cmd_buffer *cmd_buffer); +void anv_fill_buffer_surface_state(void *state, VkFormat format, + uint32_t offset, uint32_t range); + +void anv_surface_view_fini(struct anv_device *device, + struct anv_surface_view *view); + +struct anv_sampler { + uint32_t state[4]; +}; + +struct anv_framebuffer { + uint32_t width; + uint32_t height; + uint32_t layers; + + /* Viewport for clears */ + VkDynamicViewportState vp_state; + + uint32_t attachment_count; + const struct anv_attachment_view * attachments[0]; +}; + +struct anv_subpass { + uint32_t input_count; + uint32_t * input_attachments; + uint32_t color_count; + uint32_t * color_attachments; + uint32_t * resolve_attachments; + uint32_t depth_stencil_attachment; +}; + +struct anv_render_pass_attachment { + VkFormat format; + uint32_t samples; + VkAttachmentLoadOp load_op; + VkAttachmentLoadOp stencil_load_op; +}; + +struct anv_render_pass { + uint32_t attachment_count; + uint32_t subpass_count; + + struct anv_render_pass_attachment * attachments; + struct anv_subpass subpasses[0]; +}; + +void anv_device_init_meta(struct anv_device *device); +void anv_device_finish_meta(struct anv_device *device); + +void *anv_lookup_entrypoint(const char *name); + +#define ANV_DEFINE_HANDLE_CASTS(__anv_type, __VkType) \ + \ + static inline struct __anv_type * \ + __anv_type ## _from_handle(__VkType _handle) \ + { \ + return (struct __anv_type *) _handle; \ + } \ + \ + static inline __VkType \ + __anv_type ## _to_handle(struct __anv_type *_obj) \ + { \ + return (__VkType) _obj; \ + } + +#define ANV_DEFINE_NONDISP_HANDLE_CASTS(__anv_type, __VkType) \ + \ + static inline struct __anv_type * \ + __anv_type ## _from_handle(__VkType _handle) \ + { \ + return (struct __anv_type *) _handle.handle; \ + } \ + \ + static inline __VkType \ + __anv_type ## _to_handle(struct __anv_type *_obj) \ + { \ + return (__VkType) { .handle = (uint64_t) _obj }; \ + } + +#define ANV_FROM_HANDLE(__anv_type, __name, __handle) \ + struct __anv_type *__name = __anv_type ## _from_handle(__handle) + +ANV_DEFINE_HANDLE_CASTS(anv_cmd_buffer, VkCmdBuffer) +ANV_DEFINE_HANDLE_CASTS(anv_device, VkDevice) +ANV_DEFINE_HANDLE_CASTS(anv_instance, VkInstance) +ANV_DEFINE_HANDLE_CASTS(anv_physical_device, VkPhysicalDevice) +ANV_DEFINE_HANDLE_CASTS(anv_queue, VkQueue) +ANV_DEFINE_HANDLE_CASTS(anv_swap_chain, VkSwapChainWSI); + +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_attachment_view, VkAttachmentView) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer, VkBuffer) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer_view, VkBufferView); +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set, VkDescriptorSet) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set_layout, VkDescriptorSetLayout) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_device_memory, VkDeviceMemory) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_cb_state, VkDynamicColorBlendState) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_ds_state, VkDynamicDepthStencilState) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_rs_state, VkDynamicRasterState) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_vp_state, VkDynamicViewportState) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_fence, VkFence) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_framebuffer, VkFramebuffer) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_image, VkImage) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_image_view, VkImageView); +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_pipeline, VkPipeline) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_pipeline_layout, VkPipelineLayout) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_query_pool, VkQueryPool) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_render_pass, VkRenderPass) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_sampler, VkSampler) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_shader, VkShader) +ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_shader_module, VkShaderModule) + +#define ANV_DEFINE_STRUCT_CASTS(__anv_type, __VkType) \ + \ + static inline const __VkType * \ + __anv_type ## _to_ ## __VkType(const struct __anv_type *__anv_obj) \ + { \ + return (const __VkType *) __anv_obj; \ + } + +#define ANV_COMMON_TO_STRUCT(__VkType, __vk_name, __common_name) \ + const __VkType *__vk_name = anv_common_to_ ## __VkType(__common_name) + +ANV_DEFINE_STRUCT_CASTS(anv_common, VkMemoryBarrier) +ANV_DEFINE_STRUCT_CASTS(anv_common, VkBufferMemoryBarrier) +ANV_DEFINE_STRUCT_CASTS(anv_common, VkImageMemoryBarrier) + +#ifdef __cplusplus +} +#endif diff --git a/src/vulkan/anv_query.c b/src/vulkan/anv_query.c new file mode 100644 index 00000000000..d7903ee2cb8 --- /dev/null +++ b/src/vulkan/anv_query.c @@ -0,0 +1,352 @@ +/* + * 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 +#include +#include +#include +#include + +#include "anv_private.h" + +struct anv_query_pool_slot { + uint64_t begin; + uint64_t end; + uint64_t available; +}; + +struct anv_query_pool { + VkQueryType type; + uint32_t slots; + struct anv_bo bo; +}; + +VkResult anv_CreateQueryPool( + VkDevice _device, + const VkQueryPoolCreateInfo* pCreateInfo, + VkQueryPool* pQueryPool) +{ + ANV_FROM_HANDLE(anv_device, 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); + + 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 = anv_query_pool_to_handle(pool); + + return VK_SUCCESS; + + fail: + anv_device_free(device, pool); + + return result; +} + +VkResult anv_DestroyQueryPool( + VkDevice _device, + VkQueryPool _pool) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_query_pool, pool, _pool); + + 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; +} + +VkResult anv_GetQueryPoolResults( + VkDevice _device, + VkQueryPool queryPool, + uint32_t startQuery, + uint32_t queryCount, + size_t* pDataSize, + void* pData, + VkQueryResultFlags flags) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_query_pool, 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; +} + +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) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_query_pool, 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) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_query_pool, 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) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_buffer, 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) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); + ANV_FROM_HANDLE(anv_query_pool, pool, queryPool); + ANV_FROM_HANDLE(anv_buffer, 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, + .StallAtPixelScoreboard = 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; + } +} diff --git a/src/vulkan/anv_util.c b/src/vulkan/anv_util.c new file mode 100644 index 00000000000..820356675c7 --- /dev/null +++ b/src/vulkan/anv_util.c @@ -0,0 +1,151 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "anv_private.h" + +/** Log an error message. */ +void anv_printflike(1, 2) +anv_loge(const char *format, ...) +{ + va_list va; + + va_start(va, format); + anv_loge_v(format, va); + va_end(va); +} + +/** \see anv_loge() */ +void +anv_loge_v(const char *format, va_list va) +{ + fprintf(stderr, "vk: error: "); + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); +} + +void anv_printflike(3, 4) +__anv_finishme(const char *file, int line, const char *format, ...) +{ + va_list ap; + char buffer[256]; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buffer); +} + +void anv_noreturn anv_printflike(1, 2) +anv_abortf(const char *format, ...) +{ + va_list va; + + va_start(va, format); + anv_abortfv(format, va); + va_end(va); +} + +void anv_noreturn +anv_abortfv(const char *format, va_list va) +{ + fprintf(stderr, "vk: error: "); + vfprintf(stderr, format, va); + fprintf(stderr, "\n"); + abort(); +} + +int +anv_vector_init(struct anv_vector *vector, uint32_t element_size, uint32_t size) +{ + assert(is_power_of_two(size)); + assert(element_size < size && is_power_of_two(element_size)); + + vector->head = 0; + vector->tail = 0; + vector->element_size = element_size; + vector->size = size; + vector->data = malloc(size); + + return vector->data != NULL; +} + +void * +anv_vector_add(struct anv_vector *vector) +{ + uint32_t offset, size, split, tail; + void *data; + + if (vector->head - vector->tail == vector->size) { + size = vector->size * 2; + data = malloc(size); + if (data == NULL) + return NULL; + split = align_u32(vector->tail, vector->size); + tail = vector->tail & (vector->size - 1); + if (vector->head - split < vector->size) { + memcpy(data + tail, + vector->data + tail, + split - vector->tail); + memcpy(data + vector->size, + vector->data, vector->head - split); + } else { + memcpy(data + tail, + vector->data + tail, + vector->head - vector->tail); + } + free(vector->data); + vector->data = data; + vector->size = size; + } + + assert(vector->head - vector->tail < vector->size); + + offset = vector->head & (vector->size - 1); + vector->head += vector->element_size; + + return vector->data + offset; +} + +void * +anv_vector_remove(struct anv_vector *vector) +{ + uint32_t offset; + + if (vector->head == vector->tail) + return NULL; + + assert(vector->head - vector->tail <= vector->size); + + offset = vector->tail & (vector->size - 1); + vector->tail += vector->element_size; + + return vector->data + offset; +} diff --git a/src/vulkan/anv_x11.c b/src/vulkan/anv_x11.c new file mode 100644 index 00000000000..9ffce8d8cbf --- /dev/null +++ b/src/vulkan/anv_x11.c @@ -0,0 +1,299 @@ +/* + * 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 "anv_private.h" + +#include +#include +#include + +static const VkFormat formats[] = { + VK_FORMAT_B5G6R5_UNORM, + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_B8G8R8A8_SRGB, +}; + +VkResult anv_GetDisplayInfoWSI( + VkDisplayWSI display, + VkDisplayInfoTypeWSI infoType, + size_t* pDataSize, + void* pData) +{ + VkDisplayFormatPropertiesWSI *properties = pData; + size_t size; + + if (pDataSize == NULL) + return VK_ERROR_INVALID_POINTER; + + switch (infoType) { + case VK_DISPLAY_INFO_TYPE_FORMAT_PROPERTIES_WSI: + size = sizeof(properties[0]) * ARRAY_SIZE(formats); + + if (pData == NULL) { + *pDataSize = size; + return VK_SUCCESS; + } + + if (*pDataSize < size) + return vk_error(VK_ERROR_INVALID_VALUE); + + *pDataSize = size; + + for (uint32_t i = 0; i < ARRAY_SIZE(formats); i++) + properties[i].swapChainFormat = formats[i]; + + return VK_SUCCESS; + + default: + return VK_UNSUPPORTED; + } +} + +struct anv_swap_chain { + struct anv_device * device; + xcb_connection_t * conn; + xcb_window_t window; + xcb_gc_t gc; + VkExtent2D extent; + uint32_t count; + struct { + struct anv_image * image; + struct anv_device_memory * memory; + xcb_pixmap_t pixmap; + } images[0]; +}; + +VkResult anv_CreateSwapChainWSI( + VkDevice _device, + const VkSwapChainCreateInfoWSI* pCreateInfo, + VkSwapChainWSI* pSwapChain) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + struct anv_swap_chain *chain; + xcb_void_cookie_t cookie; + VkResult result; + size_t size; + int ret; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI); + + size = sizeof(*chain) + pCreateInfo->imageCount * sizeof(chain->images[0]); + chain = anv_device_alloc(device, size, 8, + VK_SYSTEM_ALLOC_TYPE_API_OBJECT); + if (chain == NULL) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + chain->device = device; + chain->conn = (xcb_connection_t *) pCreateInfo->pNativeWindowSystemHandle; + chain->window = (xcb_window_t) (uintptr_t) pCreateInfo->pNativeWindowHandle; + chain->count = pCreateInfo->imageCount; + chain->extent = pCreateInfo->imageExtent; + + for (uint32_t i = 0; i < chain->count; i++) { + VkDeviceMemory memory_h; + VkImage image_h; + struct anv_image *image; + struct anv_surface *surface; + struct anv_device_memory *memory; + + anv_image_create(_device, + &(struct anv_image_create_info) { + .force_tile_mode = true, + .tile_mode = XMAJOR, + .vk_info = + &(VkImageCreateInfo) { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1 + }, + .mipLevels = 1, + .arraySize = 1, + .samples = 1, + /* FIXME: Need a way to use X tiling to allow scanout */ + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .flags = 0, + }}, + &image_h); + + image = anv_image_from_handle(image_h); + surface = &image->primary_surface; + + anv_AllocMemory(_device, + &(VkMemoryAllocInfo) { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, + .allocationSize = image->size, + .memoryTypeIndex = 0, + }, + &memory_h); + + memory = anv_device_memory_from_handle(memory_h); + + anv_BindImageMemory(VK_NULL_HANDLE, anv_image_to_handle(image), + memory_h, 0); + + ret = anv_gem_set_tiling(device, memory->bo.gem_handle, + surface->stride, I915_TILING_X); + if (ret) { + result = vk_error(VK_ERROR_UNKNOWN); + goto fail; + } + + int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle); + if (fd == -1) { + result = vk_error(VK_ERROR_UNKNOWN); + goto fail; + } + + uint32_t bpp = 32; + uint32_t depth = 24; + xcb_pixmap_t pixmap = xcb_generate_id(chain->conn); + + cookie = + xcb_dri3_pixmap_from_buffer_checked(chain->conn, + pixmap, + chain->window, + image->size, + pCreateInfo->imageExtent.width, + pCreateInfo->imageExtent.height, + surface->stride, + depth, bpp, fd); + + chain->images[i].image = image; + chain->images[i].memory = memory; + chain->images[i].pixmap = pixmap; + image->swap_chain = chain; + + xcb_discard_reply(chain->conn, cookie.sequence); + } + + chain->gc = xcb_generate_id(chain->conn); + if (!chain->gc) { + result = vk_error(VK_ERROR_UNKNOWN); + goto fail; + } + + cookie = xcb_create_gc(chain->conn, + chain->gc, + chain->window, + XCB_GC_GRAPHICS_EXPOSURES, + (uint32_t []) { 0 }); + xcb_discard_reply(chain->conn, cookie.sequence); + + *pSwapChain = anv_swap_chain_to_handle(chain); + + return VK_SUCCESS; + + fail: + return result; +} + +VkResult anv_DestroySwapChainWSI( + VkSwapChainWSI _chain) +{ + ANV_FROM_HANDLE(anv_swap_chain, chain, _chain); + + anv_device_free(chain->device, chain); + + return VK_SUCCESS; +} + +VkResult anv_GetSwapChainInfoWSI( + VkSwapChainWSI _chain, + VkSwapChainInfoTypeWSI infoType, + size_t* pDataSize, + void* pData) +{ + ANV_FROM_HANDLE(anv_swap_chain, chain, _chain); + + VkSwapChainImageInfoWSI *images; + size_t size; + + switch (infoType) { + case VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI: + size = sizeof(*images) * chain->count; + if (pData && *pDataSize < size) + return VK_ERROR_INVALID_VALUE; + + *pDataSize = size; + if (!pData) + return VK_SUCCESS; + + images = pData; + for (uint32_t i = 0; i < chain->count; i++) { + images[i].image = anv_image_to_handle(chain->images[i].image); + images[i].memory = anv_device_memory_to_handle(chain->images[i].memory); + } + + return VK_SUCCESS; + + default: + return VK_UNSUPPORTED; + } +} + +VkResult anv_QueuePresentWSI( + VkQueue queue_, + const VkPresentInfoWSI* pPresentInfo) +{ + ANV_FROM_HANDLE(anv_image, image, pPresentInfo->image); + + struct anv_swap_chain *chain = image->swap_chain; + xcb_void_cookie_t cookie; + xcb_pixmap_t pixmap; + + assert(pPresentInfo->sType == VK_STRUCTURE_TYPE_PRESENT_INFO_WSI); + + if (chain == NULL) + return vk_error(VK_ERROR_INVALID_VALUE); + + pixmap = XCB_NONE; + for (uint32_t i = 0; i < chain->count; i++) { + if (image == chain->images[i].image) { + pixmap = chain->images[i].pixmap; + break; + } + } + + if (pixmap == XCB_NONE) + return vk_error(VK_ERROR_INVALID_VALUE); + + cookie = xcb_copy_area(chain->conn, + pixmap, + chain->window, + chain->gc, + 0, 0, + 0, 0, + chain->extent.width, + chain->extent.height); + xcb_discard_reply(chain->conn, cookie.sequence); + + xcb_flush(chain->conn); + + return VK_SUCCESS; +} diff --git a/src/vulkan/aub.c b/src/vulkan/aub.c deleted file mode 100644 index c33defd48f5..00000000000 --- a/src/vulkan/aub.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "private.h" -#include "aub.h" - -struct anv_aub_writer { - FILE *file; - uint32_t offset; - int gen; -}; - -static void -aub_out(struct anv_aub_writer *writer, uint32_t data) -{ - fwrite(&data, 1, 4, writer->file); -} - -static void -aub_out_data(struct anv_aub_writer *writer, const void *data, size_t size) -{ - fwrite(data, 1, size, writer->file); -} - -static struct anv_aub_writer * -get_anv_aub_writer(struct anv_device *device) -{ - struct anv_aub_writer *writer = device->aub_writer; - int entry = 0x200003; - int i; - int gtt_size = 0x10000; - const char *filename; - - if (geteuid() != getuid()) - return NULL; - - if (writer) - return writer; - - writer = malloc(sizeof(*writer)); - if (writer == NULL) - return NULL; - - filename = "intel.aub"; - writer->gen = device->info.gen; - writer->file = fopen(filename, "w+"); - if (!writer->file) { - free(writer); - return NULL; - } - - /* Start allocating objects from just after the GTT. */ - writer->offset = gtt_size; - - /* Start with a (required) version packet. */ - aub_out(writer, CMD_AUB_HEADER | (13 - 2)); - aub_out(writer, - (4 << AUB_HEADER_MAJOR_SHIFT) | - (0 << AUB_HEADER_MINOR_SHIFT)); - for (i = 0; i < 8; i++) { - aub_out(writer, 0); /* app name */ - } - aub_out(writer, 0); /* timestamp */ - aub_out(writer, 0); /* timestamp */ - aub_out(writer, 0); /* comment len */ - - /* Set up the GTT. The max we can handle is 256M */ - aub_out(writer, CMD_AUB_TRACE_HEADER_BLOCK | ((writer->gen >= 8 ? 6 : 5) - 2)); - aub_out(writer, - AUB_TRACE_MEMTYPE_GTT_ENTRY | - AUB_TRACE_TYPE_NOTYPE | AUB_TRACE_OP_DATA_WRITE); - aub_out(writer, 0); /* subtype */ - aub_out(writer, 0); /* offset */ - aub_out(writer, gtt_size); /* size */ - if (writer->gen >= 8) - aub_out(writer, 0); - for (i = 0x000; i < gtt_size; i += 4, entry += 0x1000) { - aub_out(writer, entry); - } - - return device->aub_writer = writer; -} - -void -anv_aub_writer_destroy(struct anv_aub_writer *writer) -{ - fclose(writer->file); - free(writer); -} - - -/** - * Break up large objects into multiple writes. Otherwise a 128kb VBO - * would overflow the 16 bits of size field in the packet header and - * everything goes badly after that. - */ -static void -aub_write_trace_block(struct anv_aub_writer *writer, uint32_t type, - void *virtual, uint32_t size, uint32_t gtt_offset) -{ - uint32_t block_size; - uint32_t offset; - uint32_t subtype = 0; - static const char null_block[8 * 4096]; - - for (offset = 0; offset < size; offset += block_size) { - block_size = size - offset; - - if (block_size > 8 * 4096) - block_size = 8 * 4096; - - aub_out(writer, - CMD_AUB_TRACE_HEADER_BLOCK | - ((writer->gen >= 8 ? 6 : 5) - 2)); - aub_out(writer, - AUB_TRACE_MEMTYPE_GTT | - type | AUB_TRACE_OP_DATA_WRITE); - aub_out(writer, subtype); - aub_out(writer, gtt_offset + offset); - aub_out(writer, align_u32(block_size, 4)); - if (writer->gen >= 8) - aub_out(writer, 0); - - if (virtual) - aub_out_data(writer, (char *) virtual + offset, block_size); - else - aub_out_data(writer, null_block, block_size); - - /* Pad to a multiple of 4 bytes. */ - aub_out_data(writer, null_block, -block_size & 3); - } -} - -/* - * Make a ringbuffer on fly and dump it - */ -static void -aub_build_dump_ringbuffer(struct anv_aub_writer *writer, - uint32_t batch_offset, uint32_t offset, - int ring_flag) -{ - uint32_t ringbuffer[4096]; - int ring = AUB_TRACE_TYPE_RING_PRB0; /* The default ring */ - int ring_count = 0; - - if (ring_flag == I915_EXEC_BSD) - ring = AUB_TRACE_TYPE_RING_PRB1; - else if (ring_flag == I915_EXEC_BLT) - ring = AUB_TRACE_TYPE_RING_PRB2; - - /* Make a ring buffer to execute our batchbuffer. */ - memset(ringbuffer, 0, sizeof(ringbuffer)); - if (writer->gen >= 8) { - ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START | (3 - 2); - ringbuffer[ring_count++] = batch_offset; - ringbuffer[ring_count++] = 0; - } else { - ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START; - ringbuffer[ring_count++] = batch_offset; - } - - /* Write out the ring. This appears to trigger execution of - * the ring in the simulator. - */ - aub_out(writer, - CMD_AUB_TRACE_HEADER_BLOCK | - ((writer->gen >= 8 ? 6 : 5) - 2)); - aub_out(writer, - AUB_TRACE_MEMTYPE_GTT | ring | AUB_TRACE_OP_COMMAND_WRITE); - aub_out(writer, 0); /* general/surface subtype */ - aub_out(writer, offset); - aub_out(writer, ring_count * 4); - if (writer->gen >= 8) - aub_out(writer, 0); - - /* FIXME: Need some flush operations here? */ - aub_out_data(writer, ringbuffer, ring_count * 4); -} - -struct aub_bo { - uint32_t offset; - void *map; - void *relocated; -}; - -static void -relocate_bo(struct anv_bo *bo, struct drm_i915_gem_relocation_entry *relocs, - size_t num_relocs, struct aub_bo *bos) -{ - struct aub_bo *aub_bo = &bos[bo->index]; - struct drm_i915_gem_relocation_entry *reloc; - uint32_t *dw; - - aub_bo->relocated = malloc(bo->size); - memcpy(aub_bo->relocated, aub_bo->map, bo->size); - for (size_t i = 0; i < num_relocs; i++) { - reloc = &relocs[i]; - assert(reloc->offset < bo->size); - dw = aub_bo->relocated + reloc->offset; - *dw = bos[reloc->target_handle].offset + reloc->delta; - } -} - -void -anv_cmd_buffer_dump(struct anv_cmd_buffer *cmd_buffer) -{ - struct anv_device *device = cmd_buffer->device; - struct anv_batch *batch = &cmd_buffer->batch; - struct anv_aub_writer *writer; - struct anv_bo *bo; - uint32_t ring_flag = 0; - uint32_t offset; - struct aub_bo *aub_bos; - - writer = get_anv_aub_writer(device); - if (writer == NULL) - return; - - aub_bos = malloc(cmd_buffer->exec2_bo_count * sizeof(aub_bos[0])); - offset = writer->offset; - for (uint32_t i = 0; i < cmd_buffer->exec2_bo_count; i++) { - bo = cmd_buffer->exec2_bos[i]; - if (bo->map) - aub_bos[i].map = bo->map; - else - aub_bos[i].map = anv_gem_mmap(device, bo->gem_handle, 0, bo->size); - aub_bos[i].relocated = aub_bos[i].map; - aub_bos[i].offset = offset; - offset = align_u32(offset + bo->size + 4095, 4096); - } - - struct anv_batch_bo *first_bbo; - for (struct anv_batch_bo *bbo = cmd_buffer->last_batch_bo; - bbo != NULL; bbo = bbo->prev_batch_bo) { - /* Keep stashing the current BO until we get to the beginning */ - first_bbo = bbo; - - /* Handle relocations for this batch BO */ - relocate_bo(&bbo->bo, &batch->relocs.relocs[bbo->first_reloc], - bbo->num_relocs, aub_bos); - } - assert(first_bbo->prev_batch_bo == NULL); - - for (struct anv_batch_bo *bbo = cmd_buffer->surface_batch_bo; - bbo != NULL; bbo = bbo->prev_batch_bo) { - - /* Handle relocations for this surface state BO */ - relocate_bo(&bbo->bo, - &cmd_buffer->surface_relocs.relocs[bbo->first_reloc], - bbo->num_relocs, aub_bos); - } - - for (uint32_t i = 0; i < cmd_buffer->exec2_bo_count; i++) { - bo = cmd_buffer->exec2_bos[i]; - if (i == cmd_buffer->exec2_bo_count - 1) { - assert(bo == &first_bbo->bo); - aub_write_trace_block(writer, AUB_TRACE_TYPE_BATCH, - aub_bos[i].relocated, - first_bbo->length, aub_bos[i].offset); - } else { - aub_write_trace_block(writer, AUB_TRACE_TYPE_NOTYPE, - aub_bos[i].relocated, - bo->size, aub_bos[i].offset); - } - if (aub_bos[i].relocated != aub_bos[i].map) - free(aub_bos[i].relocated); - if (aub_bos[i].map != bo->map) - anv_gem_munmap(aub_bos[i].map, bo->size); - } - - /* Dump ring buffer */ - aub_build_dump_ringbuffer(writer, aub_bos[first_bbo->bo.index].offset, - offset, ring_flag); - - free(aub_bos); - - fflush(writer->file); -} diff --git a/src/vulkan/aub.h b/src/vulkan/aub.h deleted file mode 100644 index 7a67712ff9c..00000000000 --- a/src/vulkan/aub.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - * - * Authors: - * Eric Anholt - * - */ - -/** @file intel_aub.h - * - * The AUB file is a file format used by Intel's internal simulation - * and other validation tools. It can be used at various levels by a - * driver to input state to the simulated hardware or a replaying - * debugger. - * - * We choose to dump AUB files using the trace block format for ease - * of implementation -- dump out the blocks of memory as plain blobs - * and insert ring commands to execute the batchbuffer blob. - */ - -#ifndef _INTEL_AUB_H -#define _INTEL_AUB_H - -#define AUB_MI_NOOP (0) -#define AUB_MI_BATCH_BUFFER_START (0x31 << 23) -#define AUB_PIPE_CONTROL (0x7a000002) - -/* DW0: instruction type. */ - -#define CMD_AUB (7 << 29) - -#define CMD_AUB_HEADER (CMD_AUB | (1 << 23) | (0x05 << 16)) -/* DW1 */ -# define AUB_HEADER_MAJOR_SHIFT 24 -# define AUB_HEADER_MINOR_SHIFT 16 - -#define CMD_AUB_TRACE_HEADER_BLOCK (CMD_AUB | (1 << 23) | (0x41 << 16)) -#define CMD_AUB_DUMP_BMP (CMD_AUB | (1 << 23) | (0x9e << 16)) - -/* DW1 */ -#define AUB_TRACE_OPERATION_MASK 0x000000ff -#define AUB_TRACE_OP_COMMENT 0x00000000 -#define AUB_TRACE_OP_DATA_WRITE 0x00000001 -#define AUB_TRACE_OP_COMMAND_WRITE 0x00000002 -#define AUB_TRACE_OP_MMIO_WRITE 0x00000003 -// operation = TRACE_DATA_WRITE, Type -#define AUB_TRACE_TYPE_MASK 0x0000ff00 -#define AUB_TRACE_TYPE_NOTYPE (0 << 8) -#define AUB_TRACE_TYPE_BATCH (1 << 8) -#define AUB_TRACE_TYPE_VERTEX_BUFFER (5 << 8) -#define AUB_TRACE_TYPE_2D_MAP (6 << 8) -#define AUB_TRACE_TYPE_CUBE_MAP (7 << 8) -#define AUB_TRACE_TYPE_VOLUME_MAP (9 << 8) -#define AUB_TRACE_TYPE_1D_MAP (10 << 8) -#define AUB_TRACE_TYPE_CONSTANT_BUFFER (11 << 8) -#define AUB_TRACE_TYPE_CONSTANT_URB (12 << 8) -#define AUB_TRACE_TYPE_INDEX_BUFFER (13 << 8) -#define AUB_TRACE_TYPE_GENERAL (14 << 8) -#define AUB_TRACE_TYPE_SURFACE (15 << 8) - - -// operation = TRACE_COMMAND_WRITE, Type = -#define AUB_TRACE_TYPE_RING_HWB (1 << 8) -#define AUB_TRACE_TYPE_RING_PRB0 (2 << 8) -#define AUB_TRACE_TYPE_RING_PRB1 (3 << 8) -#define AUB_TRACE_TYPE_RING_PRB2 (4 << 8) - -// Address space -#define AUB_TRACE_ADDRESS_SPACE_MASK 0x00ff0000 -#define AUB_TRACE_MEMTYPE_GTT (0 << 16) -#define AUB_TRACE_MEMTYPE_LOCAL (1 << 16) -#define AUB_TRACE_MEMTYPE_NONLOCAL (2 << 16) -#define AUB_TRACE_MEMTYPE_PCI (3 << 16) -#define AUB_TRACE_MEMTYPE_GTT_ENTRY (4 << 16) - -/* DW2 */ - -/** - * aub_state_struct_type enum values are encoded with the top 16 bits - * representing the type to be delivered to the .aub file, and the bottom 16 - * bits representing the subtype. This macro performs the encoding. - */ -#define ENCODE_SS_TYPE(type, subtype) (((type) << 16) | (subtype)) - -enum aub_state_struct_type { - AUB_TRACE_VS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 1), - AUB_TRACE_GS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 2), - AUB_TRACE_CLIP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 3), - AUB_TRACE_SF_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 4), - AUB_TRACE_WM_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 5), - AUB_TRACE_CC_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 6), - AUB_TRACE_CLIP_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 7), - AUB_TRACE_SF_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 8), - AUB_TRACE_CC_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x9), - AUB_TRACE_SAMPLER_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xa), - AUB_TRACE_KERNEL_INSTRUCTIONS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xb), - AUB_TRACE_SCRATCH_SPACE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xc), - AUB_TRACE_SAMPLER_DEFAULT_COLOR = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xd), - - AUB_TRACE_SCISSOR_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x15), - AUB_TRACE_BLEND_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x16), - AUB_TRACE_DEPTH_STENCIL_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x17), - - AUB_TRACE_VERTEX_BUFFER = ENCODE_SS_TYPE(AUB_TRACE_TYPE_VERTEX_BUFFER, 0), - AUB_TRACE_BINDING_TABLE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x100), - AUB_TRACE_SURFACE_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x200), - AUB_TRACE_VS_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 0), - AUB_TRACE_WM_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 1), -}; - -#undef ENCODE_SS_TYPE - -/** - * Decode a aub_state_struct_type value to determine the type that should be - * stored in the .aub file. - */ -static inline uint32_t AUB_TRACE_TYPE(enum aub_state_struct_type ss_type) -{ - return (ss_type & 0xFFFF0000) >> 16; -} - -/** - * Decode a state_struct_type value to determine the subtype that should be - * stored in the .aub file. - */ -static inline uint32_t AUB_TRACE_SUBTYPE(enum aub_state_struct_type ss_type) -{ - return ss_type & 0xFFFF; -} - -/* DW3: address */ -/* DW4: len */ - -#endif /* _INTEL_AUB_H */ diff --git a/src/vulkan/compiler.cpp b/src/vulkan/compiler.cpp deleted file mode 100644 index 9152de63ec9..00000000000 --- a/src/vulkan/compiler.cpp +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * 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 -#include -#include - -#include "private.h" - -#include -#include /* brw_new_shader_program is here */ -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* XXX: We need this to keep symbols in nir.h from conflicting with the - * generated GEN command packing headers. We need to fix *both* to not - * define something as generic as LOAD. - */ -#undef LOAD - -#include - -#define SPIR_V_MAGIC_NUMBER 0x07230203 - -static void -fail_if(int cond, const char *format, ...) -{ - va_list args; - - if (!cond) - return; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - - exit(1); -} - -static VkResult -set_binding_table_layout(struct brw_stage_prog_data *prog_data, - struct anv_pipeline *pipeline, uint32_t stage) -{ - uint32_t bias, count, k, *map; - struct anv_pipeline_layout *layout = pipeline->layout; - - /* No layout is valid for shaders that don't bind any resources. */ - if (pipeline->layout == NULL) - return VK_SUCCESS; - - if (stage == VK_SHADER_STAGE_FRAGMENT) - bias = MAX_RTS; - else - bias = 0; - - count = layout->stage[stage].surface_count; - prog_data->map_entries = - (uint32_t *) malloc(count * sizeof(prog_data->map_entries[0])); - if (prog_data->map_entries == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - k = bias; - map = prog_data->map_entries; - for (uint32_t i = 0; i < layout->num_sets; i++) { - prog_data->bind_map[i].index = map; - for (uint32_t j = 0; j < layout->set[i].layout->stage[stage].surface_count; j++) - *map++ = k++; - - prog_data->bind_map[i].index_count = - layout->set[i].layout->stage[stage].surface_count; - } - - return VK_SUCCESS; -} - -static void -brw_vs_populate_key(struct brw_context *brw, - struct brw_vertex_program *vp, - struct brw_vs_prog_key *key) -{ - struct gl_context *ctx = &brw->ctx; - /* BRW_NEW_VERTEX_PROGRAM */ - struct gl_program *prog = (struct gl_program *) vp; - - memset(key, 0, sizeof(*key)); - - /* Just upload the program verbatim for now. Always send it all - * the inputs it asks for, whether they are varying or not. - */ - key->base.program_string_id = vp->id; - brw_setup_vue_key_clip_info(brw, &key->base, - vp->program.Base.UsesClipDistanceOut); - - /* _NEW_POLYGON */ - if (brw->gen < 6) { - key->copy_edgeflag = (ctx->Polygon.FrontMode != GL_FILL || - ctx->Polygon.BackMode != GL_FILL); - } - - if (prog->OutputsWritten & (VARYING_BIT_COL0 | VARYING_BIT_COL1 | - VARYING_BIT_BFC0 | VARYING_BIT_BFC1)) { - /* _NEW_LIGHT | _NEW_BUFFERS */ - key->clamp_vertex_color = ctx->Light._ClampVertexColor; - } - - /* _NEW_POINT */ - if (brw->gen < 6 && ctx->Point.PointSprite) { - for (int i = 0; i < 8; i++) { - if (ctx->Point.CoordReplace[i]) - key->point_coord_replace |= (1 << i); - } - } - - /* _NEW_TEXTURE */ - brw_populate_sampler_prog_key_data(ctx, prog, brw->vs.base.sampler_count, - &key->base.tex); -} - -static bool -really_do_vs_prog(struct brw_context *brw, - struct gl_shader_program *prog, - struct brw_vertex_program *vp, - struct brw_vs_prog_key *key, struct anv_pipeline *pipeline) -{ - GLuint program_size; - const GLuint *program; - struct brw_vs_compile c; - struct brw_vs_prog_data *prog_data = &pipeline->vs_prog_data; - struct brw_stage_prog_data *stage_prog_data = &prog_data->base.base; - void *mem_ctx; - struct gl_shader *vs = NULL; - - if (prog) - vs = prog->_LinkedShaders[MESA_SHADER_VERTEX]; - - memset(&c, 0, sizeof(c)); - memcpy(&c.key, key, sizeof(*key)); - memset(prog_data, 0, sizeof(*prog_data)); - - mem_ctx = ralloc_context(NULL); - - c.vp = vp; - - /* Allocate the references to the uniforms that will end up in the - * prog_data associated with the compiled program, and which will be freed - * by the state cache. - */ - int param_count; - if (vs) { - /* We add padding around uniform values below vec4 size, with the worst - * case being a float value that gets blown up to a vec4, so be - * conservative here. - */ - param_count = vs->num_uniform_components * 4; - - } else { - param_count = vp->program.Base.Parameters->NumParameters * 4; - } - /* vec4_visitor::setup_uniform_clipplane_values() also uploads user clip - * planes as uniforms. - */ - param_count += c.key.base.nr_userclip_plane_consts * 4; - - /* Setting nr_params here NOT to the size of the param and pull_param - * arrays, but to the number of uniform components vec4_visitor - * needs. vec4_visitor::setup_uniforms() will set it back to a proper value. - */ - stage_prog_data->nr_params = ALIGN(param_count, 4) / 4; - if (vs) { - stage_prog_data->nr_params += vs->num_samplers; - } - - GLbitfield64 outputs_written = vp->program.Base.OutputsWritten; - prog_data->inputs_read = vp->program.Base.InputsRead; - - if (c.key.copy_edgeflag) { - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_EDGE); - prog_data->inputs_read |= VERT_BIT_EDGEFLAG; - } - - if (brw->gen < 6) { - /* Put dummy slots into the VUE for the SF to put the replaced - * point sprite coords in. We shouldn't need these dummy slots, - * which take up precious URB space, but it would mean that the SF - * doesn't get nice aligned pairs of input coords into output - * coords, which would be a pain to handle. - */ - for (int i = 0; i < 8; i++) { - if (c.key.point_coord_replace & (1 << i)) - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_TEX0 + i); - } - - /* if back colors are written, allocate slots for front colors too */ - if (outputs_written & BITFIELD64_BIT(VARYING_SLOT_BFC0)) - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_COL0); - if (outputs_written & BITFIELD64_BIT(VARYING_SLOT_BFC1)) - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_COL1); - } - - /* In order for legacy clipping to work, we need to populate the clip - * distance varying slots whenever clipping is enabled, even if the vertex - * shader doesn't write to gl_ClipDistance. - */ - if (c.key.base.userclip_active) { - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0); - outputs_written |= BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1); - } - - brw_compute_vue_map(brw->intelScreen->devinfo, - &prog_data->base.vue_map, outputs_written); -\ - set_binding_table_layout(&prog_data->base.base, pipeline, - VK_SHADER_STAGE_VERTEX); - - /* Emit GEN4 code. - */ - program = brw_vs_emit(brw, prog, &c, prog_data, mem_ctx, &program_size); - if (program == NULL) { - ralloc_free(mem_ctx); - return false; - } - - struct anv_state vs_state = anv_state_stream_alloc(&pipeline->program_stream, - program_size, 64); - memcpy(vs_state.map, program, program_size); - - pipeline->vs_simd8 = vs_state.offset; - - ralloc_free(mem_ctx); - - return true; -} - -void brw_wm_populate_key(struct brw_context *brw, - struct brw_fragment_program *fp, - struct brw_wm_prog_key *key) -{ - struct gl_context *ctx = &brw->ctx; - struct gl_program *prog = (struct gl_program *) brw->fragment_program; - GLuint lookup = 0; - GLuint line_aa; - bool program_uses_dfdy = fp->program.UsesDFdy; - struct gl_framebuffer draw_buffer; - bool multisample_fbo; - - memset(key, 0, sizeof(*key)); - - for (int i = 0; i < MAX_SAMPLERS; i++) { - /* Assume color sampler, no swizzling. */ - key->tex.swizzles[i] = SWIZZLE_XYZW; - } - - /* A non-zero framebuffer name indicates that the framebuffer was created by - * the user rather than the window system. */ - draw_buffer.Name = 1; - draw_buffer.Visual.samples = 1; - draw_buffer._NumColorDrawBuffers = 1; - draw_buffer._NumColorDrawBuffers = 1; - draw_buffer.Width = 400; - draw_buffer.Height = 400; - ctx->DrawBuffer = &draw_buffer; - - multisample_fbo = ctx->DrawBuffer->Visual.samples > 1; - - /* Build the index for table lookup - */ - if (brw->gen < 6) { - /* _NEW_COLOR */ - if (fp->program.UsesKill || ctx->Color.AlphaEnabled) - lookup |= IZ_PS_KILL_ALPHATEST_BIT; - - if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) - lookup |= IZ_PS_COMPUTES_DEPTH_BIT; - - /* _NEW_DEPTH */ - if (ctx->Depth.Test) - lookup |= IZ_DEPTH_TEST_ENABLE_BIT; - - if (ctx->Depth.Test && ctx->Depth.Mask) /* ?? */ - lookup |= IZ_DEPTH_WRITE_ENABLE_BIT; - - /* _NEW_STENCIL | _NEW_BUFFERS */ - if (ctx->Stencil._Enabled) { - lookup |= IZ_STENCIL_TEST_ENABLE_BIT; - - if (ctx->Stencil.WriteMask[0] || - ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) - lookup |= IZ_STENCIL_WRITE_ENABLE_BIT; - } - key->iz_lookup = lookup; - } - - line_aa = AA_NEVER; - - /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ - if (ctx->Line.SmoothFlag) { - if (brw->reduced_primitive == GL_LINES) { - line_aa = AA_ALWAYS; - } - else if (brw->reduced_primitive == GL_TRIANGLES) { - if (ctx->Polygon.FrontMode == GL_LINE) { - line_aa = AA_SOMETIMES; - - if (ctx->Polygon.BackMode == GL_LINE || - (ctx->Polygon.CullFlag && - ctx->Polygon.CullFaceMode == GL_BACK)) - line_aa = AA_ALWAYS; - } - else if (ctx->Polygon.BackMode == GL_LINE) { - line_aa = AA_SOMETIMES; - - if ((ctx->Polygon.CullFlag && - ctx->Polygon.CullFaceMode == GL_FRONT)) - line_aa = AA_ALWAYS; - } - } - } - - key->line_aa = line_aa; - - /* _NEW_HINT */ - key->high_quality_derivatives = - ctx->Hint.FragmentShaderDerivative == GL_NICEST; - - if (brw->gen < 6) - key->stats_wm = brw->stats_wm; - - /* _NEW_LIGHT */ - key->flat_shade = (ctx->Light.ShadeModel == GL_FLAT); - - /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ - key->clamp_fragment_color = ctx->Color._ClampFragmentColor; - - /* _NEW_TEXTURE */ - brw_populate_sampler_prog_key_data(ctx, prog, brw->wm.base.sampler_count, - &key->tex); - - /* _NEW_BUFFERS */ - /* - * Include the draw buffer origin and height so that we can calculate - * fragment position values relative to the bottom left of the drawable, - * from the incoming screen origin relative position we get as part of our - * payload. - * - * This is only needed for the WM_WPOSXY opcode when the fragment program - * uses the gl_FragCoord input. - * - * We could avoid recompiling by including this as a constant referenced by - * our program, but if we were to do that it would also be nice to handle - * getting that constant updated at batchbuffer submit time (when we - * hold the lock and know where the buffer really is) rather than at emit - * time when we don't hold the lock and are just guessing. We could also - * just avoid using this as key data if the program doesn't use - * fragment.position. - * - * For DRI2 the origin_x/y will always be (0,0) but we still need the - * drawable height in order to invert the Y axis. - */ - if (fp->program.Base.InputsRead & VARYING_BIT_POS) { - key->drawable_height = ctx->DrawBuffer->Height; - } - - if ((fp->program.Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { - key->render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); - } - - /* _NEW_BUFFERS */ - key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; - - /* _NEW_MULTISAMPLE, _NEW_COLOR, _NEW_BUFFERS */ - key->replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && - (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); - - /* _NEW_BUFFERS _NEW_MULTISAMPLE */ - /* Ignore sample qualifier while computing this flag. */ - key->persample_shading = - _mesa_get_min_invocations_per_fragment(ctx, &fp->program, true) > 1; - if (key->persample_shading) - key->persample_2x = ctx->DrawBuffer->Visual.samples == 2; - - key->compute_pos_offset = - _mesa_get_min_invocations_per_fragment(ctx, &fp->program, false) > 1 && - fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_POS; - - key->compute_sample_id = - multisample_fbo && - ctx->Multisample.Enabled && - (fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_ID); - - /* BRW_NEW_VUE_MAP_GEOM_OUT */ - if (brw->gen < 6 || _mesa_bitcount_64(fp->program.Base.InputsRead & - BRW_FS_VARYING_INPUT_MASK) > 16) - key->input_slots_valid = brw->vue_map_geom_out.slots_valid; - - - /* _NEW_COLOR | _NEW_BUFFERS */ - /* Pre-gen6, the hardware alpha test always used each render - * target's alpha to do alpha test, as opposed to render target 0's alpha - * like GL requires. Fix that by building the alpha test into the - * shader, and we'll skip enabling the fixed function alpha test. - */ - if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { - key->alpha_test_func = ctx->Color.AlphaFunc; - key->alpha_test_ref = ctx->Color.AlphaRef; - } - - /* The unique fragment program ID */ - key->program_string_id = fp->id; - - ctx->DrawBuffer = NULL; -} - -static uint8_t -computed_depth_mode(struct gl_fragment_program *fp) -{ - if (fp->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { - switch (fp->FragDepthLayout) { - case FRAG_DEPTH_LAYOUT_NONE: - case FRAG_DEPTH_LAYOUT_ANY: - return BRW_PSCDEPTH_ON; - case FRAG_DEPTH_LAYOUT_GREATER: - return BRW_PSCDEPTH_ON_GE; - case FRAG_DEPTH_LAYOUT_LESS: - return BRW_PSCDEPTH_ON_LE; - case FRAG_DEPTH_LAYOUT_UNCHANGED: - return BRW_PSCDEPTH_OFF; - } - } - return BRW_PSCDEPTH_OFF; -} - -static bool -really_do_wm_prog(struct brw_context *brw, - struct gl_shader_program *prog, - struct brw_fragment_program *fp, - struct brw_wm_prog_key *key, struct anv_pipeline *pipeline) -{ - struct gl_context *ctx = &brw->ctx; - void *mem_ctx = ralloc_context(NULL); - struct brw_wm_prog_data *prog_data = &pipeline->wm_prog_data; - struct gl_shader *fs = NULL; - unsigned int program_size; - const uint32_t *program; - - if (prog) - fs = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]; - - memset(prog_data, 0, sizeof(*prog_data)); - - /* key->alpha_test_func means simulating alpha testing via discards, - * so the shader definitely kills pixels. - */ - prog_data->uses_kill = fp->program.UsesKill || key->alpha_test_func; - - prog_data->computed_depth_mode = computed_depth_mode(&fp->program); - - /* Allocate the references to the uniforms that will end up in the - * prog_data associated with the compiled program, and which will be freed - * by the state cache. - */ - int param_count; - if (fs) { - param_count = fs->num_uniform_components; - } else { - param_count = fp->program.Base.Parameters->NumParameters * 4; - } - /* The backend also sometimes adds params for texture size. */ - param_count += 2 * ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; - prog_data->base.param = - rzalloc_array(NULL, const gl_constant_value *, param_count); - prog_data->base.pull_param = - rzalloc_array(NULL, const gl_constant_value *, param_count); - prog_data->base.nr_params = param_count; - - prog_data->barycentric_interp_modes = - brw_compute_barycentric_interp_modes(brw, key->flat_shade, - key->persample_shading, - &fp->program); - - set_binding_table_layout(&prog_data->base, pipeline, - VK_SHADER_STAGE_FRAGMENT); - /* This needs to come after shader time and pull constant entries, but we - * don't have those set up now, so just put it after the layout entries. - */ - prog_data->binding_table.render_target_start = 0; - - program = brw_wm_fs_emit(brw, mem_ctx, key, prog_data, - &fp->program, prog, &program_size); - if (program == NULL) { - ralloc_free(mem_ctx); - return false; - } - - struct anv_state ps_state = anv_state_stream_alloc(&pipeline->program_stream, - program_size, 64); - memcpy(ps_state.map, program, program_size); - - if (prog_data->no_8) - pipeline->ps_simd8 = NO_KERNEL; - else - pipeline->ps_simd8 = ps_state.offset; - - if (prog_data->no_8 || prog_data->prog_offset_16) { - pipeline->ps_simd16 = ps_state.offset + prog_data->prog_offset_16; - } else { - pipeline->ps_simd16 = NO_KERNEL; - } - - ralloc_free(mem_ctx); - - return true; -} - -static void -brw_gs_populate_key(struct brw_context *brw, - struct anv_pipeline *pipeline, - struct brw_geometry_program *gp, - struct brw_gs_prog_key *key) -{ - struct gl_context *ctx = &brw->ctx; - struct brw_stage_state *stage_state = &brw->gs.base; - struct gl_program *prog = &gp->program.Base; - - memset(key, 0, sizeof(*key)); - - key->base.program_string_id = gp->id; - brw_setup_vue_key_clip_info(brw, &key->base, - gp->program.Base.UsesClipDistanceOut); - - /* _NEW_TEXTURE */ - brw_populate_sampler_prog_key_data(ctx, prog, stage_state->sampler_count, - &key->base.tex); - - struct brw_vs_prog_data *prog_data = &pipeline->vs_prog_data; - - /* BRW_NEW_VUE_MAP_VS */ - key->input_varyings = prog_data->base.vue_map.slots_valid; -} - -static bool -really_do_gs_prog(struct brw_context *brw, - struct gl_shader_program *prog, - struct brw_geometry_program *gp, - struct brw_gs_prog_key *key, struct anv_pipeline *pipeline) -{ - struct brw_gs_compile_output output; - - /* FIXME: We pass the bind map to the compile in the output struct. Need - * something better. */ - set_binding_table_layout(&output.prog_data.base.base, - pipeline, VK_SHADER_STAGE_GEOMETRY); - - brw_compile_gs_prog(brw, prog, gp, key, &output); - - struct anv_state gs_state = anv_state_stream_alloc(&pipeline->program_stream, - output.program_size, 64); - memcpy(gs_state.map, output.program, output.program_size); - - pipeline->gs_vec4 = gs_state.offset; - pipeline->gs_vertex_count = gp->program.VerticesIn; - - ralloc_free(output.mem_ctx); - - return true; -} - -static bool -brw_codegen_cs_prog(struct brw_context *brw, - struct gl_shader_program *prog, - struct brw_compute_program *cp, - struct brw_cs_prog_key *key, struct anv_pipeline *pipeline) -{ - struct gl_context *ctx = &brw->ctx; - const GLuint *program; - void *mem_ctx = ralloc_context(NULL); - GLuint program_size; - struct brw_cs_prog_data *prog_data = &pipeline->cs_prog_data; - - struct gl_shader *cs = prog->_LinkedShaders[MESA_SHADER_COMPUTE]; - assert (cs); - - memset(prog_data, 0, sizeof(*prog_data)); - - set_binding_table_layout(&prog_data->base, pipeline, VK_SHADER_STAGE_COMPUTE); - - /* Allocate the references to the uniforms that will end up in the - * prog_data associated with the compiled program, and which will be freed - * by the state cache. - */ - int param_count = cs->num_uniform_components; - - /* The backend also sometimes adds params for texture size. */ - param_count += 2 * ctx->Const.Program[MESA_SHADER_COMPUTE].MaxTextureImageUnits; - prog_data->base.param = - rzalloc_array(NULL, const gl_constant_value *, param_count); - prog_data->base.pull_param = - rzalloc_array(NULL, const gl_constant_value *, param_count); - prog_data->base.nr_params = param_count; - - program = brw_cs_emit(brw, mem_ctx, key, prog_data, - &cp->program, prog, &program_size); - if (program == NULL) { - ralloc_free(mem_ctx); - return false; - } - - if (unlikely(INTEL_DEBUG & DEBUG_CS)) - fprintf(stderr, "\n"); - - struct anv_state cs_state = anv_state_stream_alloc(&pipeline->program_stream, - program_size, 64); - memcpy(cs_state.map, program, program_size); - - pipeline->cs_simd = cs_state.offset; - - ralloc_free(mem_ctx); - - return true; -} - -static void -brw_cs_populate_key(struct brw_context *brw, - struct brw_compute_program *bcp, struct brw_cs_prog_key *key) -{ - memset(key, 0, sizeof(*key)); - - /* The unique compute program ID */ - key->program_string_id = bcp->id; -} - -static void -fail_on_compile_error(int status, const char *msg) -{ - int source, line, column; - char error[256]; - - if (status) - return; - - if (sscanf(msg, "%d:%d(%d): error: %255[^\n]", &source, &line, &column, error) == 4) - fail_if(!status, "%d:%s\n", line, error); - else - fail_if(!status, "%s\n", msg); -} - -struct anv_compiler { - struct anv_device *device; - struct intel_screen *screen; - struct brw_context *brw; - struct gl_pipeline_object pipeline; -}; - -extern "C" { - -struct anv_compiler * -anv_compiler_create(struct anv_device *device) -{ - const struct brw_device_info *devinfo = &device->info; - struct anv_compiler *compiler; - struct gl_context *ctx; - - compiler = rzalloc(NULL, struct anv_compiler); - if (compiler == NULL) - return NULL; - - compiler->screen = rzalloc(compiler, struct intel_screen); - if (compiler->screen == NULL) - goto fail; - - compiler->brw = rzalloc(compiler, struct brw_context); - if (compiler->brw == NULL) - goto fail; - - compiler->device = device; - - compiler->brw->optionCache.info = NULL; - compiler->brw->bufmgr = NULL; - compiler->brw->gen = devinfo->gen; - compiler->brw->is_g4x = devinfo->is_g4x; - compiler->brw->is_baytrail = devinfo->is_baytrail; - compiler->brw->is_haswell = devinfo->is_haswell; - compiler->brw->is_cherryview = devinfo->is_cherryview; - - /* We need this at least for CS, which will check brw->max_cs_threads - * against the work group size. */ - compiler->brw->max_vs_threads = devinfo->max_vs_threads; - compiler->brw->max_hs_threads = devinfo->max_hs_threads; - compiler->brw->max_ds_threads = devinfo->max_ds_threads; - compiler->brw->max_gs_threads = devinfo->max_gs_threads; - compiler->brw->max_wm_threads = devinfo->max_wm_threads; - compiler->brw->max_cs_threads = devinfo->max_cs_threads; - compiler->brw->urb.size = devinfo->urb.size; - compiler->brw->urb.min_vs_entries = devinfo->urb.min_vs_entries; - compiler->brw->urb.max_vs_entries = devinfo->urb.max_vs_entries; - compiler->brw->urb.max_hs_entries = devinfo->urb.max_hs_entries; - compiler->brw->urb.max_ds_entries = devinfo->urb.max_ds_entries; - compiler->brw->urb.max_gs_entries = devinfo->urb.max_gs_entries; - - compiler->brw->intelScreen = compiler->screen; - compiler->screen->devinfo = &device->info; - - brw_process_intel_debug_variable(compiler->screen); - - compiler->screen->compiler = brw_compiler_create(compiler, &device->info); - - ctx = &compiler->brw->ctx; - _mesa_init_shader_object_functions(&ctx->Driver); - - _mesa_init_constants(&ctx->Const, API_OPENGL_CORE); - - brw_initialize_context_constants(compiler->brw); - - intelInitExtensions(ctx); - - /* Set dd::NewShader */ - brwInitFragProgFuncs(&ctx->Driver); - - ctx->_Shader = &compiler->pipeline; - - compiler->brw->precompile = false; - - return compiler; - - fail: - ralloc_free(compiler); - return NULL; -} - -void -anv_compiler_destroy(struct anv_compiler *compiler) -{ - _mesa_free_errors_data(&compiler->brw->ctx); - ralloc_free(compiler); -} - -/* From gen7_urb.c */ - -/* FIXME: Add to struct intel_device_info */ - -static const int gen8_push_size = 32 * 1024; - -static void -gen7_compute_urb_partition(struct anv_pipeline *pipeline) -{ - const struct brw_device_info *devinfo = &pipeline->device->info; - bool vs_present = pipeline->vs_simd8 != NO_KERNEL; - unsigned vs_size = vs_present ? pipeline->vs_prog_data.base.urb_entry_size : 1; - unsigned vs_entry_size_bytes = vs_size * 64; - bool gs_present = pipeline->gs_vec4 != NO_KERNEL; - unsigned gs_size = gs_present ? pipeline->gs_prog_data.base.urb_entry_size : 1; - unsigned gs_entry_size_bytes = gs_size * 64; - - /* From p35 of the Ivy Bridge PRM (section 1.7.1: 3DSTATE_URB_GS): - * - * VS Number of URB Entries must be divisible by 8 if the VS URB Entry - * Allocation Size is less than 9 512-bit URB entries. - * - * Similar text exists for GS. - */ - unsigned vs_granularity = (vs_size < 9) ? 8 : 1; - unsigned gs_granularity = (gs_size < 9) ? 8 : 1; - - /* URB allocations must be done in 8k chunks. */ - unsigned chunk_size_bytes = 8192; - - /* Determine the size of the URB in chunks. */ - unsigned urb_chunks = devinfo->urb.size * 1024 / chunk_size_bytes; - - /* Reserve space for push constants */ - unsigned push_constant_bytes = gen8_push_size; - unsigned push_constant_chunks = - push_constant_bytes / chunk_size_bytes; - - /* Initially, assign each stage the minimum amount of URB space it needs, - * and make a note of how much additional space it "wants" (the amount of - * additional space it could actually make use of). - */ - - /* VS has a lower limit on the number of URB entries */ - unsigned vs_chunks = - ALIGN(devinfo->urb.min_vs_entries * vs_entry_size_bytes, - chunk_size_bytes) / chunk_size_bytes; - unsigned vs_wants = - ALIGN(devinfo->urb.max_vs_entries * vs_entry_size_bytes, - chunk_size_bytes) / chunk_size_bytes - vs_chunks; - - unsigned gs_chunks = 0; - unsigned gs_wants = 0; - if (gs_present) { - /* There are two constraints on the minimum amount of URB space we can - * allocate: - * - * (1) We need room for at least 2 URB entries, since we always operate - * the GS in DUAL_OBJECT mode. - * - * (2) We can't allocate less than nr_gs_entries_granularity. - */ - gs_chunks = ALIGN(MAX2(gs_granularity, 2) * gs_entry_size_bytes, - chunk_size_bytes) / chunk_size_bytes; - gs_wants = - ALIGN(devinfo->urb.max_gs_entries * gs_entry_size_bytes, - chunk_size_bytes) / chunk_size_bytes - gs_chunks; - } - - /* There should always be enough URB space to satisfy the minimum - * requirements of each stage. - */ - unsigned total_needs = push_constant_chunks + vs_chunks + gs_chunks; - assert(total_needs <= urb_chunks); - - /* Mete out remaining space (if any) in proportion to "wants". */ - unsigned total_wants = vs_wants + gs_wants; - unsigned remaining_space = urb_chunks - total_needs; - if (remaining_space > total_wants) - remaining_space = total_wants; - if (remaining_space > 0) { - unsigned vs_additional = (unsigned) - round(vs_wants * (((double) remaining_space) / total_wants)); - vs_chunks += vs_additional; - remaining_space -= vs_additional; - gs_chunks += remaining_space; - } - - /* Sanity check that we haven't over-allocated. */ - assert(push_constant_chunks + vs_chunks + gs_chunks <= urb_chunks); - - /* Finally, compute the number of entries that can fit in the space - * allocated to each stage. - */ - unsigned nr_vs_entries = vs_chunks * chunk_size_bytes / vs_entry_size_bytes; - unsigned nr_gs_entries = gs_chunks * chunk_size_bytes / gs_entry_size_bytes; - - /* Since we rounded up when computing *_wants, this may be slightly more - * than the maximum allowed amount, so correct for that. - */ - nr_vs_entries = MIN2(nr_vs_entries, devinfo->urb.max_vs_entries); - nr_gs_entries = MIN2(nr_gs_entries, devinfo->urb.max_gs_entries); - - /* Ensure that we program a multiple of the granularity. */ - nr_vs_entries = ROUND_DOWN_TO(nr_vs_entries, vs_granularity); - nr_gs_entries = ROUND_DOWN_TO(nr_gs_entries, gs_granularity); - - /* Finally, sanity check to make sure we have at least the minimum number - * of entries needed for each stage. - */ - assert(nr_vs_entries >= devinfo->urb.min_vs_entries); - if (gs_present) - assert(nr_gs_entries >= 2); - - /* Lay out the URB in the following order: - * - push constants - * - VS - * - GS - */ - pipeline->urb.vs_start = push_constant_chunks; - pipeline->urb.vs_size = vs_size; - pipeline->urb.nr_vs_entries = nr_vs_entries; - - pipeline->urb.gs_start = push_constant_chunks + vs_chunks; - pipeline->urb.gs_size = gs_size; - pipeline->urb.nr_gs_entries = nr_gs_entries; -} - -static const struct { - uint32_t token; - gl_shader_stage stage; - const char *name; -} stage_info[] = { - { GL_VERTEX_SHADER, MESA_SHADER_VERTEX, "vertex" }, - { GL_TESS_CONTROL_SHADER, (gl_shader_stage)-1,"tess control" }, - { GL_TESS_EVALUATION_SHADER, (gl_shader_stage)-1, "tess evaluation" }, - { GL_GEOMETRY_SHADER, MESA_SHADER_GEOMETRY, "geometry" }, - { GL_FRAGMENT_SHADER, MESA_SHADER_FRAGMENT, "fragment" }, - { GL_COMPUTE_SHADER, MESA_SHADER_COMPUTE, "compute" }, -}; - -struct spirv_header{ - uint32_t magic; - uint32_t version; - uint32_t gen_magic; -}; - -static const char * -src_as_glsl(const char *data) -{ - const struct spirv_header *as_spirv = (const struct spirv_header *)data; - - /* Check alignment */ - if ((intptr_t)data & 0x3) { - return data; - } - - if (as_spirv->magic == SPIR_V_MAGIC_NUMBER) { - /* LunarG back-door */ - if (as_spirv->version == 0) - return data + 12; - else - return NULL; - } else { - return data; - } -} - -static void -anv_compile_shader_glsl(struct anv_compiler *compiler, - struct gl_shader_program *program, - struct anv_pipeline *pipeline, uint32_t stage) -{ - struct brw_context *brw = compiler->brw; - struct gl_shader *shader; - int name = 0; - - shader = brw_new_shader(&brw->ctx, name, stage_info[stage].token); - fail_if(shader == NULL, "failed to create %s shader\n", stage_info[stage].name); - - shader->Source = strdup(src_as_glsl(pipeline->shaders[stage]->module->data)); - _mesa_glsl_compile_shader(&brw->ctx, shader, false, false); - fail_on_compile_error(shader->CompileStatus, shader->InfoLog); - - program->Shaders[program->NumShaders] = shader; - program->NumShaders++; -} - -static void -setup_nir_io(struct gl_program *prog, - nir_shader *shader) -{ - foreach_list_typed(nir_variable, var, node, &shader->inputs) { - prog->InputsRead |= BITFIELD64_BIT(var->data.location); - } - - foreach_list_typed(nir_variable, var, node, &shader->outputs) { - prog->OutputsWritten |= BITFIELD64_BIT(var->data.location); - } -} - -static void -anv_compile_shader_spirv(struct anv_compiler *compiler, - struct gl_shader_program *program, - struct anv_pipeline *pipeline, uint32_t stage) -{ - struct brw_context *brw = compiler->brw; - struct anv_shader *shader = pipeline->shaders[stage]; - struct gl_shader *mesa_shader; - int name = 0; - - mesa_shader = brw_new_shader(&brw->ctx, name, stage_info[stage].token); - fail_if(mesa_shader == NULL, - "failed to create %s shader\n", stage_info[stage].name); - - switch (stage) { - case VK_SHADER_STAGE_VERTEX: - mesa_shader->Program = &rzalloc(mesa_shader, struct brw_vertex_program)->program.Base; - break; - case VK_SHADER_STAGE_GEOMETRY: - mesa_shader->Program = &rzalloc(mesa_shader, struct brw_geometry_program)->program.Base; - break; - case VK_SHADER_STAGE_FRAGMENT: - mesa_shader->Program = &rzalloc(mesa_shader, struct brw_fragment_program)->program.Base; - break; - case VK_SHADER_STAGE_COMPUTE: - mesa_shader->Program = &rzalloc(mesa_shader, struct brw_compute_program)->program.Base; - break; - } - - mesa_shader->Program->Parameters = - rzalloc(mesa_shader, struct gl_program_parameter_list); - - mesa_shader->Type = stage_info[stage].token; - mesa_shader->Stage = stage_info[stage].stage; - - assert(shader->module->size % 4 == 0); - - struct gl_shader_compiler_options *glsl_options = - &compiler->screen->compiler->glsl_compiler_options[stage_info[stage].stage]; - - mesa_shader->Program->nir = - spirv_to_nir((uint32_t *)shader->module->data, shader->module->size / 4, - glsl_options->NirOptions); - nir_validate_shader(mesa_shader->Program->nir); - - brw_process_nir(mesa_shader->Program->nir, - compiler->screen->devinfo, - NULL, mesa_shader->Stage); - - setup_nir_io(mesa_shader->Program, mesa_shader->Program->nir); - - fail_if(mesa_shader->Program->nir == NULL, - "failed to translate SPIR-V to NIR\n"); - - program->Shaders[program->NumShaders] = mesa_shader; - program->NumShaders++; -} - -static void -add_compiled_stage(struct anv_pipeline *pipeline, uint32_t stage, - struct brw_stage_prog_data *prog_data) -{ - struct brw_device_info *devinfo = &pipeline->device->info; - uint32_t max_threads[] = { - [VK_SHADER_STAGE_VERTEX] = devinfo->max_vs_threads, - [VK_SHADER_STAGE_TESS_CONTROL] = 0, - [VK_SHADER_STAGE_TESS_EVALUATION] = 0, - [VK_SHADER_STAGE_GEOMETRY] = devinfo->max_gs_threads, - [VK_SHADER_STAGE_FRAGMENT] = devinfo->max_wm_threads, - [VK_SHADER_STAGE_COMPUTE] = devinfo->max_cs_threads, - }; - - pipeline->prog_data[stage] = prog_data; - pipeline->active_stages |= 1 << stage; - pipeline->scratch_start[stage] = pipeline->total_scratch; - pipeline->total_scratch = - align_u32(pipeline->total_scratch, 1024) + - prog_data->total_scratch * max_threads[stage]; -} - -int -anv_compiler_run(struct anv_compiler *compiler, struct anv_pipeline *pipeline) -{ - struct gl_shader_program *program; - int name = 0; - struct brw_context *brw = compiler->brw; - - pipeline->writes_point_size = false; - - /* When we free the pipeline, we detect stages based on the NULL status - * of various prog_data pointers. Make them NULL by default. - */ - memset(pipeline->prog_data, 0, sizeof(pipeline->prog_data)); - memset(pipeline->scratch_start, 0, sizeof(pipeline->scratch_start)); - - brw->use_rep_send = pipeline->use_repclear; - brw->no_simd8 = pipeline->use_repclear; - - program = brw->ctx.Driver.NewShaderProgram(name); - program->Shaders = (struct gl_shader **) - calloc(VK_SHADER_STAGE_NUM, sizeof(struct gl_shader *)); - fail_if(program == NULL || program->Shaders == NULL, - "failed to create program\n"); - - bool all_spirv = true; - for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { - if (pipeline->shaders[i] == NULL) - continue; - - /* You need at least this much for "void main() { }" anyway */ - assert(pipeline->shaders[i]->module->size >= 12); - - if (src_as_glsl(pipeline->shaders[i]->module->data)) { - all_spirv = false; - break; - } - - assert(pipeline->shaders[i]->module->size % 4 == 0); - } - - if (all_spirv) { - for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { - if (pipeline->shaders[i]) - anv_compile_shader_spirv(compiler, program, pipeline, i); - } - - for (unsigned i = 0; i < program->NumShaders; i++) { - struct gl_shader *shader = program->Shaders[i]; - program->_LinkedShaders[shader->Stage] = shader; - } - } else { - for (unsigned i = 0; i < VK_SHADER_STAGE_NUM; i++) { - if (pipeline->shaders[i]) - anv_compile_shader_glsl(compiler, program, pipeline, i); - } - - _mesa_glsl_link_shader(&brw->ctx, program); - fail_on_compile_error(program->LinkStatus, - program->InfoLog); - } - - bool success; - pipeline->active_stages = 0; - pipeline->total_scratch = 0; - - if (pipeline->shaders[VK_SHADER_STAGE_VERTEX]) { - struct brw_vs_prog_key vs_key; - struct gl_vertex_program *vp = (struct gl_vertex_program *) - program->_LinkedShaders[MESA_SHADER_VERTEX]->Program; - struct brw_vertex_program *bvp = brw_vertex_program(vp); - - brw_vs_populate_key(brw, bvp, &vs_key); - - success = really_do_vs_prog(brw, program, bvp, &vs_key, pipeline); - fail_if(!success, "do_wm_prog failed\n"); - add_compiled_stage(pipeline, VK_SHADER_STAGE_VERTEX, - &pipeline->vs_prog_data.base.base); - - if (vp->Base.OutputsWritten & VARYING_SLOT_PSIZ) - pipeline->writes_point_size = true; - } else { - memset(&pipeline->vs_prog_data, 0, sizeof(pipeline->vs_prog_data)); - pipeline->vs_simd8 = NO_KERNEL; - } - - - if (pipeline->shaders[VK_SHADER_STAGE_GEOMETRY]) { - struct brw_gs_prog_key gs_key; - struct gl_geometry_program *gp = (struct gl_geometry_program *) - program->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program; - struct brw_geometry_program *bgp = brw_geometry_program(gp); - - brw_gs_populate_key(brw, pipeline, bgp, &gs_key); - - success = really_do_gs_prog(brw, program, bgp, &gs_key, pipeline); - fail_if(!success, "do_gs_prog failed\n"); - add_compiled_stage(pipeline, VK_SHADER_STAGE_GEOMETRY, - &pipeline->gs_prog_data.base.base); - - if (gp->Base.OutputsWritten & VARYING_SLOT_PSIZ) - pipeline->writes_point_size = true; - } else { - pipeline->gs_vec4 = NO_KERNEL; - } - - if (pipeline->shaders[VK_SHADER_STAGE_FRAGMENT]) { - struct brw_wm_prog_key wm_key; - struct gl_fragment_program *fp = (struct gl_fragment_program *) - program->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program; - struct brw_fragment_program *bfp = brw_fragment_program(fp); - - brw_wm_populate_key(brw, bfp, &wm_key); - - success = really_do_wm_prog(brw, program, bfp, &wm_key, pipeline); - fail_if(!success, "do_wm_prog failed\n"); - add_compiled_stage(pipeline, VK_SHADER_STAGE_FRAGMENT, - &pipeline->wm_prog_data.base); - } - - if (pipeline->shaders[VK_SHADER_STAGE_COMPUTE]) { - struct brw_cs_prog_key cs_key; - struct gl_compute_program *cp = (struct gl_compute_program *) - program->_LinkedShaders[MESA_SHADER_COMPUTE]->Program; - struct brw_compute_program *bcp = brw_compute_program(cp); - - brw_cs_populate_key(brw, bcp, &cs_key); - - success = brw_codegen_cs_prog(brw, program, bcp, &cs_key, pipeline); - fail_if(!success, "brw_codegen_cs_prog failed\n"); - add_compiled_stage(pipeline, VK_SHADER_STAGE_COMPUTE, - &pipeline->cs_prog_data.base); - } - - /* XXX: Deleting the shader is broken with our current SPIR-V hacks. We - * need to fix this ASAP. - */ - if (!all_spirv) - brw->ctx.Driver.DeleteShaderProgram(&brw->ctx, program); - - struct anv_device *device = compiler->device; - while (device->scratch_block_pool.bo.size < pipeline->total_scratch) - anv_block_pool_alloc(&device->scratch_block_pool); - - gen7_compute_urb_partition(pipeline); - - return 0; -} - -/* This badly named function frees the struct anv_pipeline data that the compiler - * allocates. Currently just the prog_data structs. - */ -void -anv_compiler_free(struct anv_pipeline *pipeline) -{ - for (uint32_t stage = 0; stage < VK_SHADER_STAGE_NUM; stage++) { - if (pipeline->prog_data[stage]) { - free(pipeline->prog_data[stage]->map_entries); - ralloc_free(pipeline->prog_data[stage]->param); - ralloc_free(pipeline->prog_data[stage]->pull_param); - } - } -} - -} diff --git a/src/vulkan/device.c b/src/vulkan/device.c deleted file mode 100644 index 1073ab00ad4..00000000000 --- a/src/vulkan/device.c +++ /dev/null @@ -1,2390 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" -#include "mesa/main/git_sha1.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 void -anv_physical_device_finish(struct anv_physical_device *device) -{ - if (device->fd >= 0) - close(device->fd); -} - -static VkResult -anv_physical_device_init(struct anv_physical_device *device, - struct anv_instance *instance, - const char *path) -{ - device->fd = open(path, O_RDWR | O_CLOEXEC); - if (device->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(device->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(device->fd, I915_PARAM_HAS_WAIT_TIMEOUT)) - goto fail; - - if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_EXECBUF2)) - goto fail; - - if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_LLC)) - goto fail; - - if (!anv_gem_get_param(device->fd, I915_PARAM_HAS_EXEC_CONSTANTS)) - goto fail; - - return VK_SUCCESS; - -fail: - anv_physical_device_finish(device); - 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; - - 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; - - *pInstance = anv_instance_to_handle(instance); - - return VK_SUCCESS; -} - -VkResult anv_DestroyInstance( - VkInstance _instance) -{ - ANV_FROM_HANDLE(anv_instance, instance, _instance); - - if (instance->physicalDeviceCount > 0) { - anv_physical_device_finish(&instance->physicalDevice); - } - - instance->pfnFree(instance->pAllocUserData, instance); - - return VK_SUCCESS; -} - -VkResult anv_EnumeratePhysicalDevices( - VkInstance _instance, - uint32_t* pPhysicalDeviceCount, - VkPhysicalDevice* pPhysicalDevices) -{ - ANV_FROM_HANDLE(anv_instance, instance, _instance); - VkResult result; - - if (instance->physicalDeviceCount == 0) { - result = anv_physical_device_init(&instance->physicalDevice, - instance, "/dev/dri/renderD128"); - if (result != VK_SUCCESS) - return result; - - instance->physicalDeviceCount = 1; - } - - /* pPhysicalDeviceCount is an out parameter if pPhysicalDevices is NULL; - * otherwise it's an inout parameter. - * - * The Vulkan spec (git aaed022) says: - * - * pPhysicalDeviceCount is a pointer to an unsigned integer variable - * that is initialized with the number of devices the application is - * prepared to receive handles to. pname:pPhysicalDevices is pointer to - * an array of at least this many VkPhysicalDevice handles [...]. - * - * Upon success, if pPhysicalDevices is NULL, vkEnumeratePhysicalDevices - * overwrites the contents of the variable pointed to by - * pPhysicalDeviceCount with the number of physical devices in in the - * instance; otherwise, vkEnumeratePhysicalDevices overwrites - * pPhysicalDeviceCount with the number of physical handles written to - * pPhysicalDevices. - */ - if (!pPhysicalDevices) { - *pPhysicalDeviceCount = instance->physicalDeviceCount; - } else if (*pPhysicalDeviceCount >= 1) { - pPhysicalDevices[0] = anv_physical_device_to_handle(&instance->physicalDevice); - *pPhysicalDeviceCount = 1; - } else { - *pPhysicalDeviceCount = 0; - } - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceFeatures( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures* pFeatures) -{ - anv_finishme("Get correct values for PhysicalDeviceFeatures"); - - *pFeatures = (VkPhysicalDeviceFeatures) { - .robustBufferAccess = false, - .fullDrawIndexUint32 = false, - .imageCubeArray = false, - .independentBlend = false, - .geometryShader = true, - .tessellationShader = false, - .sampleRateShading = false, - .dualSourceBlend = true, - .logicOp = true, - .instancedDrawIndirect = true, - .depthClip = false, - .depthBiasClamp = false, - .fillModeNonSolid = true, - .depthBounds = false, - .wideLines = true, - .largePoints = true, - .textureCompressionETC2 = true, - .textureCompressionASTC_LDR = true, - .textureCompressionBC = true, - .pipelineStatisticsQuery = true, - .vertexSideEffects = false, - .tessellationSideEffects = false, - .geometrySideEffects = false, - .fragmentSideEffects = false, - .shaderTessellationPointSize = false, - .shaderGeometryPointSize = true, - .shaderTextureGatherExtended = true, - .shaderStorageImageExtendedFormats = false, - .shaderStorageImageMultisample = false, - .shaderStorageBufferArrayConstantIndexing = false, - .shaderStorageImageArrayConstantIndexing = false, - .shaderUniformBufferArrayDynamicIndexing = true, - .shaderSampledImageArrayDynamicIndexing = false, - .shaderStorageBufferArrayDynamicIndexing = false, - .shaderStorageImageArrayDynamicIndexing = false, - .shaderClipDistance = false, - .shaderCullDistance = false, - .shaderFloat64 = false, - .shaderInt64 = false, - .shaderFloat16 = false, - .shaderInt16 = false, - }; - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceLimits( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceLimits* pLimits) -{ - ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); - const struct brw_device_info *devinfo = physical_device->info; - - anv_finishme("Get correct values for PhysicalDeviceLimits"); - - *pLimits = (VkPhysicalDeviceLimits) { - .maxImageDimension1D = (1 << 14), - .maxImageDimension2D = (1 << 14), - .maxImageDimension3D = (1 << 10), - .maxImageDimensionCube = (1 << 14), - .maxImageArrayLayers = (1 << 10), - .maxTexelBufferSize = (1 << 14), - .maxUniformBufferSize = UINT32_MAX, - .maxStorageBufferSize = UINT32_MAX, - .maxPushConstantsSize = 128, - .maxMemoryAllocationCount = UINT32_MAX, - .bufferImageGranularity = 64, /* A cache line */ - .maxBoundDescriptorSets = MAX_SETS, - .maxDescriptorSets = UINT32_MAX, - .maxPerStageDescriptorSamplers = 64, - .maxPerStageDescriptorUniformBuffers = 64, - .maxPerStageDescriptorStorageBuffers = 64, - .maxPerStageDescriptorSampledImages = 64, - .maxPerStageDescriptorStorageImages = 64, - .maxDescriptorSetSamplers = 256, - .maxDescriptorSetUniformBuffers = 256, - .maxDescriptorSetStorageBuffers = 256, - .maxDescriptorSetSampledImages = 256, - .maxDescriptorSetStorageImages = 256, - .maxVertexInputAttributes = 32, - .maxVertexInputAttributeOffset = 256, - .maxVertexInputBindingStride = 256, - .maxVertexOutputComponents = 32, - .maxTessGenLevel = 0, - .maxTessPatchSize = 0, - .maxTessControlPerVertexInputComponents = 0, - .maxTessControlPerVertexOutputComponents = 0, - .maxTessControlPerPatchOutputComponents = 0, - .maxTessControlTotalOutputComponents = 0, - .maxTessEvaluationInputComponents = 0, - .maxTessEvaluationOutputComponents = 0, - .maxGeometryShaderInvocations = 6, - .maxGeometryInputComponents = 16, - .maxGeometryOutputComponents = 16, - .maxGeometryOutputVertices = 16, - .maxGeometryTotalOutputComponents = 16, - .maxFragmentInputComponents = 16, - .maxFragmentOutputBuffers = 8, - .maxFragmentDualSourceBuffers = 2, - .maxFragmentCombinedOutputResources = 8, - .maxComputeSharedMemorySize = 1024, - .maxComputeWorkGroupCount = { - 16 * devinfo->max_cs_threads, - 16 * devinfo->max_cs_threads, - 16 * devinfo->max_cs_threads, - }, - .maxComputeWorkGroupInvocations = 16 * devinfo->max_cs_threads, - .maxComputeWorkGroupSize = { - 16 * devinfo->max_cs_threads, - 16 * devinfo->max_cs_threads, - 16 * devinfo->max_cs_threads, - }, - .subPixelPrecisionBits = 4 /* FIXME */, - .subTexelPrecisionBits = 4 /* FIXME */, - .mipmapPrecisionBits = 4 /* FIXME */, - .maxDrawIndexedIndexValue = UINT32_MAX, - .maxDrawIndirectInstanceCount = UINT32_MAX, - .primitiveRestartForPatches = UINT32_MAX, - .maxSamplerLodBias = 16, - .maxSamplerAnisotropy = 16, - .maxViewports = 16, - .maxDynamicViewportStates = UINT32_MAX, - .maxViewportDimensions = { (1 << 14), (1 << 14) }, - .viewportBoundsRange = { -1.0, 1.0 }, /* FIXME */ - .viewportSubPixelBits = 13, /* We take a float? */ - .minMemoryMapAlignment = 64, /* A cache line */ - .minTexelBufferOffsetAlignment = 1, - .minUniformBufferOffsetAlignment = 1, - .minStorageBufferOffsetAlignment = 1, - .minTexelOffset = 0, /* FIXME */ - .maxTexelOffset = 0, /* FIXME */ - .minTexelGatherOffset = 0, /* FIXME */ - .maxTexelGatherOffset = 0, /* FIXME */ - .minInterpolationOffset = 0, /* FIXME */ - .maxInterpolationOffset = 0, /* FIXME */ - .subPixelInterpolationOffsetBits = 0, /* FIXME */ - .maxFramebufferWidth = (1 << 14), - .maxFramebufferHeight = (1 << 14), - .maxFramebufferLayers = (1 << 10), - .maxFramebufferColorSamples = 8, - .maxFramebufferDepthSamples = 8, - .maxFramebufferStencilSamples = 8, - .maxColorAttachments = MAX_RTS, - .maxSampledImageColorSamples = 8, - .maxSampledImageDepthSamples = 8, - .maxSampledImageIntegerSamples = 1, - .maxStorageImageSamples = 1, - .maxSampleMaskWords = 1, - .timestampFrequency = 1000 * 1000 * 1000 / 80, - .maxClipDistances = 0 /* FIXME */, - .maxCullDistances = 0 /* FIXME */, - .maxCombinedClipAndCullDistances = 0 /* FIXME */, - .pointSizeRange = { 0.125, 255.875 }, - .lineWidthRange = { 0.0, 7.9921875 }, - .pointSizeGranularity = (1.0 / 8.0), - .lineWidthGranularity = (1.0 / 128.0), - }; - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties* pProperties) -{ - ANV_FROM_HANDLE(anv_physical_device, pdevice, physicalDevice); - - *pProperties = (VkPhysicalDeviceProperties) { - .apiVersion = 1, - .driverVersion = 1, - .vendorId = 0x8086, - .deviceId = pdevice->chipset_id, - .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, - }; - - strcpy(pProperties->deviceName, pdevice->name); - snprintf((char *)pProperties->pipelineCacheUUID, VK_UUID_LENGTH, - "anv-%s", MESA_GIT_SHA1 + 4); - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceQueueCount( - VkPhysicalDevice physicalDevice, - uint32_t* pCount) -{ - *pCount = 1; - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceQueueProperties( - VkPhysicalDevice physicalDevice, - uint32_t count, - VkPhysicalDeviceQueueProperties* pQueueProperties) -{ - assert(count == 1); - - *pQueueProperties = (VkPhysicalDeviceQueueProperties) { - .queueFlags = VK_QUEUE_GRAPHICS_BIT | - VK_QUEUE_COMPUTE_BIT | - VK_QUEUE_DMA_BIT, - .queueCount = 1, - .supportsTimestamps = true, - }; - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties* pMemoryProperties) -{ - ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); - - size_t aperture_size; - size_t heap_size; - - if (anv_gem_get_aperture(physical_device, &aperture_size) == -1) - return vk_error(VK_ERROR_UNAVAILABLE); - - /* Reserve some wiggle room for the driver by exposing only 75% of the - * aperture to the heap. - */ - heap_size = 3 * aperture_size / 4; - - /* The property flags below are valid only for llc platforms. */ - pMemoryProperties->memoryTypeCount = 1; - pMemoryProperties->memoryTypes[0] = (VkMemoryType) { - .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .heapIndex = 1, - }; - - pMemoryProperties->memoryHeapCount = 1; - pMemoryProperties->memoryHeaps[0] = (VkMemoryHeap) { - .size = heap_size, - .flags = VK_MEMORY_HEAP_HOST_LOCAL, - }; - - return VK_SUCCESS; -} - -PFN_vkVoidFunction anv_GetInstanceProcAddr( - VkInstance instance, - const char* pName) -{ - return anv_lookup_entrypoint(pName); -} - -PFN_vkVoidFunction anv_GetDeviceProcAddr( - VkDevice device, - 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; - } - } -} - -static VkResult -anv_queue_init(struct anv_device *device, struct anv_queue *queue) -{ - queue->device = device; - queue->pool = &device->surface_state_pool; - - queue->completed_serial = anv_state_pool_alloc(queue->pool, 4, 4); - if (queue->completed_serial.map == NULL) - return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); - - *(uint32_t *)queue->completed_serial.map = 0; - queue->next_serial = 1; - - return VK_SUCCESS; -} - -static void -anv_queue_finish(struct anv_queue *queue) -{ -#ifdef HAVE_VALGRIND - /* This gets torn down with the device so we only need to do this if - * valgrind is present. - */ - anv_state_pool_free(queue->pool, queue->completed_serial); -#endif -} - -static void -anv_device_init_border_colors(struct anv_device *device) -{ - static const VkClearColorValue border_colors[] = { - [VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK] = { .f32 = { 0.0, 0.0, 0.0, 0.0 } }, - [VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK] = { .f32 = { 0.0, 0.0, 0.0, 1.0 } }, - [VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE] = { .f32 = { 1.0, 1.0, 1.0, 1.0 } }, - [VK_BORDER_COLOR_INT_TRANSPARENT_BLACK] = { .u32 = { 0, 0, 0, 0 } }, - [VK_BORDER_COLOR_INT_OPAQUE_BLACK] = { .u32 = { 0, 0, 0, 1 } }, - [VK_BORDER_COLOR_INT_OPAQUE_WHITE] = { .u32 = { 1, 1, 1, 1 } }, - }; - - device->border_colors = - anv_state_pool_alloc(&device->dynamic_state_pool, - sizeof(border_colors), 32); - memcpy(device->border_colors.map, border_colors, sizeof(border_colors)); -} - -static const uint32_t BATCH_SIZE = 8192; - -VkResult anv_CreateDevice( - VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo* pCreateInfo, - VkDevice* pDevice) -{ - ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); - struct anv_instance *instance = physical_device->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 = physical_device->no_hw; - parse_debug_flags(device); - - device->instance = physical_device->instance; - - /* XXX(chadv): Can we dup() physicalDevice->fd here? */ - device->fd = open(physical_device->path, 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_bo_pool_init(&device->batch_bo_pool, device, BATCH_SIZE); - - anv_block_pool_init(&device->dynamic_state_block_pool, device, 2048); - - anv_state_pool_init(&device->dynamic_state_pool, - &device->dynamic_state_block_pool); - - anv_block_pool_init(&device->instruction_block_pool, device, 2048); - anv_block_pool_init(&device->surface_state_block_pool, device, 2048); - - anv_state_pool_init(&device->surface_state_pool, - &device->surface_state_block_pool); - - anv_block_pool_init(&device->scratch_block_pool, device, 0x10000); - - device->info = *physical_device->info; - - device->compiler = anv_compiler_create(device); - device->aub_writer = NULL; - - pthread_mutex_init(&device->mutex, NULL); - - anv_queue_init(device, &device->queue); - - anv_device_init_meta(device); - - anv_device_init_border_colors(device); - - *pDevice = anv_device_to_handle(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) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - anv_compiler_destroy(device->compiler); - - anv_queue_finish(&device->queue); - - anv_device_finish_meta(device); - -#ifdef HAVE_VALGRIND - /* We only need to free these to prevent valgrind errors. The backing - * BO will go away in a couple of lines so we don't actually leak. - */ - anv_state_pool_free(&device->dynamic_state_pool, device->border_colors); -#endif - - anv_bo_pool_finish(&device->batch_bo_pool); - 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; -} - -static const VkExtensionProperties global_extensions[] = { - { - .extName = "VK_WSI_LunarG", - .specVersion = 3 - } -}; - -VkResult anv_GetGlobalExtensionProperties( - const char* pLayerName, - uint32_t* pCount, - VkExtensionProperties* pProperties) -{ - if (pProperties == NULL) { - *pCount = ARRAY_SIZE(global_extensions); - return VK_SUCCESS; - } - - assert(*pCount < ARRAY_SIZE(global_extensions)); - - *pCount = ARRAY_SIZE(global_extensions); - memcpy(pProperties, global_extensions, sizeof(global_extensions)); - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - uint32_t* pCount, - VkExtensionProperties* pProperties) -{ - if (pProperties == NULL) { - *pCount = 0; - return VK_SUCCESS; - } - - /* None supported at this time */ - return vk_error(VK_ERROR_INVALID_EXTENSION); -} - -VkResult anv_GetGlobalLayerProperties( - uint32_t* pCount, - VkLayerProperties* pProperties) -{ - if (pProperties == NULL) { - *pCount = 0; - return VK_SUCCESS; - } - - /* None supported at this time */ - return vk_error(VK_ERROR_INVALID_LAYER); -} - -VkResult anv_GetPhysicalDeviceLayerProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pCount, - VkLayerProperties* pProperties) -{ - if (pProperties == NULL) { - *pCount = 0; - return VK_SUCCESS; - } - - /* None supported at this time */ - return vk_error(VK_ERROR_INVALID_LAYER); -} - -VkResult anv_GetDeviceQueue( - VkDevice _device, - uint32_t queueNodeIndex, - uint32_t queueIndex, - VkQueue* pQueue) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - assert(queueIndex == 0); - - *pQueue = anv_queue_to_handle(&device->queue); - - return VK_SUCCESS; -} - -VkResult anv_QueueSubmit( - VkQueue _queue, - uint32_t cmdBufferCount, - const VkCmdBuffer* pCmdBuffers, - VkFence _fence) -{ - ANV_FROM_HANDLE(anv_queue, queue, _queue); - ANV_FROM_HANDLE(anv_fence, fence, _fence); - struct anv_device *device = queue->device; - int ret; - - for (uint32_t i = 0; i < cmdBufferCount; i++) { - ANV_FROM_HANDLE(anv_cmd_buffer, 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->exec2_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_QueueWaitIdle( - VkQueue _queue) -{ - ANV_FROM_HANDLE(anv_queue, queue, _queue); - - return vkDeviceWaitIdle(anv_device_to_handle(queue->device)); -} - -VkResult anv_DeviceWaitIdle( - VkDevice _device) -{ - ANV_FROM_HANDLE(anv_device, 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.start = batch.next = state.map; - batch.end = state.map + 32; - 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) -{ - if (mem == NULL) - return; - - 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) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_device_memory *mem; - VkResult result; - - assert(pAllocInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO); - - if (pAllocInfo->memoryTypeIndex != 0) { - /* We support exactly one memory heap. */ - return vk_error(VK_ERROR_INVALID_VALUE); - } - - /* FINISHME: Fail if allocation request exceeds heap size. */ - - 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 = anv_device_memory_to_handle(mem); - - return VK_SUCCESS; - - fail: - anv_device_free(device, mem); - - return result; -} - -VkResult anv_FreeMemory( - VkDevice _device, - VkDeviceMemory _mem) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_device_memory, mem, _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_MapMemory( - VkDevice _device, - VkDeviceMemory _mem, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - void** ppData) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_device_memory, mem, _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) -{ - ANV_FROM_HANDLE(anv_device_memory, mem, _mem); - - anv_gem_munmap(mem->map, mem->map_size); - - return VK_SUCCESS; -} - -VkResult anv_FlushMappedMemoryRanges( - VkDevice device, - uint32_t memRangeCount, - const VkMappedMemoryRange* pMemRanges) -{ - /* clflush here for !llc platforms */ - - return VK_SUCCESS; -} - -VkResult anv_InvalidateMappedMemoryRanges( - VkDevice device, - uint32_t memRangeCount, - const VkMappedMemoryRange* pMemRanges) -{ - return anv_FlushMappedMemoryRanges(device, memRangeCount, pMemRanges); -} - -VkResult anv_GetBufferMemoryRequirements( - VkDevice device, - VkBuffer _buffer, - VkMemoryRequirements* pMemoryRequirements) -{ - ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); - - /* The Vulkan spec (git aaed022) says: - * - * memoryTypeBits is a bitfield and contains one bit set for every - * supported memory type for the resource. The bit `1<memoryTypeBits = 1; - - pMemoryRequirements->size = buffer->size; - pMemoryRequirements->alignment = 16; - - return VK_SUCCESS; -} - -VkResult anv_GetImageMemoryRequirements( - VkDevice device, - VkImage _image, - VkMemoryRequirements* pMemoryRequirements) -{ - ANV_FROM_HANDLE(anv_image, image, _image); - - /* The Vulkan spec (git aaed022) says: - * - * memoryTypeBits is a bitfield and contains one bit set for every - * supported memory type for the resource. The bit `1<memoryTypeBits = 1; - - pMemoryRequirements->size = image->size; - pMemoryRequirements->alignment = image->alignment; - - return VK_SUCCESS; -} - -VkResult anv_GetImageSparseMemoryRequirements( - VkDevice device, - VkImage image, - uint32_t* pNumRequirements, - VkSparseImageMemoryRequirements* pSparseMemoryRequirements) -{ - return vk_error(VK_UNSUPPORTED); -} - -VkResult anv_GetDeviceMemoryCommitment( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize* pCommittedMemoryInBytes) -{ - *pCommittedMemoryInBytes = 0; - stub_return(VK_SUCCESS); -} - -VkResult anv_BindBufferMemory( - VkDevice device, - VkBuffer _buffer, - VkDeviceMemory _mem, - VkDeviceSize memOffset) -{ - ANV_FROM_HANDLE(anv_device_memory, mem, _mem); - ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); - - buffer->bo = &mem->bo; - buffer->offset = memOffset; - - return VK_SUCCESS; -} - -VkResult anv_BindImageMemory( - VkDevice device, - VkImage _image, - VkDeviceMemory _mem, - VkDeviceSize memOffset) -{ - ANV_FROM_HANDLE(anv_device_memory, mem, _mem); - ANV_FROM_HANDLE(anv_image, image, _image); - - image->bo = &mem->bo; - image->offset = memOffset; - - return VK_SUCCESS; -} - -VkResult anv_QueueBindSparseBufferMemory( - VkQueue queue, - VkBuffer buffer, - uint32_t numBindings, - const VkSparseMemoryBindInfo* pBindInfo) -{ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_QueueBindSparseImageOpaqueMemory( - VkQueue queue, - VkImage image, - uint32_t numBindings, - const VkSparseMemoryBindInfo* pBindInfo) -{ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_QueueBindSparseImageMemory( - VkQueue queue, - VkImage image, - uint32_t numBindings, - const VkSparseImageMemoryBindInfo* pBindInfo) -{ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_CreateFence( - VkDevice _device, - const VkFenceCreateInfo* pCreateInfo, - VkFence* pFence) -{ - ANV_FROM_HANDLE(anv_device, 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 = batch.start = fence->bo.map; - batch.end = fence->bo.map + fence->bo.size; - 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 = anv_fence_to_handle(fence); - - return VK_SUCCESS; - - fail: - anv_device_free(device, fence); - - return result; -} - -VkResult anv_DestroyFence( - VkDevice _device, - VkFence _fence) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_fence, fence, _fence); - - 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; -} - -VkResult anv_ResetFences( - VkDevice _device, - uint32_t fenceCount, - const VkFence* pFences) -{ - for (uint32_t i = 0; i < fenceCount; i++) { - ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); - fence->ready = false; - } - - return VK_SUCCESS; -} - -VkResult anv_GetFenceStatus( - VkDevice _device, - VkFence _fence) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_fence, 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, - VkBool32 waitAll, - uint64_t timeout) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - int64_t t = timeout; - int ret; - - /* FIXME: handle !waitAll */ - - for (uint32_t i = 0; i < fenceCount; i++) { - ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); - ret = anv_gem_wait(device, fence->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_DestroySemaphore( - VkDevice device, - VkSemaphore semaphore) -{ - 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_DestroyEvent( - VkDevice device, - VkEvent event) -{ - 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); -} - -// Buffer functions - -VkResult anv_CreateBuffer( - VkDevice _device, - const VkBufferCreateInfo* pCreateInfo, - VkBuffer* pBuffer) -{ - ANV_FROM_HANDLE(anv_device, 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 = anv_buffer_to_handle(buffer); - - return VK_SUCCESS; -} - -VkResult anv_DestroyBuffer( - VkDevice _device, - VkBuffer _buffer) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_buffer, buffer, _buffer); - - anv_device_free(device, buffer); - - return VK_SUCCESS; -} - -// Buffer view functions - -void -anv_fill_buffer_surface_state(void *state, VkFormat format, - uint32_t offset, uint32_t range) -{ - const struct anv_format *info; - - info = anv_format_for_vk_format(format); - /* This assumes RGBA float format. */ - uint32_t stride = 4; - uint32_t num_elements = range / stride; - - struct GEN8_RENDER_SURFACE_STATE surface_state = { - .SurfaceType = SURFTYPE_BUFFER, - .SurfaceArray = false, - .SurfaceFormat = info->surface_format, - .SurfaceVerticalAlignment = VALIGN4, - .SurfaceHorizontalAlignment = HALIGN4, - .TileMode = LINEAR, - .VerticalLineStride = 0, - .VerticalLineStrideOffset = 0, - .SamplerL2BypassModeDisable = true, - .RenderCacheReadWriteMode = WriteOnlyCache, - .MemoryObjectControlState = GEN8_MOCS, - .BaseMipLevel = 0.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.0, - /* FIXME: We assume that the image must be bound at this time. */ - .SurfaceBaseAddress = { NULL, offset }, - }; - - GEN8_RENDER_SURFACE_STATE_pack(NULL, state, &surface_state); -} - -VkResult anv_CreateBufferView( - VkDevice _device, - const VkBufferViewCreateInfo* pCreateInfo, - VkBufferView* pView) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_buffer, buffer, pCreateInfo->buffer); - struct anv_buffer_view *bview; - struct anv_surface_view *view; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO); - - bview = anv_device_alloc(device, sizeof(*view), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (bview == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - view = &bview->view; - 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; - view->range = pCreateInfo->range; - - anv_fill_buffer_surface_state(view->surface_state.map, - pCreateInfo->format, - view->offset, pCreateInfo->range); - - *pView = anv_buffer_view_to_handle(bview); - - return VK_SUCCESS; -} - -VkResult anv_DestroyBufferView( - VkDevice _device, - VkBufferView _bview) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_buffer_view, bview, _bview); - - anv_surface_view_fini(device, &bview->view); - anv_device_free(device, bview); - - return VK_SUCCESS; -} - -// Sampler functions - -VkResult anv_CreateSampler( - VkDevice _device, - const VkSamplerCreateInfo* pCreateInfo, - VkSampler* pSampler) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_sampler *sampler; - uint32_t mag_filter, min_filter, max_anisotropy; - - 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 > 1) { - mag_filter = MAPFILTER_ANISOTROPIC; - min_filter = MAPFILTER_ANISOTROPIC; - max_anisotropy = (pCreateInfo->maxAnisotropy - 2) / 2; - } else { - mag_filter = vk_to_gen_tex_filter[pCreateInfo->magFilter]; - min_filter = vk_to_gen_tex_filter[pCreateInfo->minFilter]; - max_anisotropy = RATIO21; - } - - struct GEN8_SAMPLER_STATE sampler_state = { - .SamplerDisable = false, - .TextureBorderColorMode = DX10OGL, - .LODPreClampMode = 0, - .BaseMipLevel = 0.0, - .MipModeFilter = vk_to_gen_mipmap_mode[pCreateInfo->mipMode], - .MagModeFilter = mag_filter, - .MinModeFilter = min_filter, - .TextureLODBias = pCreateInfo->mipLodBias * 256, - .AnisotropicAlgorithm = EWAApproximation, - .MinLOD = pCreateInfo->minLod, - .MaxLOD = pCreateInfo->maxLod, - .ChromaKeyEnable = 0, - .ChromaKeyIndex = 0, - .ChromaKeyMode = 0, - .ShadowFunction = vk_to_gen_compare_op[pCreateInfo->compareOp], - .CubeSurfaceControlMode = 0, - - .IndirectStatePointer = - device->border_colors.offset + - pCreateInfo->borderColor * sizeof(float) * 4, - - .LODClampMagnificationMode = MIPNONE, - .MaximumAnisotropy = max_anisotropy, - .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 = anv_sampler_to_handle(sampler); - - return VK_SUCCESS; -} - -VkResult anv_DestroySampler( - VkDevice _device, - VkSampler _sampler) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_sampler, sampler, _sampler); - - anv_device_free(device, sampler); - - return VK_SUCCESS; -} - -// Descriptor set functions - -VkResult anv_CreateDescriptorSetLayout( - VkDevice _device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayout* pSetLayout) -{ - ANV_FROM_HANDLE(anv_device, 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_SHADER_STAGE_NUM] = { 0, }; - uint32_t surface_count[VK_SHADER_STAGE_NUM] = { 0, }; - uint32_t num_dynamic_buffers = 0; - uint32_t count = 0; - uint32_t stages = 0; - uint32_t s; - - for (uint32_t i = 0; i < pCreateInfo->count; i++) { - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) - sampler_count[s] += pCreateInfo->pBinding[i].arraySize; - break; - default: - break; - } - - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - 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: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) - surface_count[s] += pCreateInfo->pBinding[i].arraySize; - break; - default: - break; - } - - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - num_dynamic_buffers += pCreateInfo->pBinding[i].arraySize; - break; - default: - break; - } - - stages |= pCreateInfo->pBinding[i].stageFlags; - count += pCreateInfo->pBinding[i].arraySize; - } - - uint32_t sampler_total = 0; - uint32_t surface_total = 0; - for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { - sampler_total += sampler_count[s]; - surface_total += surface_count[s]; - } - - size_t size = sizeof(*set_layout) + - (sampler_total + surface_total) * sizeof(set_layout->entries[0]); - set_layout = anv_device_alloc(device, size, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (!set_layout) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - set_layout->num_dynamic_buffers = num_dynamic_buffers; - set_layout->count = count; - set_layout->shader_stages = stages; - - struct anv_descriptor_slot *p = set_layout->entries; - struct anv_descriptor_slot *sampler[VK_SHADER_STAGE_NUM]; - struct anv_descriptor_slot *surface[VK_SHADER_STAGE_NUM]; - for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; 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; - int8_t dynamic_slot = 0; - bool is_dynamic; - for (uint32_t i = 0; i < pCreateInfo->count; i++) { - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) - for (uint32_t j = 0; j < pCreateInfo->pBinding[i].arraySize; j++) { - sampler[s]->index = descriptor + j; - sampler[s]->dynamic_slot = -1; - sampler[s]++; - } - break; - default: - break; - } - - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - is_dynamic = true; - break; - default: - is_dynamic = false; - break; - } - - switch (pCreateInfo->pBinding[i].descriptorType) { - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - 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: - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - for_each_bit(s, pCreateInfo->pBinding[i].stageFlags) - for (uint32_t j = 0; j < pCreateInfo->pBinding[i].arraySize; j++) { - surface[s]->index = descriptor + j; - if (is_dynamic) - surface[s]->dynamic_slot = dynamic_slot + j; - else - surface[s]->dynamic_slot = -1; - surface[s]++; - } - break; - default: - break; - } - - if (is_dynamic) - dynamic_slot += pCreateInfo->pBinding[i].arraySize; - - descriptor += pCreateInfo->pBinding[i].arraySize; - } - - *pSetLayout = anv_descriptor_set_layout_to_handle(set_layout); - - return VK_SUCCESS; -} - -VkResult anv_DestroyDescriptorSetLayout( - VkDevice _device, - VkDescriptorSetLayout _set_layout) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout, _set_layout); - - anv_device_free(device, set_layout); - - return VK_SUCCESS; -} - -VkResult anv_CreateDescriptorPool( - VkDevice device, - VkDescriptorPoolUsage poolUsage, - uint32_t maxSets, - const VkDescriptorPoolCreateInfo* pCreateInfo, - VkDescriptorPool* pDescriptorPool) -{ - anv_finishme("VkDescriptorPool is a stub"); - pDescriptorPool->handle = 1; - return VK_SUCCESS; -} - -VkResult anv_DestroyDescriptorPool( - VkDevice _device, - VkDescriptorPool _pool) -{ - anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets"); - return VK_SUCCESS; -} - -VkResult anv_ResetDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool) -{ - anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets"); - return VK_SUCCESS; -} - -VkResult -anv_descriptor_set_create(struct anv_device *device, - const struct anv_descriptor_set_layout *layout, - struct anv_descriptor_set **out_set) -{ - struct anv_descriptor_set *set; - size_t size = sizeof(*set) + layout->count * sizeof(set->descriptors[0]); - - set = anv_device_alloc(device, size, 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (!set) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - /* A descriptor set may not be 100% filled. Clear the set so we can can - * later detect holes in it. - */ - memset(set, 0, size); - - *out_set = set; - - return VK_SUCCESS; -} - -void -anv_descriptor_set_destroy(struct anv_device *device, - struct anv_descriptor_set *set) -{ - anv_device_free(device, set); -} - -VkResult anv_AllocDescriptorSets( - VkDevice _device, - VkDescriptorPool descriptorPool, - VkDescriptorSetUsage setUsage, - uint32_t count, - const VkDescriptorSetLayout* pSetLayouts, - VkDescriptorSet* pDescriptorSets, - uint32_t* pCount) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - VkResult result; - struct anv_descriptor_set *set; - - for (uint32_t i = 0; i < count; i++) { - ANV_FROM_HANDLE(anv_descriptor_set_layout, layout, pSetLayouts[i]); - - result = anv_descriptor_set_create(device, layout, &set); - if (result != VK_SUCCESS) { - *pCount = i; - return result; - } - - pDescriptorSets[i] = anv_descriptor_set_to_handle(set); - } - - *pCount = count; - - return VK_SUCCESS; -} - -VkResult anv_UpdateDescriptorSets( - VkDevice device, - uint32_t writeCount, - const VkWriteDescriptorSet* pDescriptorWrites, - uint32_t copyCount, - const VkCopyDescriptorSet* pDescriptorCopies) -{ - for (uint32_t i = 0; i < writeCount; i++) { - const VkWriteDescriptorSet *write = &pDescriptorWrites[i]; - ANV_FROM_HANDLE(anv_descriptor_set, set, write->destSet); - - switch (write->descriptorType) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - for (uint32_t j = 0; j < write->count; j++) { - set->descriptors[write->destBinding + j].sampler = - anv_sampler_from_handle(write->pDescriptors[j].sampler); - } - - if (write->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) - break; - - /* fallthrough */ - - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - for (uint32_t j = 0; j < write->count; j++) { - ANV_FROM_HANDLE(anv_image_view, iview, - write->pDescriptors[j].imageView); - set->descriptors[write->destBinding + j].view = &iview->view; - } - break; - - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - anv_finishme("texel buffers not implemented"); - break; - - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - anv_finishme("input attachments not implemented"); - break; - - 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 (uint32_t j = 0; j < write->count; j++) { - ANV_FROM_HANDLE(anv_buffer_view, bview, - write->pDescriptors[j].bufferView); - set->descriptors[write->destBinding + j].view = &bview->view; - } - - default: - break; - } - } - - for (uint32_t i = 0; i < copyCount; i++) { - const VkCopyDescriptorSet *copy = &pDescriptorCopies[i]; - ANV_FROM_HANDLE(anv_descriptor_set, src, copy->destSet); - ANV_FROM_HANDLE(anv_descriptor_set, dest, copy->destSet); - for (uint32_t j = 0; j < copy->count; j++) { - dest->descriptors[copy->destBinding + j] = - src->descriptors[copy->srcBinding + j]; - } - } - - return VK_SUCCESS; -} - -// 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 VkDynamicViewportStateCreateInfo* pCreateInfo, - VkDynamicViewportState* pState) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_dynamic_vp_state *state; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_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 VkRect2D *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 = anv_dynamic_vp_state_to_handle(state); - - return VK_SUCCESS; -} - -VkResult anv_DestroyDynamicViewportState( - VkDevice _device, - VkDynamicViewportState _vp_state) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_dynamic_vp_state, vp_state, _vp_state); - - anv_state_pool_free(&device->dynamic_state_pool, vp_state->sf_clip_vp); - anv_state_pool_free(&device->dynamic_state_pool, vp_state->cc_vp); - anv_state_pool_free(&device->dynamic_state_pool, vp_state->scissor); - - anv_device_free(device, vp_state); - - return VK_SUCCESS; -} - -VkResult anv_CreateDynamicRasterState( - VkDevice _device, - const VkDynamicRasterStateCreateInfo* pCreateInfo, - VkDynamicRasterState* pState) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_dynamic_rs_state *state; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_RASTER_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); - - struct GEN8_3DSTATE_SF sf = { - GEN8_3DSTATE_SF_header, - .LineWidth = pCreateInfo->lineWidth, - }; - - GEN8_3DSTATE_SF_pack(NULL, state->state_sf, &sf); - - bool enable_bias = pCreateInfo->depthBias != 0.0f || - pCreateInfo->slopeScaledDepthBias != 0.0f; - struct GEN8_3DSTATE_RASTER raster = { - .GlobalDepthOffsetEnableSolid = enable_bias, - .GlobalDepthOffsetEnableWireframe = enable_bias, - .GlobalDepthOffsetEnablePoint = enable_bias, - .GlobalDepthOffsetConstant = pCreateInfo->depthBias, - .GlobalDepthOffsetScale = pCreateInfo->slopeScaledDepthBias, - .GlobalDepthOffsetClamp = pCreateInfo->depthBiasClamp - }; - - GEN8_3DSTATE_RASTER_pack(NULL, state->state_raster, &raster); - - *pState = anv_dynamic_rs_state_to_handle(state); - - return VK_SUCCESS; -} - -VkResult anv_DestroyDynamicRasterState( - VkDevice _device, - VkDynamicRasterState _rs_state) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_dynamic_rs_state, rs_state, _rs_state); - - anv_device_free(device, rs_state); - - return VK_SUCCESS; -} - -VkResult anv_CreateDynamicColorBlendState( - VkDevice _device, - const VkDynamicColorBlendStateCreateInfo* pCreateInfo, - VkDynamicColorBlendState* pState) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_dynamic_cb_state *state; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_COLOR_BLEND_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); - - struct GEN8_COLOR_CALC_STATE color_calc_state = { - .BlendConstantColorRed = pCreateInfo->blendConst[0], - .BlendConstantColorGreen = pCreateInfo->blendConst[1], - .BlendConstantColorBlue = pCreateInfo->blendConst[2], - .BlendConstantColorAlpha = pCreateInfo->blendConst[3] - }; - - GEN8_COLOR_CALC_STATE_pack(NULL, state->state_color_calc, &color_calc_state); - - *pState = anv_dynamic_cb_state_to_handle(state); - - return VK_SUCCESS; -} - -VkResult anv_DestroyDynamicColorBlendState( - VkDevice _device, - VkDynamicColorBlendState _cb_state) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_dynamic_cb_state, cb_state, _cb_state); - - anv_device_free(device, cb_state); - - return VK_SUCCESS; -} - -VkResult anv_CreateDynamicDepthStencilState( - VkDevice _device, - const VkDynamicDepthStencilStateCreateInfo* pCreateInfo, - VkDynamicDepthStencilState* pState) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_dynamic_ds_state *state; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_STENCIL_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); - - struct GEN8_3DSTATE_WM_DEPTH_STENCIL wm_depth_stencil = { - GEN8_3DSTATE_WM_DEPTH_STENCIL_header, - - /* Is this what we need to do? */ - .StencilBufferWriteEnable = pCreateInfo->stencilWriteMask != 0, - - .StencilTestMask = pCreateInfo->stencilReadMask & 0xff, - .StencilWriteMask = pCreateInfo->stencilWriteMask & 0xff, - - .BackfaceStencilTestMask = pCreateInfo->stencilReadMask & 0xff, - .BackfaceStencilWriteMask = pCreateInfo->stencilWriteMask & 0xff, - }; - - GEN8_3DSTATE_WM_DEPTH_STENCIL_pack(NULL, state->state_wm_depth_stencil, - &wm_depth_stencil); - - struct GEN8_COLOR_CALC_STATE color_calc_state = { - .StencilReferenceValue = pCreateInfo->stencilFrontRef, - .BackFaceStencilReferenceValue = pCreateInfo->stencilBackRef - }; - - GEN8_COLOR_CALC_STATE_pack(NULL, state->state_color_calc, &color_calc_state); - - *pState = anv_dynamic_ds_state_to_handle(state); - - return VK_SUCCESS; -} - -VkResult anv_DestroyDynamicDepthStencilState( - VkDevice _device, - VkDynamicDepthStencilState _ds_state) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_dynamic_ds_state, ds_state, _ds_state); - - anv_device_free(device, ds_state); - - return VK_SUCCESS; -} - -// Command buffer functions - -VkResult anv_CreateCommandPool( - VkDevice device, - const VkCmdPoolCreateInfo* pCreateInfo, - VkCmdPool* pCmdPool) -{ - pCmdPool->handle = 7; - - stub_return(VK_SUCCESS); -} - -VkResult anv_DestroyCommandPool( - VkDevice device, - VkCmdPool cmdPool) -{ - stub_return(VK_SUCCESS); -} - -VkResult anv_ResetCommandPool( - VkDevice device, - VkCmdPool cmdPool, - VkCmdPoolResetFlags flags) -{ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_CreateFramebuffer( - VkDevice _device, - const VkFramebufferCreateInfo* pCreateInfo, - VkFramebuffer* pFramebuffer) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_framebuffer *framebuffer; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); - - size_t size = sizeof(*framebuffer) + - sizeof(struct anv_attachment_view *) * pCreateInfo->attachmentCount; - framebuffer = anv_device_alloc(device, size, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (framebuffer == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - framebuffer->attachment_count = pCreateInfo->attachmentCount; - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - ANV_FROM_HANDLE(anv_attachment_view, view, - pCreateInfo->pAttachments[i].view); - - framebuffer->attachments[i] = view; - } - - framebuffer->width = pCreateInfo->width; - framebuffer->height = pCreateInfo->height; - framebuffer->layers = pCreateInfo->layers; - - anv_CreateDynamicViewportState(anv_device_to_handle(device), - &(VkDynamicViewportStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_STATE_CREATE_INFO, - .viewportAndScissorCount = 1, - .pViewports = (VkViewport[]) { - { - .originX = 0, - .originY = 0, - .width = pCreateInfo->width, - .height = pCreateInfo->height, - .minDepth = 0, - .maxDepth = 1 - }, - }, - .pScissors = (VkRect2D[]) { - { { 0, 0 }, - { pCreateInfo->width, pCreateInfo->height } }, - } - }, - &framebuffer->vp_state); - - *pFramebuffer = anv_framebuffer_to_handle(framebuffer); - - return VK_SUCCESS; -} - -VkResult anv_DestroyFramebuffer( - VkDevice _device, - VkFramebuffer _fb) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_framebuffer, fb, _fb); - - anv_DestroyDynamicViewportState(anv_device_to_handle(device), - fb->vp_state); - anv_device_free(device, fb); - - return VK_SUCCESS; -} - -VkResult anv_CreateRenderPass( - VkDevice _device, - const VkRenderPassCreateInfo* pCreateInfo, - VkRenderPass* pRenderPass) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_render_pass *pass; - size_t size; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); - - size = sizeof(*pass) + - pCreateInfo->subpassCount * sizeof(struct anv_subpass); - 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); - - /* Clear the subpasses along with the parent pass. This required because - * each array member of anv_subpass must be a valid pointer if not NULL. - */ - memset(pass, 0, size); - - pass->attachment_count = pCreateInfo->attachmentCount; - pass->subpass_count = pCreateInfo->subpassCount; - - size = pCreateInfo->attachmentCount * sizeof(*pass->attachments); - pass->attachments = anv_device_alloc(device, size, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - pass->attachments[i].format = pCreateInfo->pAttachments[i].format; - pass->attachments[i].samples = pCreateInfo->pAttachments[i].samples; - pass->attachments[i].load_op = pCreateInfo->pAttachments[i].loadOp; - pass->attachments[i].stencil_load_op = pCreateInfo->pAttachments[i].stencilLoadOp; - // pass->attachments[i].store_op = pCreateInfo->pAttachments[i].storeOp; - // pass->attachments[i].stencil_store_op = pCreateInfo->pAttachments[i].stencilStoreOp; - } - - for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { - const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i]; - struct anv_subpass *subpass = &pass->subpasses[i]; - - subpass->input_count = desc->inputCount; - subpass->color_count = desc->colorCount; - - if (desc->inputCount > 0) { - subpass->input_attachments = - anv_device_alloc(device, desc->inputCount * sizeof(uint32_t), - 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - - for (uint32_t j = 0; j < desc->inputCount; j++) { - subpass->input_attachments[j] - = desc->inputAttachments[j].attachment; - } - } - - if (desc->colorCount > 0) { - subpass->color_attachments = - anv_device_alloc(device, desc->colorCount * sizeof(uint32_t), - 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - - for (uint32_t j = 0; j < desc->colorCount; j++) { - subpass->color_attachments[j] - = desc->colorAttachments[j].attachment; - } - } - - if (desc->resolveAttachments) { - subpass->resolve_attachments = - anv_device_alloc(device, desc->colorCount * sizeof(uint32_t), - 8, VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - - for (uint32_t j = 0; j < desc->colorCount; j++) { - subpass->resolve_attachments[j] - = desc->resolveAttachments[j].attachment; - } - } - - subpass->depth_stencil_attachment = desc->depthStencilAttachment.attachment; - } - - *pRenderPass = anv_render_pass_to_handle(pass); - - return VK_SUCCESS; -} - -VkResult anv_DestroyRenderPass( - VkDevice _device, - VkRenderPass _pass) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_render_pass, pass, _pass); - - anv_device_free(device, pass->attachments); - - for (uint32_t i = 0; i < pass->subpass_count; i++) { - /* In VkSubpassCreateInfo, each of the attachment arrays may be null. - * Don't free the null arrays. - */ - struct anv_subpass *subpass = &pass->subpasses[i]; - - anv_device_free(device, subpass->input_attachments); - anv_device_free(device, subpass->color_attachments); - anv_device_free(device, subpass->resolve_attachments); - } - - anv_device_free(device, pass); - - return VK_SUCCESS; -} - -VkResult anv_GetRenderAreaGranularity( - VkDevice device, - VkRenderPass renderPass, - VkExtent2D* pGranularity) -{ - *pGranularity = (VkExtent2D) { 1, 1 }; - - return VK_SUCCESS; -} - -void vkCmdDbgMarkerBegin( - VkCmdBuffer cmdBuffer, - const char* pMarker) - __attribute__ ((visibility ("default"))); - -void vkCmdDbgMarkerEnd( - VkCmdBuffer cmdBuffer) - __attribute__ ((visibility ("default"))); - -void vkCmdDbgMarkerBegin( - VkCmdBuffer cmdBuffer, - const char* pMarker) -{ -} - -void vkCmdDbgMarkerEnd( - VkCmdBuffer cmdBuffer) -{ -} diff --git a/src/vulkan/formats.c b/src/vulkan/formats.c deleted file mode 100644 index 9d9294b7ebd..00000000000 --- a/src/vulkan/formats.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * 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 "private.h" - -#define UNSUPPORTED 0xffff - -#define fmt(__vk_fmt, ...) \ - [__vk_fmt] = { .name = #__vk_fmt, __VA_ARGS__ } - -static const struct anv_format anv_formats[] = { - fmt(VK_FORMAT_UNDEFINED, RAW, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R4G4_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_R4G4_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_R4G4B4A4_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_R4G4B4A4_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_R5G6B5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_R5G6B5_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_R5G5B5A1_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_R5G5B5A1_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_R8_UNORM, R8_UNORM, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R8_SNORM, R8_SNORM, .cpp = 1, .num_channels = 1,), - fmt(VK_FORMAT_R8_USCALED, R8_USCALED, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R8_SSCALED, R8_SSCALED, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R8_UINT, R8_UINT, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R8_SINT, R8_SINT, .cpp = 1, .num_channels = 1), - fmt(VK_FORMAT_R8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_R8G8_UNORM, R8G8_UNORM, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_SNORM, R8G8_SNORM, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_USCALED, R8G8_USCALED, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_SSCALED, R8G8_SSCALED, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_UINT, R8G8_UINT, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_SINT, R8G8_SINT, .cpp = 2, .num_channels = 2), - fmt(VK_FORMAT_R8G8_SRGB, UNSUPPORTED), /* L8A8_UNORM_SRGB */ - fmt(VK_FORMAT_R8G8B8_UNORM, R8G8B8X8_UNORM, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_SNORM, R8G8B8_SNORM, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_USCALED, R8G8B8_USCALED, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_SSCALED, R8G8B8_SSCALED, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_UINT, R8G8B8_UINT, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_SINT, R8G8B8_SINT, .cpp = 3, .num_channels = 3), - fmt(VK_FORMAT_R8G8B8_SRGB, UNSUPPORTED), /* B8G8R8A8_UNORM_SRGB */ - fmt(VK_FORMAT_R8G8B8A8_UNORM, R8G8B8A8_UNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_SNORM, R8G8B8A8_SNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_USCALED, R8G8B8A8_USCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_SSCALED, R8G8B8A8_SSCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_UINT, R8G8B8A8_UINT, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_SINT, R8G8B8A8_SINT, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R8G8B8A8_SRGB, R8G8B8A8_UNORM_SRGB, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_UNORM, R10G10B10A2_UNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_SNORM, R10G10B10A2_SNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_USCALED, R10G10B10A2_USCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_SSCALED, R10G10B10A2_SSCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_UINT, R10G10B10A2_UINT, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R10G10B10A2_SINT, R10G10B10A2_SINT, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_R16_UNORM, R16_UNORM, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_SNORM, R16_SNORM, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_USCALED, R16_USCALED, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_SSCALED, R16_SSCALED, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_UINT, R16_UINT, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_SINT, R16_SINT, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16_SFLOAT, R16_FLOAT, .cpp = 2, .num_channels = 1), - fmt(VK_FORMAT_R16G16_UNORM, R16G16_UNORM, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_SNORM, R16G16_SNORM, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_USCALED, R16G16_USCALED, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_SSCALED, R16G16_SSCALED, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_UINT, R16G16_UINT, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_SINT, R16G16_SINT, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16_SFLOAT, R16G16_FLOAT, .cpp = 4, .num_channels = 2), - fmt(VK_FORMAT_R16G16B16_UNORM, R16G16B16_UNORM, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_SNORM, R16G16B16_SNORM, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_USCALED, R16G16B16_USCALED, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_SSCALED, R16G16B16_SSCALED, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_UINT, R16G16B16_UINT, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_SINT, R16G16B16_SINT, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16_SFLOAT, R16G16B16_FLOAT, .cpp = 6, .num_channels = 3), - fmt(VK_FORMAT_R16G16B16A16_UNORM, R16G16B16A16_UNORM, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_SNORM, R16G16B16A16_SNORM, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_USCALED, R16G16B16A16_USCALED, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_SSCALED, R16G16B16A16_SSCALED, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_UINT, R16G16B16A16_UINT, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_SINT, R16G16B16A16_SINT, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R16G16B16A16_SFLOAT, R16G16B16A16_FLOAT, .cpp = 8, .num_channels = 4), - fmt(VK_FORMAT_R32_UINT, R32_UINT, .cpp = 4, .num_channels = 1,), - fmt(VK_FORMAT_R32_SINT, R32_SINT, .cpp = 4, .num_channels = 1,), - fmt(VK_FORMAT_R32_SFLOAT, R32_FLOAT, .cpp = 4, .num_channels = 1,), - fmt(VK_FORMAT_R32G32_UINT, R32G32_UINT, .cpp = 8, .num_channels = 2,), - fmt(VK_FORMAT_R32G32_SINT, R32G32_SINT, .cpp = 8, .num_channels = 2,), - fmt(VK_FORMAT_R32G32_SFLOAT, R32G32_FLOAT, .cpp = 8, .num_channels = 2,), - fmt(VK_FORMAT_R32G32B32_UINT, R32G32B32_UINT, .cpp = 12, .num_channels = 3,), - fmt(VK_FORMAT_R32G32B32_SINT, R32G32B32_SINT, .cpp = 12, .num_channels = 3,), - fmt(VK_FORMAT_R32G32B32_SFLOAT, R32G32B32_FLOAT, .cpp = 12, .num_channels = 3,), - fmt(VK_FORMAT_R32G32B32A32_UINT, R32G32B32A32_UINT, .cpp = 16, .num_channels = 4,), - fmt(VK_FORMAT_R32G32B32A32_SINT, R32G32B32A32_SINT, .cpp = 16, .num_channels = 4,), - fmt(VK_FORMAT_R32G32B32A32_SFLOAT, R32G32B32A32_FLOAT, .cpp = 16, .num_channels = 4,), - fmt(VK_FORMAT_R64_SFLOAT, R64_FLOAT, .cpp = 8, .num_channels = 1), - fmt(VK_FORMAT_R64G64_SFLOAT, R64G64_FLOAT, .cpp = 16, .num_channels = 2), - fmt(VK_FORMAT_R64G64B64_SFLOAT, R64G64B64_FLOAT, .cpp = 24, .num_channels = 3), - fmt(VK_FORMAT_R64G64B64A64_SFLOAT, R64G64B64A64_FLOAT, .cpp = 32, .num_channels = 4), - fmt(VK_FORMAT_R11G11B10_UFLOAT, R11G11B10_FLOAT, .cpp = 4, .num_channels = 3), - fmt(VK_FORMAT_R9G9B9E5_UFLOAT, R9G9B9E5_SHAREDEXP, .cpp = 4, .num_channels = 3), - - fmt(VK_FORMAT_D16_UNORM, R16_UNORM, .cpp = 2, .num_channels = 1, .depth_format = D16_UNORM), - fmt(VK_FORMAT_D24_UNORM, R24_UNORM_X8_TYPELESS, .cpp = 4, .num_channels = 1, .depth_format = D24_UNORM_X8_UINT), - fmt(VK_FORMAT_D32_SFLOAT, R32_FLOAT, .cpp = 4, .num_channels = 1, .depth_format = D32_FLOAT), - fmt(VK_FORMAT_S8_UINT, R8_UINT, .cpp = 1, .num_channels = 1, .has_stencil = true), - fmt(VK_FORMAT_D16_UNORM_S8_UINT, R16_UNORM, .cpp = 2, .num_channels = 2, .depth_format = D16_UNORM, .has_stencil = true), - fmt(VK_FORMAT_D24_UNORM_S8_UINT, R24_UNORM_X8_TYPELESS, .cpp = 4, .num_channels = 2, .depth_format = D24_UNORM_X8_UINT, .has_stencil = true), - fmt(VK_FORMAT_D32_SFLOAT_S8_UINT, R32_FLOAT, .cpp = 4, .num_channels = 2, .depth_format = D32_FLOAT, .has_stencil = true), - - fmt(VK_FORMAT_BC1_RGB_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC1_RGB_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_BC1_RGBA_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC1_RGBA_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_BC2_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC2_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_BC3_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC3_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_BC4_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC4_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC5_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC6H_UFLOAT, UNSUPPORTED), - fmt(VK_FORMAT_BC6H_SFLOAT, UNSUPPORTED), - fmt(VK_FORMAT_BC7_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_BC7_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8A1_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8A1_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8A8_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ETC2_R8G8B8A8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_EAC_R11_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_EAC_R11_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_EAC_R11G11_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_EAC_R11G11_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_4x4_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_4x4_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_5x4_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_5x4_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_5x5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_5x5_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_6x5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_6x5_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_6x6_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_6x6_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x5_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x6_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x6_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x8_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_8x8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x5_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x5_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x6_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x6_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x8_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x10_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_10x10_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_12x10_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_12x10_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_12x12_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_ASTC_12x12_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_B4G4R4A4_UNORM, B4G4R4A4_UNORM, .cpp = 2, .num_channels = 4), - fmt(VK_FORMAT_B5G5R5A1_UNORM, B5G5R5A1_UNORM, .cpp = 2, .num_channels = 4), - fmt(VK_FORMAT_B5G6R5_UNORM, B5G6R5_UNORM, .cpp = 2, .num_channels = 3), - fmt(VK_FORMAT_B5G6R5_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_UNORM, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_SSCALED, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_UINT, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_SINT, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8_SRGB, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_UNORM, B8G8R8A8_UNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B8G8R8A8_SNORM, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_USCALED, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_SSCALED, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_UINT, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_SINT, UNSUPPORTED), - fmt(VK_FORMAT_B8G8R8A8_SRGB, B8G8R8A8_UNORM_SRGB, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_UNORM, B10G10R10A2_UNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_SNORM, B10G10R10A2_SNORM, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_USCALED, B10G10R10A2_USCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_SSCALED, B10G10R10A2_SSCALED, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_UINT, B10G10R10A2_UINT, .cpp = 4, .num_channels = 4), - fmt(VK_FORMAT_B10G10R10A2_SINT, B10G10R10A2_SINT, .cpp = 4, .num_channels = 4) -}; - -#undef fmt - -const struct anv_format * -anv_format_for_vk_format(VkFormat format) -{ - return &anv_formats[format]; -} - -bool -anv_is_vk_format_depth_or_stencil(VkFormat format) -{ - const struct anv_format *format_info = - anv_format_for_vk_format(format); - - if (format_info->depth_format != UNSUPPORTED && - format_info->depth_format != 0) - return true; - - return format_info->has_stencil; -} - -// Format capabilities - -struct surface_format_info { - bool exists; - int sampling; - int filtering; - int shadow_compare; - int chroma_key; - int render_target; - int alpha_blend; - int input_vb; - int streamed_output_vb; - int color_processing; -}; - -extern const struct surface_format_info surface_formats[]; - -VkResult anv_validate_GetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat _format, - VkFormatProperties* pFormatProperties) -{ - const struct anv_format *format = anv_format_for_vk_format(_format); - fprintf(stderr, "vkGetFormatProperties(%s)\n", format->name); - return anv_GetPhysicalDeviceFormatProperties(physicalDevice, _format, pFormatProperties); -} - -VkResult anv_GetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat _format, - VkFormatProperties* pFormatProperties) -{ - ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); - const struct surface_format_info *info; - int gen; - - const struct anv_format *format = anv_format_for_vk_format(_format); - if (format == NULL) - return vk_error(VK_ERROR_INVALID_VALUE); - - gen = physical_device->info->gen * 10; - if (physical_device->info->is_haswell) - gen += 5; - - if (format->surface_format == UNSUPPORTED) - goto unsupported; - - info = &surface_formats[format->surface_format]; - if (!info->exists) - goto unsupported; - - uint32_t linear = 0, tiled = 0; - if (info->sampling <= gen) { - linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; - tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; - } - if (info->render_target <= gen) { - linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; - tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; - } - if (info->alpha_blend <= gen) { - linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; - tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; - } - if (info->input_vb <= gen) { - linear |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; - } - - pFormatProperties->linearTilingFeatures = linear; - pFormatProperties->optimalTilingFeatures = tiled; - - return VK_SUCCESS; - - unsupported: - pFormatProperties->linearTilingFeatures = 0; - pFormatProperties->optimalTilingFeatures = 0; - - return VK_SUCCESS; -} - -VkResult anv_GetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageFormatProperties* pImageFormatProperties) -{ - /* TODO: We should do something here. Chad? */ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_GetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - uint32_t samples, - VkImageUsageFlags usage, - VkImageTiling tiling, - uint32_t* pNumProperties, - VkSparseImageFormatProperties* pProperties) -{ - stub_return(VK_UNSUPPORTED); -} diff --git a/src/vulkan/gem.c b/src/vulkan/gem.c deleted file mode 100644 index db0d29f42c7..00000000000 --- a/src/vulkan/gem.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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. - */ - -#define _DEFAULT_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "private.h" - -#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) - -static int -anv_ioctl(int fd, unsigned long request, void *arg) -{ - int ret; - - do { - ret = ioctl(fd, request, arg); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - - return ret; -} - -/** - * Wrapper around DRM_IOCTL_I915_GEM_CREATE. - * - * Return gem handle, or 0 on failure. Gem handles are never 0. - */ -uint32_t -anv_gem_create(struct anv_device *device, size_t size) -{ - struct drm_i915_gem_create gem_create; - int ret; - - VG_CLEAR(gem_create); - gem_create.size = size; - - ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create); - if (ret != 0) { - /* FIXME: What do we do if this fails? */ - return 0; - } - - return gem_create.handle; -} - -void -anv_gem_close(struct anv_device *device, int gem_handle) -{ - struct drm_gem_close close; - - VG_CLEAR(close); - close.handle = gem_handle; - anv_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close); -} - -/** - * Wrapper around DRM_IOCTL_I915_GEM_MMAP. - */ -void* -anv_gem_mmap(struct anv_device *device, uint32_t gem_handle, - uint64_t offset, uint64_t size) -{ - struct drm_i915_gem_mmap gem_mmap; - int ret; - - gem_mmap.handle = gem_handle; - VG_CLEAR(gem_mmap.pad); - gem_mmap.offset = offset; - gem_mmap.size = size; - VG_CLEAR(gem_mmap.addr_ptr); - -#ifdef I915_MMAP_WC - gem_mmap.flags = 0; -#endif - - ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_mmap); - if (ret != 0) { - /* FIXME: Is NULL the right error return? Cf MAP_INVALID */ - return NULL; - } - - VG(VALGRIND_MALLOCLIKE_BLOCK(gem_mmap.addr_ptr, gem_mmap.size, 0, 1)); - return (void *)(uintptr_t) gem_mmap.addr_ptr; -} - -/* This is just a wrapper around munmap, but it also notifies valgrind that - * this map is no longer valid. Pair this with anv_gem_mmap(). - */ -void -anv_gem_munmap(void *p, uint64_t size) -{ - VG(VALGRIND_FREELIKE_BLOCK(p, 0)); - munmap(p, size); -} - -int -anv_gem_userptr(struct anv_device *device, void *mem, size_t size) -{ - struct drm_i915_gem_userptr userptr; - int ret; - - VG_CLEAR(userptr); - userptr.user_ptr = (__u64)((unsigned long) mem); - userptr.user_size = size; - userptr.flags = 0; - - ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr); - if (ret == -1) - return 0; - - return userptr.handle; -} - -/** - * On error, \a timeout_ns holds the remaining time. - */ -int -anv_gem_wait(struct anv_device *device, int gem_handle, int64_t *timeout_ns) -{ - struct drm_i915_gem_wait wait; - int ret; - - VG_CLEAR(wait); - wait.bo_handle = gem_handle; - wait.timeout_ns = *timeout_ns; - wait.flags = 0; - - ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_WAIT, &wait); - *timeout_ns = wait.timeout_ns; - - return ret; -} - -int -anv_gem_execbuffer(struct anv_device *device, - struct drm_i915_gem_execbuffer2 *execbuf) -{ - return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); -} - -int -anv_gem_set_tiling(struct anv_device *device, - int gem_handle, uint32_t stride, uint32_t tiling) -{ - struct drm_i915_gem_set_tiling set_tiling; - int ret; - - /* set_tiling overwrites the input on the error path, so we have to open - * code anv_ioctl. - */ - - do { - VG_CLEAR(set_tiling); - set_tiling.handle = gem_handle; - set_tiling.tiling_mode = I915_TILING_X; - set_tiling.stride = stride; - - ret = ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); - - return ret; -} - -int -anv_gem_get_param(int fd, uint32_t param) -{ - drm_i915_getparam_t gp; - int ret, tmp; - - VG_CLEAR(gp); - gp.param = param; - gp.value = &tmp; - ret = anv_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); - if (ret == 0) - return tmp; - - return 0; -} - -int -anv_gem_create_context(struct anv_device *device) -{ - struct drm_i915_gem_context_create create; - int ret; - - VG_CLEAR(create); - - ret = anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create); - if (ret == -1) - return -1; - - return create.ctx_id; -} - -int -anv_gem_destroy_context(struct anv_device *device, int context) -{ - struct drm_i915_gem_context_destroy destroy; - - VG_CLEAR(destroy); - destroy.ctx_id = context; - - return anv_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy); -} - -int -anv_gem_get_aperture(struct anv_physical_device *physical_dev, uint64_t *size) -{ - struct drm_i915_gem_get_aperture aperture; - int ret; - - VG_CLEAR(aperture); - ret = anv_ioctl(physical_dev->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); - if (ret == -1) - return -1; - - *size = aperture.aper_available_size; - - return 0; -} - -int -anv_gem_handle_to_fd(struct anv_device *device, int gem_handle) -{ - struct drm_prime_handle args; - int ret; - - VG_CLEAR(args); - args.handle = gem_handle; - args.flags = DRM_CLOEXEC; - - ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); - if (ret == -1) - return -1; - - return args.fd; -} - -int -anv_gem_fd_to_handle(struct anv_device *device, int fd) -{ - struct drm_prime_handle args; - int ret; - - VG_CLEAR(args); - args.fd = fd; - - ret = anv_ioctl(device->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); - if (ret == -1) - return 0; - - return args.handle; -} diff --git a/src/vulkan/image.c b/src/vulkan/image.c deleted file mode 100644 index 4b37de54dde..00000000000 --- a/src/vulkan/image.c +++ /dev/null @@ -1,745 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" - -struct anv_image_view_info { - uint8_t surface_type; /**< RENDER_SURFACE_STATE.SurfaceType */ - bool is_array:1; /**< RENDER_SURFACE_STATE.SurfaceArray */ - bool is_cube:1; /**< RENDER_SURFACE_STATE.CubeFaceEnable* */ -}; - -static const uint8_t anv_halign[] = { - [4] = HALIGN4, - [8] = HALIGN8, - [16] = HALIGN16, -}; - -static const uint8_t anv_valign[] = { - [4] = VALIGN4, - [8] = VALIGN8, - [16] = VALIGN16, -}; - -static const uint8_t anv_surf_type_from_image_type[] = { - [VK_IMAGE_TYPE_1D] = SURFTYPE_1D, - [VK_IMAGE_TYPE_2D] = SURFTYPE_2D, - [VK_IMAGE_TYPE_3D] = SURFTYPE_3D, - -}; - -static const struct anv_image_view_info -anv_image_view_info_table[] = { - #define INFO(s, ...) { .surface_type = s, __VA_ARGS__ } - [VK_IMAGE_VIEW_TYPE_1D] = INFO(SURFTYPE_1D), - [VK_IMAGE_VIEW_TYPE_2D] = INFO(SURFTYPE_2D), - [VK_IMAGE_VIEW_TYPE_3D] = INFO(SURFTYPE_3D), - [VK_IMAGE_VIEW_TYPE_CUBE] = INFO(SURFTYPE_CUBE, .is_cube = 1), - [VK_IMAGE_VIEW_TYPE_1D_ARRAY] = INFO(SURFTYPE_1D, .is_array = 1), - [VK_IMAGE_VIEW_TYPE_2D_ARRAY] = INFO(SURFTYPE_2D, .is_array = 1), - [VK_IMAGE_VIEW_TYPE_CUBE_ARRAY] = INFO(SURFTYPE_CUBE, .is_array = 1, .is_cube = 1), - #undef INFO -}; - -static const struct anv_surf_type_limits { - int32_t width; - int32_t height; - int32_t depth; -} anv_surf_type_limits[] = { - [SURFTYPE_1D] = {16384, 0, 2048}, - [SURFTYPE_2D] = {16384, 16384, 2048}, - [SURFTYPE_3D] = {2048, 2048, 2048}, - [SURFTYPE_CUBE] = {16384, 16384, 340}, - [SURFTYPE_BUFFER] = {128, 16384, 64}, - [SURFTYPE_STRBUF] = {128, 16384, 64}, -}; - -static const struct anv_tile_info { - uint32_t width; - uint32_t height; - - /** - * Alignment for RENDER_SURFACE_STATE.SurfaceBaseAddress. - * - * To simplify calculations, the alignments defined in the table are - * sometimes larger than required. For example, Skylake requires that X and - * Y tiled buffers be aligned to 4K, but Broadwell permits smaller - * alignment. We choose 4K to accomodate both chipsets. The alignment of - * a linear buffer depends on its element type and usage. Linear depth - * buffers have the largest alignment, 64B, so we choose that for all linear - * buffers. - */ - uint32_t surface_alignment; -} anv_tile_info_table[] = { - [LINEAR] = { 1, 1, 64 }, - [XMAJOR] = { 512, 8, 4096 }, - [YMAJOR] = { 128, 32, 4096 }, - [WMAJOR] = { 128, 32, 4096 }, -}; - -static uint32_t -anv_image_choose_tile_mode(const struct anv_image_create_info *anv_info) -{ - if (anv_info->force_tile_mode) - return anv_info->tile_mode; - - if (anv_info->vk_info->format == VK_FORMAT_S8_UINT) - return WMAJOR; - - switch (anv_info->vk_info->tiling) { - case VK_IMAGE_TILING_LINEAR: - return LINEAR; - case VK_IMAGE_TILING_OPTIMAL: - return YMAJOR; - default: - assert(!"bad VKImageTiling"); - return LINEAR; - } -} - -static VkResult -anv_image_make_surface(const struct anv_image_create_info *create_info, - uint64_t *inout_image_size, - uint32_t *inout_image_alignment, - struct anv_surface *out_surface) -{ - /* See RENDER_SURFACE_STATE.SurfaceQPitch */ - static const uint16_t min_qpitch UNUSED = 0x4; - static const uint16_t max_qpitch UNUSED = 0x1ffc; - - const VkExtent3D *restrict extent = &create_info->vk_info->extent; - const uint32_t levels = create_info->vk_info->mipLevels; - const uint32_t array_size = create_info->vk_info->arraySize; - - const uint8_t tile_mode = anv_image_choose_tile_mode(create_info); - - const struct anv_tile_info *tile_info = - &anv_tile_info_table[tile_mode]; - - const struct anv_format *format_info = - anv_format_for_vk_format(create_info->vk_info->format); - - const uint32_t i = 4; /* FINISHME: Stop hardcoding subimage alignment */ - const uint32_t j = 4; /* FINISHME: Stop hardcoding subimage alignment */ - const uint32_t w0 = align_u32(extent->width, i); - const uint32_t h0 = align_u32(extent->height, j); - - uint16_t qpitch; - uint32_t mt_width; - uint32_t mt_height; - - if (levels == 1 && array_size == 1) { - qpitch = min_qpitch; - mt_width = w0; - mt_height = h0; - } else { - uint32_t w1 = align_u32(anv_minify(extent->width, 1), i); - uint32_t h1 = align_u32(anv_minify(extent->height, 1), j); - uint32_t w2 = align_u32(anv_minify(extent->width, 2), i); - - qpitch = h0 + h1 + 11 * j; - mt_width = MAX(w0, w1 + w2); - mt_height = array_size * qpitch; - } - - assert(qpitch >= min_qpitch); - if (qpitch > max_qpitch) { - anv_loge("image qpitch > 0x%x\n", max_qpitch); - return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); - } - - /* From the Broadwell PRM, RENDER_SURFACE_STATE.SurfaceQpitch: - * - * This field must be set an integer multiple of the Surface Vertical - * Alignment. - */ - assert(anv_is_aligned(qpitch, j)); - - const uint32_t stride = align_u32(mt_width * format_info->cpp, - tile_info->width); - const uint32_t size = stride * align_u32(mt_height, tile_info->height); - const uint32_t offset = align_u32(*inout_image_size, - tile_info->surface_alignment); - - *inout_image_size = offset + size; - *inout_image_alignment = MAX(*inout_image_alignment, - tile_info->surface_alignment); - - *out_surface = (struct anv_surface) { - .offset = offset, - .stride = stride, - .tile_mode = tile_mode, - .qpitch = qpitch, - .h_align = i, - .v_align = j, - }; - - return VK_SUCCESS; -} - -VkResult -anv_image_create(VkDevice _device, - const struct anv_image_create_info *create_info, - VkImage *pImage) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - const VkImageCreateInfo *pCreateInfo = create_info->vk_info; - const VkExtent3D *restrict extent = &pCreateInfo->extent; - struct anv_image *image = NULL; - VkResult r; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); - - /* XXX: We don't handle any of these */ - anv_assert(pCreateInfo->imageType == VK_IMAGE_TYPE_2D); - anv_assert(pCreateInfo->mipLevels > 0); - anv_assert(pCreateInfo->arraySize > 0); - anv_assert(pCreateInfo->samples == 1); - anv_assert(pCreateInfo->extent.width > 0); - anv_assert(pCreateInfo->extent.height > 0); - anv_assert(pCreateInfo->extent.depth > 0); - - /* TODO(chadv): How should we validate inputs? */ - const uint8_t surf_type = - anv_surf_type_from_image_type[pCreateInfo->imageType]; - - const struct anv_surf_type_limits *limits = - &anv_surf_type_limits[surf_type]; - - if (extent->width > limits->width || - extent->height > limits->height || - extent->depth > limits->depth) { - /* TODO(chadv): What is the correct error? */ - anv_loge("image extent is too large"); - return vk_error(VK_ERROR_INVALID_MEMORY_SIZE); - } - - const struct anv_format *format_info = - anv_format_for_vk_format(pCreateInfo->format); - - image = anv_device_alloc(device, sizeof(*image), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (!image) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - memset(image, 0, sizeof(*image)); - image->type = pCreateInfo->imageType; - image->extent = pCreateInfo->extent; - image->format = pCreateInfo->format; - image->levels = pCreateInfo->mipLevels; - image->array_size = pCreateInfo->arraySize; - image->surf_type = surf_type; - - if (likely(!format_info->has_stencil || format_info->depth_format)) { - /* The image's primary surface is a color or depth surface. */ - r = anv_image_make_surface(create_info, &image->size, &image->alignment, - &image->primary_surface); - if (r != VK_SUCCESS) - goto fail; - } - - if (format_info->has_stencil) { - /* From the GPU's perspective, the depth buffer and stencil buffer are - * separate buffers. From Vulkan's perspective, though, depth and - * stencil reside in the same image. To satisfy Vulkan and the GPU, we - * place the depth and stencil buffers in the same bo. - */ - VkImageCreateInfo stencil_info = *pCreateInfo; - stencil_info.format = VK_FORMAT_S8_UINT; - - r = anv_image_make_surface( - &(struct anv_image_create_info) { - .vk_info = &stencil_info, - }, - &image->size, &image->alignment, &image->stencil_surface); - - if (r != VK_SUCCESS) - goto fail; - } - - *pImage = anv_image_to_handle(image); - - return VK_SUCCESS; - -fail: - if (image) - anv_device_free(device, image); - - return r; -} - -VkResult -anv_CreateImage(VkDevice device, - const VkImageCreateInfo *pCreateInfo, - VkImage *pImage) -{ - return anv_image_create(device, - &(struct anv_image_create_info) { - .vk_info = pCreateInfo, - }, - pImage); -} - -VkResult -anv_DestroyImage(VkDevice _device, VkImage _image) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - anv_device_free(device, anv_image_from_handle(_image)); - - return VK_SUCCESS; -} - -VkResult anv_GetImageSubresourceLayout( - VkDevice device, - VkImage image, - const VkImageSubresource* pSubresource, - VkSubresourceLayout* pLayout) -{ - stub_return(VK_UNSUPPORTED); -} - -void -anv_surface_view_fini(struct anv_device *device, - struct anv_surface_view *view) -{ - anv_state_pool_free(&device->surface_state_pool, view->surface_state); -} - -void -anv_image_view_init(struct anv_image_view *iview, - struct anv_device *device, - const VkImageViewCreateInfo* pCreateInfo, - struct anv_cmd_buffer *cmd_buffer) -{ - ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); - - const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange; - struct anv_surface_view *view = &iview->view; - struct anv_surface *surface; - - const struct anv_format *format_info = - anv_format_for_vk_format(pCreateInfo->format); - - const struct anv_image_view_info *view_type_info - = &anv_image_view_info_table[pCreateInfo->viewType]; - - if (pCreateInfo->viewType != VK_IMAGE_VIEW_TYPE_2D) - anv_finishme("non-2D image views"); - - switch (pCreateInfo->subresourceRange.aspect) { - case VK_IMAGE_ASPECT_STENCIL: - anv_finishme("stencil image views"); - abort(); - break; - case VK_IMAGE_ASPECT_DEPTH: - case VK_IMAGE_ASPECT_COLOR: - view->offset = image->offset; - surface = &image->primary_surface; - break; - default: - unreachable(""); - break; - } - - view->bo = image->bo; - view->offset = image->offset + surface->offset; - view->format = pCreateInfo->format; - - iview->extent = (VkExtent3D) { - .width = anv_minify(image->extent.width, range->baseMipLevel), - .height = anv_minify(image->extent.height, range->baseMipLevel), - .depth = anv_minify(image->extent.depth, range->baseMipLevel), - }; - - uint32_t depth = 1; - if (range->arraySize > 1) { - depth = range->arraySize; - } else if (image->extent.depth > 1) { - depth = image->extent.depth; - } - - static const uint32_t vk_to_gen_swizzle[] = { - [VK_CHANNEL_SWIZZLE_ZERO] = SCS_ZERO, - [VK_CHANNEL_SWIZZLE_ONE] = SCS_ONE, - [VK_CHANNEL_SWIZZLE_R] = SCS_RED, - [VK_CHANNEL_SWIZZLE_G] = SCS_GREEN, - [VK_CHANNEL_SWIZZLE_B] = SCS_BLUE, - [VK_CHANNEL_SWIZZLE_A] = SCS_ALPHA - }; - - struct GEN8_RENDER_SURFACE_STATE surface_state = { - .SurfaceType = view_type_info->surface_type, - .SurfaceArray = image->array_size > 1, - .SurfaceFormat = format_info->surface_format, - .SurfaceVerticalAlignment = anv_valign[surface->v_align], - .SurfaceHorizontalAlignment = anv_halign[surface->h_align], - .TileMode = surface->tile_mode, - .VerticalLineStride = 0, - .VerticalLineStrideOffset = 0, - .SamplerL2BypassModeDisable = true, - .RenderCacheReadWriteMode = WriteOnlyCache, - .MemoryObjectControlState = GEN8_MOCS, - - /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in - * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have - * both Base Mip Level fields nonzero". - */ - .BaseMipLevel = 0.0, - - .SurfaceQPitch = surface->qpitch >> 2, - .Height = image->extent.height - 1, - .Width = image->extent.width - 1, - .Depth = depth - 1, - .SurfacePitch = surface->stride - 1, - .MinimumArrayElement = range->baseArraySlice, - .NumberofMultisamples = MULTISAMPLECOUNT_1, - .XOffset = 0, - .YOffset = 0, - - /* For sampler surfaces, the hardware interprets field MIPCount/LOD as - * MIPCount. The range of levels accessible by the sampler engine is - * [SurfaceMinLOD, SurfaceMinLOD + MIPCountLOD]. - */ - .MIPCountLOD = range->mipLevels - 1, - .SurfaceMinLOD = range->baseMipLevel, - - .AuxiliarySurfaceMode = AUX_NONE, - .RedClearColor = 0, - .GreenClearColor = 0, - .BlueClearColor = 0, - .AlphaClearColor = 0, - .ShaderChannelSelectRed = vk_to_gen_swizzle[pCreateInfo->channels.r], - .ShaderChannelSelectGreen = vk_to_gen_swizzle[pCreateInfo->channels.g], - .ShaderChannelSelectBlue = vk_to_gen_swizzle[pCreateInfo->channels.b], - .ShaderChannelSelectAlpha = vk_to_gen_swizzle[pCreateInfo->channels.a], - .ResourceMinLOD = 0.0, - .SurfaceBaseAddress = { NULL, view->offset }, - }; - - if (cmd_buffer) { - view->surface_state = - anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64); - } else { - view->surface_state = - anv_state_pool_alloc(&device->surface_state_pool, 64, 64); - } - - GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state); -} - -VkResult -anv_validate_CreateImageView(VkDevice _device, - const VkImageViewCreateInfo *pCreateInfo, - VkImageView *pView) -{ - ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); - const VkImageSubresourceRange *subresource; - const struct anv_image_view_info *view_info; - const struct anv_format *view_format_info; - const struct anv_format *image_format_info; - - /* Validate structure type before dereferencing it. */ - assert(pCreateInfo); - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); - subresource = &pCreateInfo->subresourceRange; - - /* Validate viewType is in range before using it. */ - assert(pCreateInfo->viewType >= VK_IMAGE_VIEW_TYPE_BEGIN_RANGE); - assert(pCreateInfo->viewType <= VK_IMAGE_VIEW_TYPE_END_RANGE); - view_info = &anv_image_view_info_table[pCreateInfo->viewType]; - - /* Validate format is in range before using it. */ - assert(pCreateInfo->format >= VK_FORMAT_BEGIN_RANGE); - assert(pCreateInfo->format <= VK_FORMAT_END_RANGE); - image_format_info = anv_format_for_vk_format(image->format); - view_format_info = anv_format_for_vk_format(pCreateInfo->format); - - /* Validate channel swizzles. */ - assert(pCreateInfo->channels.r >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); - assert(pCreateInfo->channels.r <= VK_CHANNEL_SWIZZLE_END_RANGE); - assert(pCreateInfo->channels.g >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); - assert(pCreateInfo->channels.g <= VK_CHANNEL_SWIZZLE_END_RANGE); - assert(pCreateInfo->channels.b >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); - assert(pCreateInfo->channels.b <= VK_CHANNEL_SWIZZLE_END_RANGE); - assert(pCreateInfo->channels.a >= VK_CHANNEL_SWIZZLE_BEGIN_RANGE); - assert(pCreateInfo->channels.a <= VK_CHANNEL_SWIZZLE_END_RANGE); - - /* Validate subresource. */ - assert(subresource->aspect >= VK_IMAGE_ASPECT_BEGIN_RANGE); - assert(subresource->aspect <= VK_IMAGE_ASPECT_END_RANGE); - assert(subresource->mipLevels > 0); - assert(subresource->arraySize > 0); - assert(subresource->baseMipLevel < image->levels); - assert(subresource->baseMipLevel + subresource->mipLevels <= image->levels); - assert(subresource->baseArraySlice < image->array_size); - assert(subresource->baseArraySlice + subresource->arraySize <= image->array_size); - assert(pView); - - if (view_info->is_cube) { - assert(subresource->baseArraySlice % 6 == 0); - assert(subresource->arraySize % 6 == 0); - } - - /* Validate format. */ - switch (subresource->aspect) { - case VK_IMAGE_ASPECT_COLOR: - assert(!image_format_info->depth_format); - assert(!image_format_info->has_stencil); - assert(!view_format_info->depth_format); - assert(!view_format_info->has_stencil); - assert(view_format_info->cpp == image_format_info->cpp); - break; - case VK_IMAGE_ASPECT_DEPTH: - assert(image_format_info->depth_format); - assert(view_format_info->depth_format); - assert(view_format_info->cpp == image_format_info->cpp); - break; - case VK_IMAGE_ASPECT_STENCIL: - /* FINISHME: Is it legal to have an R8 view of S8? */ - assert(image_format_info->has_stencil); - assert(view_format_info->has_stencil); - break; - default: - assert(!"bad VkImageAspect"); - break; - } - - return anv_CreateImageView(_device, pCreateInfo, pView); -} - -VkResult -anv_CreateImageView(VkDevice _device, - const VkImageViewCreateInfo *pCreateInfo, - VkImageView *pView) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_image_view *view; - - 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); - - anv_image_view_init(view, device, pCreateInfo, NULL); - - *pView = anv_image_view_to_handle(view); - - return VK_SUCCESS; -} - -VkResult -anv_DestroyImageView(VkDevice _device, VkImageView _iview) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_image_view, iview, _iview); - - anv_surface_view_fini(device, &iview->view); - anv_device_free(device, iview); - - return VK_SUCCESS; -} - -void -anv_color_attachment_view_init(struct anv_color_attachment_view *aview, - struct anv_device *device, - const VkAttachmentViewCreateInfo* pCreateInfo, - struct anv_cmd_buffer *cmd_buffer) -{ - ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); - struct anv_surface_view *view = &aview->view; - struct anv_surface *surface = &image->primary_surface; - const struct anv_format *format_info = - anv_format_for_vk_format(pCreateInfo->format); - - aview->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_COLOR; - - anv_assert(pCreateInfo->arraySize > 0); - anv_assert(pCreateInfo->mipLevel < image->levels); - anv_assert(pCreateInfo->baseArraySlice + pCreateInfo->arraySize <= image->array_size); - - view->bo = image->bo; - view->offset = image->offset + surface->offset; - view->format = pCreateInfo->format; - - aview->base.extent = (VkExtent3D) { - .width = anv_minify(image->extent.width, pCreateInfo->mipLevel), - .height = anv_minify(image->extent.height, pCreateInfo->mipLevel), - .depth = anv_minify(image->extent.depth, pCreateInfo->mipLevel), - }; - - uint32_t depth = 1; - if (pCreateInfo->arraySize > 1) { - depth = pCreateInfo->arraySize; - } else if (image->extent.depth > 1) { - depth = image->extent.depth; - } - - if (cmd_buffer) { - view->surface_state = - anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64); - } else { - view->surface_state = - anv_state_pool_alloc(&device->surface_state_pool, 64, 64); - } - - struct GEN8_RENDER_SURFACE_STATE surface_state = { - .SurfaceType = SURFTYPE_2D, - .SurfaceArray = image->array_size > 1, - .SurfaceFormat = format_info->surface_format, - .SurfaceVerticalAlignment = anv_valign[surface->v_align], - .SurfaceHorizontalAlignment = anv_halign[surface->h_align], - .TileMode = surface->tile_mode, - .VerticalLineStride = 0, - .VerticalLineStrideOffset = 0, - .SamplerL2BypassModeDisable = true, - .RenderCacheReadWriteMode = WriteOnlyCache, - .MemoryObjectControlState = GEN8_MOCS, - - /* The driver sets BaseMipLevel in SAMPLER_STATE, not here in - * RENDER_SURFACE_STATE. The Broadwell PRM says "it is illegal to have - * both Base Mip Level fields nonzero". - */ - .BaseMipLevel = 0.0, - - .SurfaceQPitch = surface->qpitch >> 2, - .Height = image->extent.height - 1, - .Width = image->extent.width - 1, - .Depth = depth - 1, - .SurfacePitch = surface->stride - 1, - .MinimumArrayElement = pCreateInfo->baseArraySlice, - .NumberofMultisamples = MULTISAMPLECOUNT_1, - .XOffset = 0, - .YOffset = 0, - - /* For render target surfaces, the hardware interprets field MIPCount/LOD as - * LOD. The Broadwell PRM says: - * - * MIPCountLOD defines the LOD that will be rendered into. - * SurfaceMinLOD is ignored. - */ - .SurfaceMinLOD = 0, - .MIPCountLOD = pCreateInfo->mipLevel, - - .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.0, - .SurfaceBaseAddress = { NULL, view->offset }, - }; - - GEN8_RENDER_SURFACE_STATE_pack(NULL, view->surface_state.map, &surface_state); -} - -static void -anv_depth_stencil_view_init(struct anv_depth_stencil_view *view, - const VkAttachmentViewCreateInfo *pCreateInfo) -{ - ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image); - struct anv_surface *depth_surface = &image->primary_surface; - struct anv_surface *stencil_surface = &image->stencil_surface; - const struct anv_format *format = - anv_format_for_vk_format(image->format); - - view->base.attachment_type = ANV_ATTACHMENT_VIEW_TYPE_DEPTH_STENCIL; - - /* XXX: We don't handle any of these */ - anv_assert(pCreateInfo->mipLevel == 0); - anv_assert(pCreateInfo->baseArraySlice == 0); - anv_assert(pCreateInfo->arraySize == 1); - - view->bo = image->bo; - - view->depth_stride = depth_surface->stride; - view->depth_offset = image->offset + depth_surface->offset; - view->depth_format = format->depth_format; - view->depth_qpitch = 0; /* FINISHME: QPitch */ - - view->stencil_stride = stencil_surface->stride; - view->stencil_offset = image->offset + stencil_surface->offset; - view->stencil_qpitch = 0; /* FINISHME: QPitch */ -} - -VkResult -anv_CreateAttachmentView(VkDevice _device, - const VkAttachmentViewCreateInfo *pCreateInfo, - VkAttachmentView *pView) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO); - - if (anv_is_vk_format_depth_or_stencil(pCreateInfo->format)) { - struct anv_depth_stencil_view *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); - - anv_depth_stencil_view_init(view, pCreateInfo); - - *pView = anv_attachment_view_to_handle(&view->base); - } else { - struct anv_color_attachment_view *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); - - anv_color_attachment_view_init(view, device, pCreateInfo, NULL); - - *pView = anv_attachment_view_to_handle(&view->base); - } - - return VK_SUCCESS; -} - -VkResult -anv_DestroyAttachmentView(VkDevice _device, VkAttachmentView _view) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_attachment_view, view, _view); - - if (view->attachment_type == ANV_ATTACHMENT_VIEW_TYPE_COLOR) { - struct anv_color_attachment_view *aview = - (struct anv_color_attachment_view *)view; - - anv_surface_view_fini(device, &aview->view); - } - - anv_device_free(device, view); - - return VK_SUCCESS; -} diff --git a/src/vulkan/intel.c b/src/vulkan/intel.c deleted file mode 100644 index e314ba60586..00000000000 --- a/src/vulkan/intel.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" - -VkResult anv_CreateDmaBufImageINTEL( - VkDevice _device, - const VkDmaBufImageCreateInfo* pCreateInfo, - VkDeviceMemory* pMem, - VkImage* pImage) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_device_memory *mem; - struct anv_image *image; - VkResult result; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL); - - 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); - - mem->bo.gem_handle = anv_gem_fd_to_handle(device, pCreateInfo->fd); - if (!mem->bo.gem_handle) { - result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY); - goto fail; - } - - mem->bo.map = NULL; - mem->bo.index = 0; - mem->bo.offset = 0; - mem->bo.size = pCreateInfo->strideInBytes * pCreateInfo->extent.height; - - image = anv_device_alloc(device, sizeof(*image), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (image == NULL) { - result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - goto fail_mem; - } - - *image = (struct anv_image) { - .bo = &mem->bo, - .offset = 0, - .type = VK_IMAGE_TYPE_2D, - .extent = pCreateInfo->extent, - .size = mem->bo.size, - - .primary_surface = { - .offset = 0, - .stride = pCreateInfo->strideInBytes, - .tile_mode = XMAJOR, - }, - }; - - assert(image->extent.width > 0); - assert(image->extent.height > 0); - assert(image->extent.depth == 1); - - *pMem = anv_device_memory_to_handle(mem); - *pImage = anv_image_to_handle(image); - - return VK_SUCCESS; - - fail_mem: - anv_gem_close(device, mem->bo.gem_handle); - fail: - anv_device_free(device, mem); - - return result; -} diff --git a/src/vulkan/meta.c b/src/vulkan/meta.c deleted file mode 100644 index 30809581ad6..00000000000 --- a/src/vulkan/meta.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" -#include "meta-spirv.h" - -static void -anv_device_init_meta_clear_state(struct anv_device *device) -{ - /* We don't use a vertex shader for clearing, but instead build and pass - * the VUEs directly to the rasterization backend. - */ - VkShaderModule fsm = GLSL_VK_SHADER_MODULE(device, FRAGMENT, - out vec4 f_color; - flat in vec4 v_color; - void main() - { - f_color = v_color; - } - ); - - VkShader fs; - anv_CreateShader(anv_device_to_handle(device), - &(VkShaderCreateInfo) { - .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, - .module = fsm, - .pName = "main", - }, &fs); - - /* We use instanced rendering to clear multiple render targets. We have two - * vertex buffers: the first vertex buffer holds per-vertex data and - * provides the vertices for the clear rectangle. The second one holds - * per-instance data, which consists of the VUE header (which selects the - * layer) and the color (Vulkan supports per-RT clear colors). - */ - VkPipelineVertexInputStateCreateInfo vi_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .bindingCount = 2, - .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { - { - .binding = 0, - .strideInBytes = 8, - .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX - }, - { - .binding = 1, - .strideInBytes = 32, - .stepRate = VK_VERTEX_INPUT_STEP_RATE_INSTANCE - }, - }, - .attributeCount = 3, - .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { - { - /* VUE Header */ - .location = 0, - .binding = 1, - .format = VK_FORMAT_R32G32B32A32_UINT, - .offsetInBytes = 0 - }, - { - /* Position */ - .location = 1, - .binding = 0, - .format = VK_FORMAT_R32G32_SFLOAT, - .offsetInBytes = 0 - }, - { - /* Color */ - .location = 2, - .binding = 1, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offsetInBytes = 16 - } - } - }; - - anv_pipeline_create(anv_device_to_handle(device), - &(VkGraphicsPipelineCreateInfo) { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = 1, - .pStages = &(VkPipelineShaderStageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT, - .shader = fs, - .pSpecializationInfo = NULL, - }, - .pVertexInputState = &vi_create_info, - .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - .primitiveRestartEnable = false, - }, - .pRasterState = &(VkPipelineRasterStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, - .depthClipEnable = true, - .rasterizerDiscardEnable = false, - .fillMode = VK_FILL_MODE_SOLID, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_CCW - }, - .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = (VkPipelineColorBlendAttachmentState []) { - { .channelWriteMask = VK_CHANNEL_A_BIT | - VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT }, - } - }, - .flags = 0, - }, - &(struct anv_pipeline_create_info) { - .use_repclear = true, - .disable_viewport = true, - .use_rectlist = true - }, - &device->meta_state.clear.pipeline); - - anv_DestroyShader(anv_device_to_handle(device), fs); -} - -#define NUM_VB_USED 2 -struct anv_saved_state { - struct anv_vertex_binding old_vertex_bindings[NUM_VB_USED]; - struct anv_descriptor_set *old_descriptor_set0; - struct anv_pipeline *old_pipeline; - VkDynamicColorBlendState cb_state; -}; - -static void -anv_cmd_buffer_save(struct anv_cmd_buffer *cmd_buffer, - struct anv_saved_state *state) -{ - state->old_pipeline = cmd_buffer->state.pipeline; - state->old_descriptor_set0 = cmd_buffer->state.descriptors[0].set; - memcpy(state->old_vertex_bindings, cmd_buffer->state.vertex_bindings, - sizeof(state->old_vertex_bindings)); -} - -static void -anv_cmd_buffer_restore(struct anv_cmd_buffer *cmd_buffer, - const struct anv_saved_state *state) -{ - cmd_buffer->state.pipeline = state->old_pipeline; - cmd_buffer->state.descriptors[0].set = state->old_descriptor_set0; - memcpy(cmd_buffer->state.vertex_bindings, state->old_vertex_bindings, - sizeof(state->old_vertex_bindings)); - - cmd_buffer->state.vb_dirty |= (1 << NUM_VB_USED) - 1; - cmd_buffer->state.dirty |= ANV_CMD_BUFFER_PIPELINE_DIRTY; - cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_VERTEX_BIT; -} - -struct vue_header { - uint32_t Reserved; - uint32_t RTAIndex; - uint32_t ViewportIndex; - float PointWidth; -}; - -struct clear_instance_data { - struct vue_header vue_header; - VkClearColorValue color; -}; - -static void -meta_emit_clear(struct anv_cmd_buffer *cmd_buffer, - int num_instances, - struct clear_instance_data *instance_data) -{ - struct anv_device *device = cmd_buffer->device; - struct anv_framebuffer *fb = cmd_buffer->state.framebuffer; - struct anv_state state; - uint32_t size; - - const float vertex_data[] = { - /* Rect-list coordinates */ - 0.0, 0.0, - fb->width, 0.0, - fb->width, fb->height, - - /* Align to 16 bytes */ - 0.0, 0.0, - }; - - size = sizeof(vertex_data) + num_instances * sizeof(*instance_data); - state = anv_state_stream_alloc(&cmd_buffer->surface_state_stream, size, 16); - - /* Copy in the vertex and instance data */ - memcpy(state.map, vertex_data, sizeof(vertex_data)); - memcpy(state.map + sizeof(vertex_data), instance_data, - num_instances * sizeof(*instance_data)); - - struct anv_buffer vertex_buffer = { - .device = cmd_buffer->device, - .size = size, - .bo = &device->surface_state_block_pool.bo, - .offset = state.offset - }; - - anv_CmdBindVertexBuffers(anv_cmd_buffer_to_handle(cmd_buffer), 0, 2, - (VkBuffer[]) { - anv_buffer_to_handle(&vertex_buffer), - anv_buffer_to_handle(&vertex_buffer) - }, - (VkDeviceSize[]) { - 0, - sizeof(vertex_data) - }); - - if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(device->meta_state.clear.pipeline)) - anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer), - VK_PIPELINE_BIND_POINT_GRAPHICS, - device->meta_state.clear.pipeline); - - /* We don't need anything here, only set if not already set. */ - if (cmd_buffer->state.rs_state == NULL) - anv_CmdBindDynamicRasterState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.rs_state); - - if (cmd_buffer->state.vp_state == NULL) - anv_CmdBindDynamicViewportState(anv_cmd_buffer_to_handle(cmd_buffer), - cmd_buffer->state.framebuffer->vp_state); - - if (cmd_buffer->state.ds_state == NULL) - anv_CmdBindDynamicDepthStencilState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.ds_state); - - if (cmd_buffer->state.cb_state == NULL) - anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.cb_state); - - anv_CmdDraw(anv_cmd_buffer_to_handle(cmd_buffer), 0, 3, 0, num_instances); -} - -void -anv_cmd_buffer_clear_attachments(struct anv_cmd_buffer *cmd_buffer, - struct anv_render_pass *pass, - const VkClearValue *clear_values) -{ - struct anv_saved_state saved_state; - - int num_clear_layers = 0; - for (uint32_t i = 0; i < pass->attachment_count; i++) { - if (pass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { - if (anv_is_vk_format_depth_or_stencil(pass->attachments[i].format)) { - anv_finishme("Can't clear depth-stencil yet"); - continue; - } - num_clear_layers++; - } - } - - if (num_clear_layers == 0) - return; - - struct clear_instance_data instance_data[num_clear_layers]; - uint32_t color_attachments[num_clear_layers]; - - int layer = 0; - for (uint32_t i = 0; i < pass->attachment_count; i++) { - if (pass->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR && - !anv_is_vk_format_depth_or_stencil(pass->attachments[i].format)) { - instance_data[layer] = (struct clear_instance_data) { - .vue_header = { - .RTAIndex = i, - .ViewportIndex = 0, - .PointWidth = 0.0 - }, - .color = clear_values[i].color, - }; - color_attachments[layer] = i; - layer++; - } - } - - anv_cmd_buffer_save(cmd_buffer, &saved_state); - - struct anv_subpass subpass = { - .input_count = 0, - .color_count = num_clear_layers, - .color_attachments = color_attachments, - .depth_stencil_attachment = VK_ATTACHMENT_UNUSED, - }; - - anv_cmd_buffer_begin_subpass(cmd_buffer, &subpass); - - meta_emit_clear(cmd_buffer, num_clear_layers, instance_data); - - /* Restore API state */ - anv_cmd_buffer_restore(cmd_buffer, &saved_state); -} - -static void -anv_device_init_meta_blit_state(struct anv_device *device) -{ - /* We don't use a vertex shader for clearing, but instead build and pass - * the VUEs directly to the rasterization backend. However, we do need - * to provide GLSL source for the vertex shader so that the compiler - * does not dead-code our inputs. - */ - VkShaderModule vsm = GLSL_VK_SHADER_MODULE(device, VERTEX, - in vec2 a_pos; - in vec2 a_tex_coord; - out vec4 v_tex_coord; - void main() - { - v_tex_coord = vec4(a_tex_coord, 0, 1); - gl_Position = vec4(a_pos, 0, 1); - } - ); - - VkShaderModule fsm = GLSL_VK_SHADER_MODULE(device, FRAGMENT, - out vec4 f_color; - in vec4 v_tex_coord; - layout(set = 0, binding = 0) uniform sampler2D u_tex; - void main() - { - f_color = texture(u_tex, v_tex_coord.xy); - } - ); - - VkShader vs; - anv_CreateShader(anv_device_to_handle(device), - &(VkShaderCreateInfo) { - .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, - .module = vsm, - .pName = "main", - }, &vs); - - VkShader fs; - anv_CreateShader(anv_device_to_handle(device), - &(VkShaderCreateInfo) { - .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, - .module = fsm, - .pName = "main", - }, &fs); - - VkPipelineVertexInputStateCreateInfo vi_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .bindingCount = 2, - .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { - { - .binding = 0, - .strideInBytes = 0, - .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX - }, - { - .binding = 1, - .strideInBytes = 16, - .stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX - }, - }, - .attributeCount = 3, - .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { - { - /* VUE Header */ - .location = 0, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_UINT, - .offsetInBytes = 0 - }, - { - /* Position */ - .location = 1, - .binding = 1, - .format = VK_FORMAT_R32G32_SFLOAT, - .offsetInBytes = 0 - }, - { - /* Texture Coordinate */ - .location = 2, - .binding = 1, - .format = VK_FORMAT_R32G32_SFLOAT, - .offsetInBytes = 8 - } - } - }; - - VkDescriptorSetLayoutCreateInfo ds_layout_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .count = 1, - .pBinding = (VkDescriptorSetLayoutBinding[]) { - { - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .arraySize = 1, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = NULL - }, - } - }; - anv_CreateDescriptorSetLayout(anv_device_to_handle(device), &ds_layout_info, - &device->meta_state.blit.ds_layout); - - anv_CreatePipelineLayout(anv_device_to_handle(device), - &(VkPipelineLayoutCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .descriptorSetCount = 1, - .pSetLayouts = &device->meta_state.blit.ds_layout, - }, - &device->meta_state.blit.pipeline_layout); - - anv_pipeline_create(anv_device_to_handle(device), - &(VkGraphicsPipelineCreateInfo) { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = 2, - .pStages = (VkPipelineShaderStageCreateInfo[]) { - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_VERTEX, - .shader = vs, - .pSpecializationInfo = NULL - }, { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT, - .shader = fs, - .pSpecializationInfo = NULL - }, - }, - .pVertexInputState = &vi_create_info, - .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - .primitiveRestartEnable = false, - }, - .pRasterState = &(VkPipelineRasterStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, - .depthClipEnable = true, - .rasterizerDiscardEnable = false, - .fillMode = VK_FILL_MODE_SOLID, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_CCW - }, - .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = (VkPipelineColorBlendAttachmentState []) { - { .channelWriteMask = VK_CHANNEL_A_BIT | - VK_CHANNEL_R_BIT | VK_CHANNEL_G_BIT | VK_CHANNEL_B_BIT }, - } - }, - .flags = 0, - .layout = device->meta_state.blit.pipeline_layout, - }, - &(struct anv_pipeline_create_info) { - .use_repclear = false, - .disable_viewport = true, - .disable_scissor = true, - .disable_vs = true, - .use_rectlist = true - }, - &device->meta_state.blit.pipeline); - - anv_DestroyShader(anv_device_to_handle(device), vs); - anv_DestroyShader(anv_device_to_handle(device), fs); -} - -static void -meta_prepare_blit(struct anv_cmd_buffer *cmd_buffer, - struct anv_saved_state *saved_state) -{ - struct anv_device *device = cmd_buffer->device; - - anv_cmd_buffer_save(cmd_buffer, saved_state); - - if (cmd_buffer->state.pipeline != anv_pipeline_from_handle(device->meta_state.blit.pipeline)) - anv_CmdBindPipeline(anv_cmd_buffer_to_handle(cmd_buffer), - VK_PIPELINE_BIND_POINT_GRAPHICS, - device->meta_state.blit.pipeline); - - /* We don't need anything here, only set if not already set. */ - if (cmd_buffer->state.rs_state == NULL) - anv_CmdBindDynamicRasterState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.rs_state); - if (cmd_buffer->state.ds_state == NULL) - anv_CmdBindDynamicDepthStencilState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.ds_state); - - saved_state->cb_state = anv_dynamic_cb_state_to_handle(cmd_buffer->state.cb_state); - anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), - device->meta_state.shared.cb_state); -} - -struct blit_region { - VkOffset3D src_offset; - VkExtent3D src_extent; - VkOffset3D dest_offset; - VkExtent3D dest_extent; -}; - -static void -meta_emit_blit(struct anv_cmd_buffer *cmd_buffer, - struct anv_image_view *src, - VkOffset3D src_offset, - VkExtent3D src_extent, - struct anv_color_attachment_view *dest, - VkOffset3D dest_offset, - VkExtent3D dest_extent) -{ - struct anv_device *device = cmd_buffer->device; - VkDescriptorPool dummy_desc_pool = { .handle = 1 }; - - struct blit_vb_data { - float pos[2]; - float tex_coord[2]; - } *vb_data; - - unsigned vb_size = sizeof(struct vue_header) + 3 * sizeof(*vb_data); - - struct anv_state vb_state = - anv_state_stream_alloc(&cmd_buffer->surface_state_stream, vb_size, 16); - memset(vb_state.map, 0, sizeof(struct vue_header)); - vb_data = vb_state.map + sizeof(struct vue_header); - - vb_data[0] = (struct blit_vb_data) { - .pos = { - dest_offset.x + dest_extent.width, - dest_offset.y + dest_extent.height, - }, - .tex_coord = { - (float)(src_offset.x + src_extent.width) / (float)src->extent.width, - (float)(src_offset.y + src_extent.height) / (float)src->extent.height, - }, - }; - - vb_data[1] = (struct blit_vb_data) { - .pos = { - dest_offset.x, - dest_offset.y + dest_extent.height, - }, - .tex_coord = { - (float)src_offset.x / (float)src->extent.width, - (float)(src_offset.y + src_extent.height) / (float)src->extent.height, - }, - }; - - vb_data[2] = (struct blit_vb_data) { - .pos = { - dest_offset.x, - dest_offset.y, - }, - .tex_coord = { - (float)src_offset.x / (float)src->extent.width, - (float)src_offset.y / (float)src->extent.height, - }, - }; - - struct anv_buffer vertex_buffer = { - .device = device, - .size = vb_size, - .bo = &device->surface_state_block_pool.bo, - .offset = vb_state.offset, - }; - - anv_CmdBindVertexBuffers(anv_cmd_buffer_to_handle(cmd_buffer), 0, 2, - (VkBuffer[]) { - anv_buffer_to_handle(&vertex_buffer), - anv_buffer_to_handle(&vertex_buffer) - }, - (VkDeviceSize[]) { - 0, - sizeof(struct vue_header), - }); - - uint32_t count; - VkDescriptorSet set; - anv_AllocDescriptorSets(anv_device_to_handle(device), dummy_desc_pool, - VK_DESCRIPTOR_SET_USAGE_ONE_SHOT, - 1, &device->meta_state.blit.ds_layout, &set, &count); - anv_UpdateDescriptorSets(anv_device_to_handle(device), - 1, /* writeCount */ - (VkWriteDescriptorSet[]) { - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .destSet = set, - .destBinding = 0, - .destArrayElement = 0, - .count = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .pDescriptors = (VkDescriptorInfo[]) { - { - .imageView = anv_image_view_to_handle(src), - .imageLayout = VK_IMAGE_LAYOUT_GENERAL - }, - } - } - }, 0, NULL); - - VkFramebuffer fb; - anv_CreateFramebuffer(anv_device_to_handle(device), - &(VkFramebufferCreateInfo) { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = (VkAttachmentBindInfo[]) { - { - .view = anv_attachment_view_to_handle(&dest->base), - .layout = VK_IMAGE_LAYOUT_GENERAL - } - }, - .width = dest->base.extent.width, - .height = dest->base.extent.height, - .layers = 1 - }, &fb); - - VkRenderPass pass; - anv_CreateRenderPass(anv_device_to_handle(device), - &(VkRenderPassCreateInfo) { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &(VkAttachmentDescription) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, - .format = dest->view.format, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_GENERAL, - .finalLayout = VK_IMAGE_LAYOUT_GENERAL, - }, - .subpassCount = 1, - .pSubpasses = &(VkSubpassDescription) { - .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .inputCount = 0, - .colorCount = 1, - .colorAttachments = &(VkAttachmentReference) { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - .resolveAttachments = NULL, - .depthStencilAttachment = (VkAttachmentReference) { - .attachment = VK_ATTACHMENT_UNUSED, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - .preserveCount = 1, - .preserveAttachments = &(VkAttachmentReference) { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - }, - .dependencyCount = 0, - }, &pass); - - anv_CmdBeginRenderPass(anv_cmd_buffer_to_handle(cmd_buffer), - &(VkRenderPassBeginInfo) { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = pass, - .framebuffer = fb, - .renderArea = { - .offset = { dest_offset.x, dest_offset.y }, - .extent = { dest_extent.width, dest_extent.height }, - }, - .attachmentCount = 1, - .pAttachmentClearValues = NULL, - }, VK_RENDER_PASS_CONTENTS_INLINE); - - anv_CmdBindDynamicViewportState(anv_cmd_buffer_to_handle(cmd_buffer), - anv_framebuffer_from_handle(fb)->vp_state); - - anv_CmdBindDescriptorSets(anv_cmd_buffer_to_handle(cmd_buffer), - VK_PIPELINE_BIND_POINT_GRAPHICS, - device->meta_state.blit.pipeline_layout, 0, 1, - &set, 0, NULL); - - anv_CmdDraw(anv_cmd_buffer_to_handle(cmd_buffer), 0, 3, 0, 1); - - anv_CmdEndRenderPass(anv_cmd_buffer_to_handle(cmd_buffer)); - - /* At the point where we emit the draw call, all data from the - * descriptor sets, etc. has been used. We are free to delete it. - */ - anv_descriptor_set_destroy(device, anv_descriptor_set_from_handle(set)); - anv_DestroyFramebuffer(anv_device_to_handle(device), fb); - anv_DestroyRenderPass(anv_device_to_handle(device), pass); -} - -static void -meta_finish_blit(struct anv_cmd_buffer *cmd_buffer, - const struct anv_saved_state *saved_state) -{ - anv_cmd_buffer_restore(cmd_buffer, saved_state); - anv_CmdBindDynamicColorBlendState(anv_cmd_buffer_to_handle(cmd_buffer), - saved_state->cb_state); -} - -static VkFormat -vk_format_for_cpp(int cpp) -{ - switch (cpp) { - case 1: return VK_FORMAT_R8_UINT; - case 2: return VK_FORMAT_R8G8_UINT; - case 3: return VK_FORMAT_R8G8B8_UINT; - case 4: return VK_FORMAT_R8G8B8A8_UINT; - case 6: return VK_FORMAT_R16G16B16_UINT; - case 8: return VK_FORMAT_R16G16B16A16_UINT; - case 12: return VK_FORMAT_R32G32B32_UINT; - case 16: return VK_FORMAT_R32G32B32A32_UINT; - default: - unreachable("Invalid format cpp"); - } -} - -static void -do_buffer_copy(struct anv_cmd_buffer *cmd_buffer, - struct anv_bo *src, uint64_t src_offset, - struct anv_bo *dest, uint64_t dest_offset, - int width, int height, VkFormat copy_format) -{ - VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); - - VkImageCreateInfo image_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = copy_format, - .extent = { - .width = width, - .height = height, - .depth = 1, - }, - .mipLevels = 1, - .arraySize = 1, - .samples = 1, - .tiling = VK_IMAGE_TILING_LINEAR, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT, - .flags = 0, - }; - - VkImage src_image, dest_image; - anv_CreateImage(vk_device, &image_info, &src_image); - anv_CreateImage(vk_device, &image_info, &dest_image); - - /* We could use a vk call to bind memory, but that would require - * creating a dummy memory object etc. so there's really no point. - */ - anv_image_from_handle(src_image)->bo = src; - anv_image_from_handle(src_image)->offset = src_offset; - anv_image_from_handle(dest_image)->bo = dest; - anv_image_from_handle(dest_image)->offset = dest_offset; - - struct anv_image_view src_view; - anv_image_view_init(&src_view, cmd_buffer->device, - &(VkImageViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = src_image, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = copy_format, - .channels = { - VK_CHANNEL_SWIZZLE_R, - VK_CHANNEL_SWIZZLE_G, - VK_CHANNEL_SWIZZLE_B, - VK_CHANNEL_SWIZZLE_A - }, - .subresourceRange = { - .aspect = VK_IMAGE_ASPECT_COLOR, - .baseMipLevel = 0, - .mipLevels = 1, - .baseArraySlice = 0, - .arraySize = 1 - }, - }, - cmd_buffer); - - struct anv_color_attachment_view dest_view; - anv_color_attachment_view_init(&dest_view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = dest_image, - .format = copy_format, - .mipLevel = 0, - .baseArraySlice = 0, - .arraySize = 1, - }, - cmd_buffer); - - meta_emit_blit(cmd_buffer, - &src_view, - (VkOffset3D) { 0, 0, 0 }, - (VkExtent3D) { width, height, 1 }, - &dest_view, - (VkOffset3D) { 0, 0, 0 }, - (VkExtent3D) { width, height, 1 }); - - anv_DestroyImage(vk_device, src_image); - anv_DestroyImage(vk_device, dest_image); -} - -void anv_CmdCopyBuffer( - VkCmdBuffer cmdBuffer, - VkBuffer srcBuffer, - VkBuffer destBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_buffer, src_buffer, srcBuffer); - ANV_FROM_HANDLE(anv_buffer, dest_buffer, destBuffer); - - struct anv_saved_state saved_state; - - meta_prepare_blit(cmd_buffer, &saved_state); - - for (unsigned r = 0; r < regionCount; r++) { - uint64_t src_offset = src_buffer->offset + pRegions[r].srcOffset; - uint64_t dest_offset = dest_buffer->offset + pRegions[r].destOffset; - uint64_t copy_size = pRegions[r].copySize; - - /* First, we compute the biggest format that can be used with the - * given offsets and size. - */ - int cpp = 16; - - int fs = ffs(src_offset) - 1; - if (fs != -1) - cpp = MIN2(cpp, 1 << fs); - assert(src_offset % cpp == 0); - - fs = ffs(dest_offset) - 1; - if (fs != -1) - cpp = MIN2(cpp, 1 << fs); - assert(dest_offset % cpp == 0); - - fs = ffs(pRegions[r].copySize) - 1; - if (fs != -1) - cpp = MIN2(cpp, 1 << fs); - assert(pRegions[r].copySize % cpp == 0); - - VkFormat copy_format = vk_format_for_cpp(cpp); - - /* This is maximum possible width/height our HW can handle */ - uint64_t max_surface_dim = 1 << 14; - - /* First, we make a bunch of max-sized copies */ - uint64_t max_copy_size = max_surface_dim * max_surface_dim * cpp; - while (copy_size > max_copy_size) { - do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, - dest_buffer->bo, dest_offset, - max_surface_dim, max_surface_dim, copy_format); - copy_size -= max_copy_size; - src_offset += max_copy_size; - dest_offset += max_copy_size; - } - - uint64_t height = copy_size / (max_surface_dim * cpp); - assert(height < max_surface_dim); - if (height != 0) { - uint64_t rect_copy_size = height * max_surface_dim * cpp; - do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, - dest_buffer->bo, dest_offset, - max_surface_dim, height, copy_format); - copy_size -= rect_copy_size; - src_offset += rect_copy_size; - dest_offset += rect_copy_size; - } - - if (copy_size != 0) { - do_buffer_copy(cmd_buffer, src_buffer->bo, src_offset, - dest_buffer->bo, dest_offset, - copy_size / cpp, 1, copy_format); - } - } - - meta_finish_blit(cmd_buffer, &saved_state); -} - -void anv_CmdCopyImage( - VkCmdBuffer cmdBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage destImage, - VkImageLayout destImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_image, src_image, srcImage); - - struct anv_saved_state saved_state; - - meta_prepare_blit(cmd_buffer, &saved_state); - - for (unsigned r = 0; r < regionCount; r++) { - struct anv_image_view src_view; - anv_image_view_init(&src_view, cmd_buffer->device, - &(VkImageViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = srcImage, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = src_image->format, - .channels = { - VK_CHANNEL_SWIZZLE_R, - VK_CHANNEL_SWIZZLE_G, - VK_CHANNEL_SWIZZLE_B, - VK_CHANNEL_SWIZZLE_A - }, - .subresourceRange = { - .aspect = pRegions[r].srcSubresource.aspect, - .baseMipLevel = pRegions[r].srcSubresource.mipLevel, - .mipLevels = 1, - .baseArraySlice = pRegions[r].srcSubresource.arraySlice, - .arraySize = 1 - }, - }, - cmd_buffer); - - struct anv_color_attachment_view dest_view; - anv_color_attachment_view_init(&dest_view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = destImage, - .format = src_image->format, - .mipLevel = pRegions[r].destSubresource.mipLevel, - .baseArraySlice = pRegions[r].destSubresource.arraySlice, - .arraySize = 1, - }, - cmd_buffer); - - meta_emit_blit(cmd_buffer, - &src_view, - pRegions[r].srcOffset, - pRegions[r].extent, - &dest_view, - pRegions[r].destOffset, - pRegions[r].extent); - } - - meta_finish_blit(cmd_buffer, &saved_state); -} - -void anv_CmdBlitImage( - VkCmdBuffer cmdBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage destImage, - VkImageLayout destImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkTexFilter filter) - -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_image, src_image, srcImage); - ANV_FROM_HANDLE(anv_image, dest_image, destImage); - - struct anv_saved_state saved_state; - - anv_finishme("respect VkTexFilter"); - - meta_prepare_blit(cmd_buffer, &saved_state); - - for (unsigned r = 0; r < regionCount; r++) { - struct anv_image_view src_view; - anv_image_view_init(&src_view, cmd_buffer->device, - &(VkImageViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = srcImage, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = src_image->format, - .channels = { - VK_CHANNEL_SWIZZLE_R, - VK_CHANNEL_SWIZZLE_G, - VK_CHANNEL_SWIZZLE_B, - VK_CHANNEL_SWIZZLE_A - }, - .subresourceRange = { - .aspect = pRegions[r].srcSubresource.aspect, - .baseMipLevel = pRegions[r].srcSubresource.mipLevel, - .mipLevels = 1, - .baseArraySlice = pRegions[r].srcSubresource.arraySlice, - .arraySize = 1 - }, - }, - cmd_buffer); - - struct anv_color_attachment_view dest_view; - anv_color_attachment_view_init(&dest_view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = destImage, - .format = dest_image->format, - .mipLevel = pRegions[r].destSubresource.mipLevel, - .baseArraySlice = pRegions[r].destSubresource.arraySlice, - .arraySize = 1, - }, - cmd_buffer); - - meta_emit_blit(cmd_buffer, - &src_view, - pRegions[r].srcOffset, - pRegions[r].srcExtent, - &dest_view, - pRegions[r].destOffset, - pRegions[r].destExtent); - } - - meta_finish_blit(cmd_buffer, &saved_state); -} - -void anv_CmdCopyBufferToImage( - VkCmdBuffer cmdBuffer, - VkBuffer srcBuffer, - VkImage destImage, - VkImageLayout destImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_buffer, src_buffer, srcBuffer); - ANV_FROM_HANDLE(anv_image, dest_image, destImage); - VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); - struct anv_saved_state saved_state; - - meta_prepare_blit(cmd_buffer, &saved_state); - - for (unsigned r = 0; r < regionCount; r++) { - if (pRegions[r].bufferRowLength != 0) - anv_finishme("bufferRowLength not supported in CopyBufferToImage"); - if (pRegions[r].bufferImageHeight != 0) - anv_finishme("bufferImageHeight not supported in CopyBufferToImage"); - - VkImage srcImage; - anv_CreateImage(vk_device, - &(VkImageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = dest_image->format, - .extent = { - .width = pRegions[r].imageExtent.width, - .height = pRegions[r].imageExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arraySize = 1, - .samples = 1, - .tiling = VK_IMAGE_TILING_LINEAR, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT, - .flags = 0, - }, &srcImage); - - ANV_FROM_HANDLE(anv_image, src_image, srcImage); - - /* We could use a vk call to bind memory, but that would require - * creating a dummy memory object etc. so there's really no point. - */ - src_image->bo = src_buffer->bo; - src_image->offset = src_buffer->offset + pRegions[r].bufferOffset; - - struct anv_image_view src_view; - anv_image_view_init(&src_view, cmd_buffer->device, - &(VkImageViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = anv_image_to_handle(src_image), - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = dest_image->format, - .channels = { - VK_CHANNEL_SWIZZLE_R, - VK_CHANNEL_SWIZZLE_G, - VK_CHANNEL_SWIZZLE_B, - VK_CHANNEL_SWIZZLE_A - }, - .subresourceRange = { - .aspect = pRegions[r].imageSubresource.aspect, - .baseMipLevel = 0, - .mipLevels = 1, - .baseArraySlice = 0, - .arraySize = 1 - }, - }, - cmd_buffer); - - struct anv_color_attachment_view dest_view; - anv_color_attachment_view_init(&dest_view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = anv_image_to_handle(dest_image), - .format = dest_image->format, - .mipLevel = pRegions[r].imageSubresource.mipLevel, - .baseArraySlice = pRegions[r].imageSubresource.arraySlice, - .arraySize = 1, - }, - cmd_buffer); - - meta_emit_blit(cmd_buffer, - &src_view, - (VkOffset3D) { 0, 0, 0 }, - pRegions[r].imageExtent, - &dest_view, - pRegions[r].imageOffset, - pRegions[r].imageExtent); - - anv_DestroyImage(vk_device, srcImage); - } - - meta_finish_blit(cmd_buffer, &saved_state); -} - -void anv_CmdCopyImageToBuffer( - VkCmdBuffer cmdBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer destBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_image, src_image, srcImage); - ANV_FROM_HANDLE(anv_buffer, dest_buffer, destBuffer); - VkDevice vk_device = anv_device_to_handle(cmd_buffer->device); - struct anv_saved_state saved_state; - - meta_prepare_blit(cmd_buffer, &saved_state); - - for (unsigned r = 0; r < regionCount; r++) { - if (pRegions[r].bufferRowLength != 0) - anv_finishme("bufferRowLength not supported in CopyBufferToImage"); - if (pRegions[r].bufferImageHeight != 0) - anv_finishme("bufferImageHeight not supported in CopyBufferToImage"); - - struct anv_image_view src_view; - anv_image_view_init(&src_view, cmd_buffer->device, - &(VkImageViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = srcImage, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = src_image->format, - .channels = { - VK_CHANNEL_SWIZZLE_R, - VK_CHANNEL_SWIZZLE_G, - VK_CHANNEL_SWIZZLE_B, - VK_CHANNEL_SWIZZLE_A - }, - .subresourceRange = { - .aspect = pRegions[r].imageSubresource.aspect, - .baseMipLevel = pRegions[r].imageSubresource.mipLevel, - .mipLevels = 1, - .baseArraySlice = pRegions[r].imageSubresource.arraySlice, - .arraySize = 1 - }, - }, - cmd_buffer); - - VkImage destImage; - anv_CreateImage(vk_device, - &(VkImageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = src_image->format, - .extent = { - .width = pRegions[r].imageExtent.width, - .height = pRegions[r].imageExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arraySize = 1, - .samples = 1, - .tiling = VK_IMAGE_TILING_LINEAR, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT, - .flags = 0, - }, &destImage); - - ANV_FROM_HANDLE(anv_image, dest_image, destImage); - - /* We could use a vk call to bind memory, but that would require - * creating a dummy memory object etc. so there's really no point. - */ - dest_image->bo = dest_buffer->bo; - dest_image->offset = dest_buffer->offset + pRegions[r].bufferOffset; - - struct anv_color_attachment_view dest_view; - anv_color_attachment_view_init(&dest_view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = destImage, - .format = src_image->format, - .mipLevel = 0, - .baseArraySlice = 0, - .arraySize = 1, - }, - cmd_buffer); - - meta_emit_blit(cmd_buffer, - &src_view, - pRegions[r].imageOffset, - pRegions[r].imageExtent, - &dest_view, - (VkOffset3D) { 0, 0, 0 }, - pRegions[r].imageExtent); - - anv_DestroyImage(vk_device, destImage); - } - - meta_finish_blit(cmd_buffer, &saved_state); -} - -void anv_CmdUpdateBuffer( - VkCmdBuffer cmdBuffer, - VkBuffer destBuffer, - VkDeviceSize destOffset, - VkDeviceSize dataSize, - const uint32_t* pData) -{ - stub(); -} - -void anv_CmdFillBuffer( - VkCmdBuffer cmdBuffer, - VkBuffer destBuffer, - VkDeviceSize destOffset, - VkDeviceSize fillSize, - uint32_t data) -{ - stub(); -} - -void anv_CmdClearColorImage( - VkCmdBuffer cmdBuffer, - VkImage _image, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_image, image, _image); - struct anv_saved_state saved_state; - - anv_cmd_buffer_save(cmd_buffer, &saved_state); - - for (uint32_t r = 0; r < rangeCount; r++) { - for (uint32_t l = 0; l < pRanges[r].mipLevels; l++) { - for (uint32_t s = 0; s < pRanges[r].arraySize; s++) { - struct anv_color_attachment_view view; - anv_color_attachment_view_init(&view, cmd_buffer->device, - &(VkAttachmentViewCreateInfo) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO, - .image = _image, - .format = image->format, - .mipLevel = pRanges[r].baseMipLevel + l, - .baseArraySlice = pRanges[r].baseArraySlice + s, - .arraySize = 1, - }, - cmd_buffer); - - VkFramebuffer fb; - anv_CreateFramebuffer(anv_device_to_handle(cmd_buffer->device), - &(VkFramebufferCreateInfo) { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = (VkAttachmentBindInfo[]) { - { - .view = anv_attachment_view_to_handle(&view.base), - .layout = VK_IMAGE_LAYOUT_GENERAL - } - }, - .width = view.base.extent.width, - .height = view.base.extent.height, - .layers = 1 - }, &fb); - - VkRenderPass pass; - anv_CreateRenderPass(anv_device_to_handle(cmd_buffer->device), - &(VkRenderPassCreateInfo) { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &(VkAttachmentDescription) { - .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, - .format = view.view.format, - .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_GENERAL, - .finalLayout = VK_IMAGE_LAYOUT_GENERAL, - }, - .subpassCount = 1, - .pSubpasses = &(VkSubpassDescription) { - .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .inputCount = 0, - .colorCount = 1, - .colorAttachments = &(VkAttachmentReference) { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - .resolveAttachments = NULL, - .depthStencilAttachment = (VkAttachmentReference) { - .attachment = VK_ATTACHMENT_UNUSED, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - .preserveCount = 1, - .preserveAttachments = &(VkAttachmentReference) { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_GENERAL, - }, - }, - .dependencyCount = 0, - }, &pass); - - anv_CmdBeginRenderPass(anv_cmd_buffer_to_handle(cmd_buffer), - &(VkRenderPassBeginInfo) { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderArea = { - .offset = { 0, 0, }, - .extent = { - .width = view.base.extent.width, - .height = view.base.extent.height, - }, - }, - .renderPass = pass, - .framebuffer = fb, - .attachmentCount = 1, - .pAttachmentClearValues = NULL, - }, VK_RENDER_PASS_CONTENTS_INLINE); - - struct clear_instance_data instance_data = { - .vue_header = { - .RTAIndex = 0, - .ViewportIndex = 0, - .PointWidth = 0.0 - }, - .color = *pColor, - }; - - meta_emit_clear(cmd_buffer, 1, &instance_data); - - anv_CmdEndRenderPass(anv_cmd_buffer_to_handle(cmd_buffer)); - } - } - } - - /* Restore API state */ - anv_cmd_buffer_restore(cmd_buffer, &saved_state); -} - -void anv_CmdClearDepthStencilImage( - VkCmdBuffer cmdBuffer, - VkImage image, - VkImageLayout imageLayout, - float depth, - uint32_t stencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) -{ - stub(); -} - -void anv_CmdClearColorAttachment( - VkCmdBuffer cmdBuffer, - uint32_t colorAttachment, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - uint32_t rectCount, - const VkRect3D* pRects) -{ - stub(); -} - -void anv_CmdClearDepthStencilAttachment( - VkCmdBuffer cmdBuffer, - VkImageAspectFlags imageAspectMask, - VkImageLayout imageLayout, - float depth, - uint32_t stencil, - uint32_t rectCount, - const VkRect3D* pRects) -{ - stub(); -} - -void anv_CmdResolveImage( - VkCmdBuffer cmdBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage destImage, - VkImageLayout destImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions) -{ - stub(); -} - -void -anv_device_init_meta(struct anv_device *device) -{ - anv_device_init_meta_clear_state(device); - anv_device_init_meta_blit_state(device); - - anv_CreateDynamicRasterState(anv_device_to_handle(device), - &(VkDynamicRasterStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_DYNAMIC_RASTER_STATE_CREATE_INFO, - }, - &device->meta_state.shared.rs_state); - - anv_CreateDynamicColorBlendState(anv_device_to_handle(device), - &(VkDynamicColorBlendStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_DYNAMIC_COLOR_BLEND_STATE_CREATE_INFO - }, - &device->meta_state.shared.cb_state); - - anv_CreateDynamicDepthStencilState(anv_device_to_handle(device), - &(VkDynamicDepthStencilStateCreateInfo) { - .sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_STENCIL_STATE_CREATE_INFO - }, - &device->meta_state.shared.ds_state); -} - -void -anv_device_finish_meta(struct anv_device *device) -{ - /* Clear */ - anv_DestroyPipeline(anv_device_to_handle(device), - device->meta_state.clear.pipeline); - - /* Blit */ - anv_DestroyPipeline(anv_device_to_handle(device), - device->meta_state.blit.pipeline); - anv_DestroyPipelineLayout(anv_device_to_handle(device), - device->meta_state.blit.pipeline_layout); - anv_DestroyDescriptorSetLayout(anv_device_to_handle(device), - device->meta_state.blit.ds_layout); - - /* Shared */ - anv_DestroyDynamicRasterState(anv_device_to_handle(device), - device->meta_state.shared.rs_state); - anv_DestroyDynamicColorBlendState(anv_device_to_handle(device), - device->meta_state.shared.cb_state); - anv_DestroyDynamicDepthStencilState(anv_device_to_handle(device), - device->meta_state.shared.ds_state); -} diff --git a/src/vulkan/pipeline.c b/src/vulkan/pipeline.c deleted file mode 100644 index fdb632cd330..00000000000 --- a/src/vulkan/pipeline.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" - -// Shader functions - -VkResult anv_CreateShaderModule( - VkDevice _device, - const VkShaderModuleCreateInfo* pCreateInfo, - VkShaderModule* pShaderModule) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_shader_module *module; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); - assert(pCreateInfo->flags == 0); - - module = anv_device_alloc(device, sizeof(*module) + pCreateInfo->codeSize, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (module == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - module->size = pCreateInfo->codeSize; - memcpy(module->data, pCreateInfo->pCode, module->size); - - *pShaderModule = anv_shader_module_to_handle(module); - - return VK_SUCCESS; -} - -VkResult anv_DestroyShaderModule( - VkDevice _device, - VkShaderModule _module) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_shader_module, module, _module); - - anv_device_free(device, module); - - return VK_SUCCESS; -} - -VkResult anv_CreateShader( - VkDevice _device, - const VkShaderCreateInfo* pCreateInfo, - VkShader* pShader) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_shader_module, module, pCreateInfo->module); - struct anv_shader *shader; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_CREATE_INFO); - assert(pCreateInfo->flags == 0); - - size_t name_len = strlen(pCreateInfo->pName); - - if (strcmp(pCreateInfo->pName, "main") != 0) { - anv_finishme("Multiple shaders per module not really supported"); - } - - shader = anv_device_alloc(device, sizeof(*shader) + name_len + 1, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (shader == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - shader->module = module; - memcpy(shader->entrypoint, pCreateInfo->pName, name_len + 1); - - *pShader = anv_shader_to_handle(shader); - - return VK_SUCCESS; -} - -VkResult anv_DestroyShader( - VkDevice _device, - VkShader _shader) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_shader, shader, _shader); - - anv_device_free(device, shader); - - return VK_SUCCESS; -} - - -VkResult anv_CreatePipelineCache( - VkDevice device, - const VkPipelineCacheCreateInfo* pCreateInfo, - VkPipelineCache* pPipelineCache) -{ - pPipelineCache->handle = 1; - - stub_return(VK_SUCCESS); -} - -VkResult anv_DestroyPipelineCache( - VkDevice _device, - VkPipelineCache _cache) -{ - /* VkPipelineCache is a dummy object. */ - return VK_SUCCESS; -} - -size_t anv_GetPipelineCacheSize( - VkDevice device, - VkPipelineCache pipelineCache) -{ - stub_return(0); -} - -VkResult anv_GetPipelineCacheData( - VkDevice device, - VkPipelineCache pipelineCache, - void* pData) -{ - stub_return(VK_UNSUPPORTED); -} - -VkResult anv_MergePipelineCaches( - VkDevice device, - VkPipelineCache destCache, - uint32_t srcCacheCount, - const VkPipelineCache* pSrcCaches) -{ - stub_return(VK_UNSUPPORTED); -} - -// Pipeline functions - -static void -emit_vertex_input(struct anv_pipeline *pipeline, - const VkPipelineVertexInputStateCreateInfo *info) -{ - const uint32_t num_dwords = 1 + info->attributeCount * 2; - uint32_t *p; - bool instancing_enable[32]; - - pipeline->vb_used = 0; - for (uint32_t i = 0; i < info->bindingCount; i++) { - const VkVertexInputBindingDescription *desc = - &info->pVertexBindingDescriptions[i]; - - pipeline->vb_used |= 1 << desc->binding; - pipeline->binding_stride[desc->binding] = desc->strideInBytes; - - /* Step rate is programmed per vertex element (attribute), not - * binding. Set up a map of which bindings step per instance, for - * reference by vertex element setup. */ - switch (desc->stepRate) { - default: - case VK_VERTEX_INPUT_STEP_RATE_VERTEX: - instancing_enable[desc->binding] = false; - break; - case VK_VERTEX_INPUT_STEP_RATE_INSTANCE: - instancing_enable[desc->binding] = true; - break; - } - } - - p = anv_batch_emitn(&pipeline->batch, num_dwords, - GEN8_3DSTATE_VERTEX_ELEMENTS); - - for (uint32_t i = 0; i < info->attributeCount; i++) { - const VkVertexInputAttributeDescription *desc = - &info->pVertexAttributeDescriptions[i]; - const struct anv_format *format = anv_format_for_vk_format(desc->format); - - struct GEN8_VERTEX_ELEMENT_STATE element = { - .VertexBufferIndex = desc->binding, - .Valid = true, - .SourceElementFormat = format->surface_format, - .EdgeFlagEnable = false, - .SourceElementOffset = desc->offsetInBytes, - .Component0Control = VFCOMP_STORE_SRC, - .Component1Control = format->num_channels >= 2 ? VFCOMP_STORE_SRC : VFCOMP_STORE_0, - .Component2Control = format->num_channels >= 3 ? VFCOMP_STORE_SRC : VFCOMP_STORE_0, - .Component3Control = format->num_channels >= 4 ? VFCOMP_STORE_SRC : VFCOMP_STORE_1_FP - }; - GEN8_VERTEX_ELEMENT_STATE_pack(NULL, &p[1 + i * 2], &element); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_INSTANCING, - .InstancingEnable = instancing_enable[desc->binding], - .VertexElementIndex = i, - /* Vulkan so far doesn't have an instance divisor, so - * this is always 1 (ignored if not instancing). */ - .InstanceDataStepRate = 1); - } - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_SGVS, - .VertexIDEnable = pipeline->vs_prog_data.uses_vertexid, - .VertexIDComponentNumber = 2, - .VertexIDElementOffset = info->bindingCount, - .InstanceIDEnable = pipeline->vs_prog_data.uses_instanceid, - .InstanceIDComponentNumber = 3, - .InstanceIDElementOffset = info->bindingCount); -} - -static void -emit_ia_state(struct anv_pipeline *pipeline, - const VkPipelineInputAssemblyStateCreateInfo *info, - const struct anv_pipeline_create_info *extra) -{ - static const uint32_t vk_to_gen_primitive_type[] = { - [VK_PRIMITIVE_TOPOLOGY_POINT_LIST] = _3DPRIM_POINTLIST, - [VK_PRIMITIVE_TOPOLOGY_LINE_LIST] = _3DPRIM_LINELIST, - [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP] = _3DPRIM_LINESTRIP, - [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST] = _3DPRIM_TRILIST, - [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP] = _3DPRIM_TRISTRIP, - [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN] = _3DPRIM_TRIFAN, - [VK_PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ] = _3DPRIM_LINELIST_ADJ, - [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ] = _3DPRIM_LINESTRIP_ADJ, - [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ] = _3DPRIM_TRILIST_ADJ, - [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ] = _3DPRIM_TRISTRIP_ADJ, - [VK_PRIMITIVE_TOPOLOGY_PATCH] = _3DPRIM_PATCHLIST_1 - }; - uint32_t topology = vk_to_gen_primitive_type[info->topology]; - - if (extra && extra->use_rectlist) - topology = _3DPRIM_RECTLIST; - - struct GEN8_3DSTATE_VF vf = { - GEN8_3DSTATE_VF_header, - .IndexedDrawCutIndexEnable = info->primitiveRestartEnable, - }; - GEN8_3DSTATE_VF_pack(NULL, pipeline->state_vf, &vf); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_TOPOLOGY, - .PrimitiveTopologyType = topology); -} - -static void -emit_rs_state(struct anv_pipeline *pipeline, - const VkPipelineRasterStateCreateInfo *info, - const struct anv_pipeline_create_info *extra) -{ - static const uint32_t vk_to_gen_cullmode[] = { - [VK_CULL_MODE_NONE] = CULLMODE_NONE, - [VK_CULL_MODE_FRONT] = CULLMODE_FRONT, - [VK_CULL_MODE_BACK] = CULLMODE_BACK, - [VK_CULL_MODE_FRONT_AND_BACK] = CULLMODE_BOTH - }; - - static const uint32_t vk_to_gen_fillmode[] = { - [VK_FILL_MODE_POINTS] = RASTER_POINT, - [VK_FILL_MODE_WIREFRAME] = RASTER_WIREFRAME, - [VK_FILL_MODE_SOLID] = RASTER_SOLID - }; - - static const uint32_t vk_to_gen_front_face[] = { - [VK_FRONT_FACE_CCW] = CounterClockwise, - [VK_FRONT_FACE_CW] = Clockwise - }; - - struct GEN8_3DSTATE_SF sf = { - GEN8_3DSTATE_SF_header, - .ViewportTransformEnable = !(extra && extra->disable_viewport), - .TriangleStripListProvokingVertexSelect = 0, - .LineStripListProvokingVertexSelect = 0, - .TriangleFanProvokingVertexSelect = 0, - .PointWidthSource = pipeline->writes_point_size ? Vertex : State, - .PointWidth = 1.0, - }; - - /* FINISHME: VkBool32 rasterizerDiscardEnable; */ - - GEN8_3DSTATE_SF_pack(NULL, pipeline->state_sf, &sf); - - struct GEN8_3DSTATE_RASTER raster = { - GEN8_3DSTATE_RASTER_header, - .FrontWinding = vk_to_gen_front_face[info->frontFace], - .CullMode = vk_to_gen_cullmode[info->cullMode], - .FrontFaceFillMode = vk_to_gen_fillmode[info->fillMode], - .BackFaceFillMode = vk_to_gen_fillmode[info->fillMode], - .ScissorRectangleEnable = !(extra && extra->disable_scissor), - .ViewportZClipTestEnable = info->depthClipEnable - }; - - GEN8_3DSTATE_RASTER_pack(NULL, pipeline->state_raster, &raster); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SBE, - .ForceVertexURBEntryReadLength = false, - .ForceVertexURBEntryReadOffset = false, - .PointSpriteTextureCoordinateOrigin = UPPERLEFT, - .NumberofSFOutputAttributes = - pipeline->wm_prog_data.num_varying_inputs); - -} - -static void -emit_cb_state(struct anv_pipeline *pipeline, - const VkPipelineColorBlendStateCreateInfo *info) -{ - struct anv_device *device = pipeline->device; - - static const uint32_t vk_to_gen_logic_op[] = { - [VK_LOGIC_OP_COPY] = LOGICOP_COPY, - [VK_LOGIC_OP_CLEAR] = LOGICOP_CLEAR, - [VK_LOGIC_OP_AND] = LOGICOP_AND, - [VK_LOGIC_OP_AND_REVERSE] = LOGICOP_AND_REVERSE, - [VK_LOGIC_OP_AND_INVERTED] = LOGICOP_AND_INVERTED, - [VK_LOGIC_OP_NOOP] = LOGICOP_NOOP, - [VK_LOGIC_OP_XOR] = LOGICOP_XOR, - [VK_LOGIC_OP_OR] = LOGICOP_OR, - [VK_LOGIC_OP_NOR] = LOGICOP_NOR, - [VK_LOGIC_OP_EQUIV] = LOGICOP_EQUIV, - [VK_LOGIC_OP_INVERT] = LOGICOP_INVERT, - [VK_LOGIC_OP_OR_REVERSE] = LOGICOP_OR_REVERSE, - [VK_LOGIC_OP_COPY_INVERTED] = LOGICOP_COPY_INVERTED, - [VK_LOGIC_OP_OR_INVERTED] = LOGICOP_OR_INVERTED, - [VK_LOGIC_OP_NAND] = LOGICOP_NAND, - [VK_LOGIC_OP_SET] = LOGICOP_SET, - }; - - static const uint32_t vk_to_gen_blend[] = { - [VK_BLEND_ZERO] = BLENDFACTOR_ZERO, - [VK_BLEND_ONE] = BLENDFACTOR_ONE, - [VK_BLEND_SRC_COLOR] = BLENDFACTOR_SRC_COLOR, - [VK_BLEND_ONE_MINUS_SRC_COLOR] = BLENDFACTOR_INV_SRC_COLOR, - [VK_BLEND_DEST_COLOR] = BLENDFACTOR_DST_COLOR, - [VK_BLEND_ONE_MINUS_DEST_COLOR] = BLENDFACTOR_INV_DST_COLOR, - [VK_BLEND_SRC_ALPHA] = BLENDFACTOR_SRC_ALPHA, - [VK_BLEND_ONE_MINUS_SRC_ALPHA] = BLENDFACTOR_INV_SRC_ALPHA, - [VK_BLEND_DEST_ALPHA] = BLENDFACTOR_DST_ALPHA, - [VK_BLEND_ONE_MINUS_DEST_ALPHA] = BLENDFACTOR_INV_DST_ALPHA, - [VK_BLEND_CONSTANT_COLOR] = BLENDFACTOR_CONST_COLOR, - [VK_BLEND_ONE_MINUS_CONSTANT_COLOR] = BLENDFACTOR_INV_CONST_COLOR, - [VK_BLEND_CONSTANT_ALPHA] = BLENDFACTOR_CONST_ALPHA, - [VK_BLEND_ONE_MINUS_CONSTANT_ALPHA] = BLENDFACTOR_INV_CONST_ALPHA, - [VK_BLEND_SRC_ALPHA_SATURATE] = BLENDFACTOR_SRC_ALPHA_SATURATE, - [VK_BLEND_SRC1_COLOR] = BLENDFACTOR_SRC1_COLOR, - [VK_BLEND_ONE_MINUS_SRC1_COLOR] = BLENDFACTOR_INV_SRC1_COLOR, - [VK_BLEND_SRC1_ALPHA] = BLENDFACTOR_SRC1_ALPHA, - [VK_BLEND_ONE_MINUS_SRC1_ALPHA] = BLENDFACTOR_INV_SRC1_ALPHA, - }; - - static const uint32_t vk_to_gen_blend_op[] = { - [VK_BLEND_OP_ADD] = BLENDFUNCTION_ADD, - [VK_BLEND_OP_SUBTRACT] = BLENDFUNCTION_SUBTRACT, - [VK_BLEND_OP_REVERSE_SUBTRACT] = BLENDFUNCTION_REVERSE_SUBTRACT, - [VK_BLEND_OP_MIN] = BLENDFUNCTION_MIN, - [VK_BLEND_OP_MAX] = BLENDFUNCTION_MAX, - }; - - uint32_t num_dwords = 1 + info->attachmentCount * 2; - pipeline->blend_state = - anv_state_pool_alloc(&device->dynamic_state_pool, num_dwords * 4, 64); - - struct GEN8_BLEND_STATE blend_state = { - .AlphaToCoverageEnable = info->alphaToCoverageEnable, - }; - - uint32_t *state = pipeline->blend_state.map; - GEN8_BLEND_STATE_pack(NULL, state, &blend_state); - - for (uint32_t i = 0; i < info->attachmentCount; i++) { - const VkPipelineColorBlendAttachmentState *a = &info->pAttachments[i]; - - struct GEN8_BLEND_STATE_ENTRY entry = { - .LogicOpEnable = info->logicOpEnable, - .LogicOpFunction = vk_to_gen_logic_op[info->logicOp], - .ColorBufferBlendEnable = a->blendEnable, - .PreBlendSourceOnlyClampEnable = false, - .PreBlendColorClampEnable = false, - .PostBlendColorClampEnable = false, - .SourceBlendFactor = vk_to_gen_blend[a->srcBlendColor], - .DestinationBlendFactor = vk_to_gen_blend[a->destBlendColor], - .ColorBlendFunction = vk_to_gen_blend_op[a->blendOpColor], - .SourceAlphaBlendFactor = vk_to_gen_blend[a->srcBlendAlpha], - .DestinationAlphaBlendFactor = vk_to_gen_blend[a->destBlendAlpha], - .AlphaBlendFunction = vk_to_gen_blend_op[a->blendOpAlpha], - .WriteDisableAlpha = !(a->channelWriteMask & VK_CHANNEL_A_BIT), - .WriteDisableRed = !(a->channelWriteMask & VK_CHANNEL_R_BIT), - .WriteDisableGreen = !(a->channelWriteMask & VK_CHANNEL_G_BIT), - .WriteDisableBlue = !(a->channelWriteMask & VK_CHANNEL_B_BIT), - }; - - GEN8_BLEND_STATE_ENTRY_pack(NULL, state + i * 2 + 1, &entry); - } - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_BLEND_STATE_POINTERS, - .BlendStatePointer = pipeline->blend_state.offset, - .BlendStatePointerValid = true); -} - -static const uint32_t vk_to_gen_compare_op[] = { - [VK_COMPARE_OP_NEVER] = COMPAREFUNCTION_NEVER, - [VK_COMPARE_OP_LESS] = COMPAREFUNCTION_LESS, - [VK_COMPARE_OP_EQUAL] = COMPAREFUNCTION_EQUAL, - [VK_COMPARE_OP_LESS_EQUAL] = COMPAREFUNCTION_LEQUAL, - [VK_COMPARE_OP_GREATER] = COMPAREFUNCTION_GREATER, - [VK_COMPARE_OP_NOT_EQUAL] = COMPAREFUNCTION_NOTEQUAL, - [VK_COMPARE_OP_GREATER_EQUAL] = COMPAREFUNCTION_GEQUAL, - [VK_COMPARE_OP_ALWAYS] = COMPAREFUNCTION_ALWAYS, -}; - -static const uint32_t vk_to_gen_stencil_op[] = { - [VK_STENCIL_OP_KEEP] = 0, - [VK_STENCIL_OP_ZERO] = 0, - [VK_STENCIL_OP_REPLACE] = 0, - [VK_STENCIL_OP_INC_CLAMP] = 0, - [VK_STENCIL_OP_DEC_CLAMP] = 0, - [VK_STENCIL_OP_INVERT] = 0, - [VK_STENCIL_OP_INC_WRAP] = 0, - [VK_STENCIL_OP_DEC_WRAP] = 0 -}; - -static void -emit_ds_state(struct anv_pipeline *pipeline, - const VkPipelineDepthStencilStateCreateInfo *info) -{ - if (info == NULL) { - /* We're going to OR this together with the dynamic state. We need - * to make sure it's initialized to something useful. - */ - memset(pipeline->state_wm_depth_stencil, 0, - sizeof(pipeline->state_wm_depth_stencil)); - return; - } - - /* VkBool32 depthBoundsEnable; // optional (depth_bounds_test) */ - - struct GEN8_3DSTATE_WM_DEPTH_STENCIL wm_depth_stencil = { - .DepthTestEnable = info->depthTestEnable, - .DepthBufferWriteEnable = info->depthWriteEnable, - .DepthTestFunction = vk_to_gen_compare_op[info->depthCompareOp], - .DoubleSidedStencilEnable = true, - - .StencilTestEnable = info->stencilTestEnable, - .StencilFailOp = vk_to_gen_stencil_op[info->front.stencilFailOp], - .StencilPassDepthPassOp = vk_to_gen_stencil_op[info->front.stencilPassOp], - .StencilPassDepthFailOp = vk_to_gen_stencil_op[info->front.stencilDepthFailOp], - .StencilTestFunction = vk_to_gen_compare_op[info->front.stencilCompareOp], - .BackfaceStencilFailOp = vk_to_gen_stencil_op[info->back.stencilFailOp], - .BackfaceStencilPassDepthPassOp = vk_to_gen_stencil_op[info->back.stencilPassOp], - .BackfaceStencilPassDepthFailOp =vk_to_gen_stencil_op[info->back.stencilDepthFailOp], - .BackfaceStencilTestFunction = vk_to_gen_compare_op[info->back.stencilCompareOp], - }; - - GEN8_3DSTATE_WM_DEPTH_STENCIL_pack(NULL, pipeline->state_wm_depth_stencil, &wm_depth_stencil); -} - -VkResult -anv_pipeline_create( - VkDevice _device, - const VkGraphicsPipelineCreateInfo* pCreateInfo, - const struct anv_pipeline_create_info * extra, - VkPipeline* pPipeline) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_pipeline *pipeline; - VkResult result; - uint32_t offset, length; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO); - - pipeline = anv_device_alloc(device, sizeof(*pipeline), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (pipeline == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - pipeline->device = device; - pipeline->layout = anv_pipeline_layout_from_handle(pCreateInfo->layout); - memset(pipeline->shaders, 0, sizeof(pipeline->shaders)); - - result = anv_reloc_list_init(&pipeline->batch.relocs, device); - if (result != VK_SUCCESS) { - anv_device_free(device, pipeline); - return result; - } - pipeline->batch.next = pipeline->batch.start = pipeline->batch_data; - pipeline->batch.end = pipeline->batch.start + sizeof(pipeline->batch_data); - - anv_state_stream_init(&pipeline->program_stream, - &device->instruction_block_pool); - - for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { - pipeline->shaders[pCreateInfo->pStages[i].stage] = - anv_shader_from_handle(pCreateInfo->pStages[i].shader); - } - - if (pCreateInfo->pTessellationState) - anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO"); - if (pCreateInfo->pViewportState) - anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO"); - if (pCreateInfo->pMultisampleState) - anv_finishme("VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO"); - - pipeline->use_repclear = extra && extra->use_repclear; - - anv_compiler_run(device->compiler, pipeline); - - /* FIXME: The compiler dead-codes FS inputs when we don't have a VS, so we - * hard code this to num_attributes - 2. This is because the attributes - * include VUE header and position, which aren't counted as varying - * inputs. */ - if (pipeline->vs_simd8 == NO_KERNEL) { - pipeline->wm_prog_data.num_varying_inputs = - pCreateInfo->pVertexInputState->attributeCount - 2; - } - - assert(pCreateInfo->pVertexInputState); - emit_vertex_input(pipeline, pCreateInfo->pVertexInputState); - assert(pCreateInfo->pInputAssemblyState); - emit_ia_state(pipeline, pCreateInfo->pInputAssemblyState, extra); - assert(pCreateInfo->pRasterState); - emit_rs_state(pipeline, pCreateInfo->pRasterState, extra); - emit_ds_state(pipeline, pCreateInfo->pDepthStencilState); - emit_cb_state(pipeline, pCreateInfo->pColorBlendState); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VF_STATISTICS, - .StatisticsEnable = true); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_HS, .Enable = false); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_TE, .TEEnable = false); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_DS, .FunctionEnable = false); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_STREAMOUT, .SOFunctionEnable = false); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_VS, - .ConstantBufferOffset = 0, - .ConstantBufferSize = 4); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_GS, - .ConstantBufferOffset = 4, - .ConstantBufferSize = 4); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PUSH_CONSTANT_ALLOC_PS, - .ConstantBufferOffset = 8, - .ConstantBufferSize = 4); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_WM_CHROMAKEY, - .ChromaKeyKillEnable = false); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SBE_SWIZ); - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_AA_LINE_PARAMETERS); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_CLIP, - .ClipEnable = true, - .ViewportXYClipTestEnable = !(extra && extra->disable_viewport), - .MinimumPointWidth = 0.125, - .MaximumPointWidth = 255.875); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_WM, - .StatisticsEnable = true, - .LineEndCapAntialiasingRegionWidth = _05pixels, - .LineAntialiasingRegionWidth = _10pixels, - .EarlyDepthStencilControl = NORMAL, - .ForceThreadDispatchEnable = NORMAL, - .PointRasterizationRule = RASTRULE_UPPER_RIGHT, - .BarycentricInterpolationMode = - pipeline->wm_prog_data.barycentric_interp_modes); - - uint32_t samples = 1; - uint32_t log2_samples = __builtin_ffs(samples) - 1; - bool enable_sampling = samples > 1 ? true : false; - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_MULTISAMPLE, - .PixelPositionOffsetEnable = enable_sampling, - .PixelLocation = CENTER, - .NumberofMultisamples = log2_samples); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_SAMPLE_MASK, - .SampleMask = 0xffff); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_VS, - .VSURBStartingAddress = pipeline->urb.vs_start, - .VSURBEntryAllocationSize = pipeline->urb.vs_size - 1, - .VSNumberofURBEntries = pipeline->urb.nr_vs_entries); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_GS, - .GSURBStartingAddress = pipeline->urb.gs_start, - .GSURBEntryAllocationSize = pipeline->urb.gs_size - 1, - .GSNumberofURBEntries = pipeline->urb.nr_gs_entries); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_HS, - .HSURBStartingAddress = pipeline->urb.vs_start, - .HSURBEntryAllocationSize = 0, - .HSNumberofURBEntries = 0); - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_URB_DS, - .DSURBStartingAddress = pipeline->urb.vs_start, - .DSURBEntryAllocationSize = 0, - .DSNumberofURBEntries = 0); - - const struct brw_gs_prog_data *gs_prog_data = &pipeline->gs_prog_data; - offset = 1; - length = (gs_prog_data->base.vue_map.num_slots + 1) / 2 - offset; - - if (pipeline->gs_vec4 == NO_KERNEL) - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_GS, .Enable = false); - else - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_GS, - .SingleProgramFlow = false, - .KernelStartPointer = pipeline->gs_vec4, - .VectorMaskEnable = Vmask, - .SamplerCount = 0, - .BindingTableEntryCount = 0, - .ExpectedVertexCount = pipeline->gs_vertex_count, - - .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_GEOMETRY], - .PerThreadScratchSpace = ffs(gs_prog_data->base.base.total_scratch / 2048), - - .OutputVertexSize = gs_prog_data->output_vertex_size_hwords * 2 - 1, - .OutputTopology = gs_prog_data->output_topology, - .VertexURBEntryReadLength = gs_prog_data->base.urb_read_length, - .DispatchGRFStartRegisterForURBData = - gs_prog_data->base.base.dispatch_grf_start_reg, - - .MaximumNumberofThreads = device->info.max_gs_threads, - .ControlDataHeaderSize = gs_prog_data->control_data_header_size_hwords, - //pipeline->gs_prog_data.dispatch_mode | - .StatisticsEnable = true, - .IncludePrimitiveID = gs_prog_data->include_primitive_id, - .ReorderMode = TRAILING, - .Enable = true, - - .ControlDataFormat = gs_prog_data->control_data_format, - - /* FIXME: mesa sets this based on ctx->Transform.ClipPlanesEnabled: - * UserClipDistanceClipTestEnableBitmask_3DSTATE_GS(v) - * UserClipDistanceCullTestEnableBitmask(v) - */ - - .VertexURBEntryOutputReadOffset = offset, - .VertexURBEntryOutputLength = length); - - const struct brw_vue_prog_data *vue_prog_data = &pipeline->vs_prog_data.base; - /* Skip the VUE header and position slots */ - offset = 1; - length = (vue_prog_data->vue_map.num_slots + 1) / 2 - offset; - - if (pipeline->vs_simd8 == NO_KERNEL || (extra && extra->disable_vs)) - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VS, - .FunctionEnable = false, - .VertexURBEntryOutputReadOffset = 1, - /* Even if VS is disabled, SBE still gets the amount of - * vertex data to read from this field. We use attribute - * count - 1, as we don't count the VUE header here. */ - .VertexURBEntryOutputLength = - DIV_ROUND_UP(pCreateInfo->pVertexInputState->attributeCount - 1, 2)); - else - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_VS, - .KernelStartPointer = pipeline->vs_simd8, - .SingleVertexDispatch = Multiple, - .VectorMaskEnable = Dmask, - .SamplerCount = 0, - .BindingTableEntryCount = - vue_prog_data->base.binding_table.size_bytes / 4, - .ThreadDispatchPriority = Normal, - .FloatingPointMode = IEEE754, - .IllegalOpcodeExceptionEnable = false, - .AccessesUAV = false, - .SoftwareExceptionEnable = false, - - .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_VERTEX], - .PerThreadScratchSpace = ffs(vue_prog_data->base.total_scratch / 2048), - - .DispatchGRFStartRegisterForURBData = - vue_prog_data->base.dispatch_grf_start_reg, - .VertexURBEntryReadLength = vue_prog_data->urb_read_length, - .VertexURBEntryReadOffset = 0, - - .MaximumNumberofThreads = device->info.max_vs_threads - 1, - .StatisticsEnable = false, - .SIMD8DispatchEnable = true, - .VertexCacheDisable = false, - .FunctionEnable = true, - - .VertexURBEntryOutputReadOffset = offset, - .VertexURBEntryOutputLength = length, - .UserClipDistanceClipTestEnableBitmask = 0, - .UserClipDistanceCullTestEnableBitmask = 0); - - const struct brw_wm_prog_data *wm_prog_data = &pipeline->wm_prog_data; - uint32_t ksp0, ksp2, grf_start0, grf_start2; - - ksp2 = 0; - grf_start2 = 0; - if (pipeline->ps_simd8 != NO_KERNEL) { - ksp0 = pipeline->ps_simd8; - grf_start0 = wm_prog_data->base.dispatch_grf_start_reg; - if (pipeline->ps_simd16 != NO_KERNEL) { - ksp2 = pipeline->ps_simd16; - grf_start2 = wm_prog_data->dispatch_grf_start_reg_16; - } - } else if (pipeline->ps_simd16 != NO_KERNEL) { - ksp0 = pipeline->ps_simd16; - grf_start0 = wm_prog_data->dispatch_grf_start_reg_16; - } else { - unreachable("no ps shader"); - } - - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PS, - .KernelStartPointer0 = ksp0, - - .SingleProgramFlow = false, - .VectorMaskEnable = true, - .SamplerCount = 1, - - .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_FRAGMENT], - .PerThreadScratchSpace = ffs(wm_prog_data->base.total_scratch / 2048), - - .MaximumNumberofThreadsPerPSD = 64 - 2, - .PositionXYOffsetSelect = wm_prog_data->uses_pos_offset ? - POSOFFSET_SAMPLE: POSOFFSET_NONE, - .PushConstantEnable = wm_prog_data->base.nr_params > 0, - ._8PixelDispatchEnable = pipeline->ps_simd8 != NO_KERNEL, - ._16PixelDispatchEnable = pipeline->ps_simd16 != NO_KERNEL, - ._32PixelDispatchEnable = false, - - .DispatchGRFStartRegisterForConstantSetupData0 = grf_start0, - .DispatchGRFStartRegisterForConstantSetupData1 = 0, - .DispatchGRFStartRegisterForConstantSetupData2 = grf_start2, - - .KernelStartPointer1 = 0, - .KernelStartPointer2 = ksp2); - - bool per_sample_ps = false; - anv_batch_emit(&pipeline->batch, GEN8_3DSTATE_PS_EXTRA, - .PixelShaderValid = true, - .PixelShaderKillsPixel = wm_prog_data->uses_kill, - .PixelShaderComputedDepthMode = wm_prog_data->computed_depth_mode, - .AttributeEnable = wm_prog_data->num_varying_inputs > 0, - .oMaskPresenttoRenderTarget = wm_prog_data->uses_omask, - .PixelShaderIsPerSample = per_sample_ps); - - *pPipeline = anv_pipeline_to_handle(pipeline); - - return VK_SUCCESS; -} - -VkResult anv_DestroyPipeline( - VkDevice _device, - VkPipeline _pipeline) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_pipeline, pipeline, _pipeline); - - anv_compiler_free(pipeline); - anv_reloc_list_finish(&pipeline->batch.relocs, pipeline->device); - anv_state_stream_finish(&pipeline->program_stream); - anv_state_pool_free(&device->dynamic_state_pool, pipeline->blend_state); - anv_device_free(pipeline->device, pipeline); - - return VK_SUCCESS; -} - -VkResult anv_CreateGraphicsPipelines( - VkDevice _device, - VkPipelineCache pipelineCache, - uint32_t count, - const VkGraphicsPipelineCreateInfo* pCreateInfos, - VkPipeline* pPipelines) -{ - VkResult result = VK_SUCCESS; - - unsigned i = 0; - for (; i < count; i++) { - result = anv_pipeline_create(_device, &pCreateInfos[i], - NULL, &pPipelines[i]); - if (result != VK_SUCCESS) { - for (unsigned j = 0; j < i; j++) { - anv_DestroyPipeline(_device, pPipelines[j]); - } - - return result; - } - } - - return VK_SUCCESS; -} - -static VkResult anv_compute_pipeline_create( - VkDevice _device, - const VkComputePipelineCreateInfo* pCreateInfo, - VkPipeline* pPipeline) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_pipeline *pipeline; - VkResult result; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO); - - pipeline = anv_device_alloc(device, sizeof(*pipeline), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (pipeline == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - pipeline->device = device; - pipeline->layout = anv_pipeline_layout_from_handle(pCreateInfo->layout); - - result = anv_reloc_list_init(&pipeline->batch.relocs, device); - if (result != VK_SUCCESS) { - anv_device_free(device, pipeline); - return result; - } - pipeline->batch.next = pipeline->batch.start = pipeline->batch_data; - pipeline->batch.end = pipeline->batch.start + sizeof(pipeline->batch_data); - - anv_state_stream_init(&pipeline->program_stream, - &device->instruction_block_pool); - - memset(pipeline->shaders, 0, sizeof(pipeline->shaders)); - - pipeline->shaders[VK_SHADER_STAGE_COMPUTE] = - anv_shader_from_handle(pCreateInfo->cs.shader); - - pipeline->use_repclear = false; - - anv_compiler_run(device->compiler, pipeline); - - const struct brw_cs_prog_data *cs_prog_data = &pipeline->cs_prog_data; - - anv_batch_emit(&pipeline->batch, GEN8_MEDIA_VFE_STATE, - .ScratchSpaceBasePointer = pipeline->scratch_start[VK_SHADER_STAGE_FRAGMENT], - .PerThreadScratchSpace = ffs(cs_prog_data->base.total_scratch / 2048), - .ScratchSpaceBasePointerHigh = 0, - .StackSize = 0, - - .MaximumNumberofThreads = device->info.max_cs_threads - 1, - .NumberofURBEntries = 2, - .ResetGatewayTimer = true, - .BypassGatewayControl = true, - .URBEntryAllocationSize = 2, - .CURBEAllocationSize = 0); - - struct brw_cs_prog_data *prog_data = &pipeline->cs_prog_data; - uint32_t group_size = prog_data->local_size[0] * - prog_data->local_size[1] * prog_data->local_size[2]; - pipeline->cs_thread_width_max = DIV_ROUND_UP(group_size, prog_data->simd_size); - uint32_t remainder = group_size & (prog_data->simd_size - 1); - - if (remainder > 0) - pipeline->cs_right_mask = ~0u >> (32 - remainder); - else - pipeline->cs_right_mask = ~0u >> (32 - prog_data->simd_size); - - - *pPipeline = anv_pipeline_to_handle(pipeline); - - return VK_SUCCESS; -} - -VkResult anv_CreateComputePipelines( - VkDevice _device, - VkPipelineCache pipelineCache, - uint32_t count, - const VkComputePipelineCreateInfo* pCreateInfos, - VkPipeline* pPipelines) -{ - VkResult result = VK_SUCCESS; - - unsigned i = 0; - for (; i < count; i++) { - result = anv_compute_pipeline_create(_device, &pCreateInfos[i], - &pPipelines[i]); - if (result != VK_SUCCESS) { - for (unsigned j = 0; j < i; j++) { - anv_DestroyPipeline(_device, pPipelines[j]); - } - - return result; - } - } - - return VK_SUCCESS; -} - -// Pipeline layout functions - -VkResult anv_CreatePipelineLayout( - VkDevice _device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - VkPipelineLayout* pPipelineLayout) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - struct anv_pipeline_layout *layout; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); - - layout = anv_device_alloc(device, sizeof(*layout), 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (layout == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - layout->num_sets = pCreateInfo->descriptorSetCount; - - uint32_t surface_start[VK_SHADER_STAGE_NUM] = { 0, }; - uint32_t sampler_start[VK_SHADER_STAGE_NUM] = { 0, }; - - for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { - layout->stage[s].surface_count = 0; - layout->stage[s].sampler_count = 0; - } - - for (uint32_t i = 0; i < pCreateInfo->descriptorSetCount; i++) { - ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout, - pCreateInfo->pSetLayouts[i]); - - layout->set[i].layout = set_layout; - for (uint32_t s = 0; s < VK_SHADER_STAGE_NUM; s++) { - layout->set[i].surface_start[s] = surface_start[s]; - surface_start[s] += set_layout->stage[s].surface_count; - layout->set[i].sampler_start[s] = sampler_start[s]; - sampler_start[s] += set_layout->stage[s].sampler_count; - - layout->stage[s].surface_count += set_layout->stage[s].surface_count; - layout->stage[s].sampler_count += set_layout->stage[s].sampler_count; - } - } - - *pPipelineLayout = anv_pipeline_layout_to_handle(layout); - - return VK_SUCCESS; -} - -VkResult anv_DestroyPipelineLayout( - VkDevice _device, - VkPipelineLayout _pipelineLayout) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_pipeline_layout, pipeline_layout, _pipelineLayout); - - anv_device_free(device, pipeline_layout); - - return VK_SUCCESS; -} diff --git a/src/vulkan/private.h b/src/vulkan/private.h deleted file mode 100644 index ac64f294c2d..00000000000 --- a/src/vulkan/private.h +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_VALGRIND -#include -#include -#define VG(x) x -#define __gen_validate_value(x) VALGRIND_CHECK_MEM_IS_DEFINED(&(x), sizeof(x)) -#else -#define VG(x) -#endif - -#include "brw_device_info.h" -#include "util/macros.h" - -#define VK_PROTOTYPES -#include -#include -#include - -#include "entrypoints.h" - -#include "brw_context.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define anv_noreturn __attribute__((__noreturn__)) -#define anv_printflike(a, b) __attribute__((__format__(__printf__, a, b))) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -static inline uint32_t -align_u32(uint32_t v, uint32_t a) -{ - return (v + a - 1) & ~(a - 1); -} - -static inline int32_t -align_i32(int32_t v, int32_t a) -{ - return (v + a - 1) & ~(a - 1); -} - -/** Alignment must be a power of 2. */ -static inline bool -anv_is_aligned(uintmax_t n, uintmax_t a) -{ - assert(a == (a & -a)); - return (n & (a - 1)) == 0; -} - -static inline uint32_t -anv_minify(uint32_t n, uint32_t levels) -{ - if (unlikely(n == 0)) - return 0; - else - return MAX(n >> levels, 1); -} - -static inline bool -anv_clear_mask(uint32_t *inout_mask, uint32_t clear_mask) -{ - if (*inout_mask & clear_mask) { - *inout_mask &= ~clear_mask; - return true; - } else { - return false; - } -} - -#define for_each_bit(b, dword) \ - for (uint32_t __dword = (dword); \ - (b) = __builtin_ffs(__dword) - 1, __dword; \ - __dword &= ~(1 << (b))) - -/* Define no kernel as 1, since that's an illegal offset for a kernel */ -#define NO_KERNEL 1 - -struct anv_common { - VkStructureType sType; - const void* pNext; -}; - -/* Whenever we generate an error, pass it through this function. Useful for - * debugging, where we can break on it. Only call at error site, not when - * propagating errors. Might be useful to plug in a stack trace here. - */ - -static inline VkResult -vk_error(VkResult error) -{ -#ifdef DEBUG - fprintf(stderr, "vk_error: %x\n", error); -#endif - - return error; -} - -void __anv_finishme(const char *file, int line, const char *format, ...) - anv_printflike(3, 4); -void anv_loge(const char *format, ...) anv_printflike(1, 2); -void anv_loge_v(const char *format, va_list va); - -/** - * Print a FINISHME message, including its source location. - */ -#define anv_finishme(format, ...) \ - __anv_finishme(__FILE__, __LINE__, format, ##__VA_ARGS__); - -/* A non-fatal assert. Useful for debugging. */ -#ifdef DEBUG -#define anv_assert(x) ({ \ - if (unlikely(!(x))) \ - fprintf(stderr, "%s:%d ASSERT: %s\n", __FILE__, __LINE__, #x); \ -}) -#else -#define anv_assert(x) -#endif - -void anv_abortf(const char *format, ...) anv_noreturn anv_printflike(1, 2); -void anv_abortfv(const char *format, va_list va) anv_noreturn; - -#define stub_return(v) \ - do { \ - anv_finishme("stub %s", __func__); \ - return (v); \ - } while (0) - -#define stub() \ - do { \ - anv_finishme("stub %s", __func__); \ - return; \ - } while (0) - -/** - * A dynamically growable, circular buffer. Elements are added at head and - * removed from tail. head and tail are free-running uint32_t indices and we - * only compute the modulo with size when accessing the array. This way, - * number of bytes in the queue is always head - tail, even in case of - * wraparound. - */ - -struct anv_vector { - uint32_t head; - uint32_t tail; - uint32_t element_size; - uint32_t size; - void *data; -}; - -int anv_vector_init(struct anv_vector *queue, uint32_t element_size, uint32_t size); -void *anv_vector_add(struct anv_vector *queue); -void *anv_vector_remove(struct anv_vector *queue); - -static inline int -anv_vector_length(struct anv_vector *queue) -{ - return (queue->head - queue->tail) / queue->element_size; -} - -static inline void -anv_vector_finish(struct anv_vector *queue) -{ - free(queue->data); -} - -#define anv_vector_foreach(elem, queue) \ - static_assert(__builtin_types_compatible_p(__typeof__(queue), struct anv_vector *), ""); \ - for (uint32_t __anv_vector_offset = (queue)->tail; \ - elem = (queue)->data + (__anv_vector_offset & ((queue)->size - 1)), __anv_vector_offset < (queue)->head; \ - __anv_vector_offset += (queue)->element_size) - -struct anv_bo { - int gem_handle; - uint32_t index; - uint64_t offset; - uint64_t size; - - /* This field is here for the benefit of the aub dumper. It can (and for - * userptr bos it must) be set to the cpu map of the buffer. Destroying - * the bo won't clean up the mmap, it's still the responsibility of the bo - * user to do that. */ - void *map; -}; - -/* Represents a lock-free linked list of "free" things. This is used by - * both the block pool and the state pools. Unfortunately, in order to - * solve the ABA problem, we can't use a single uint32_t head. - */ -union anv_free_list { - struct { - uint32_t offset; - - /* A simple count that is incremented every time the head changes. */ - uint32_t count; - }; - uint64_t u64; -}; - -#define ANV_FREE_LIST_EMPTY ((union anv_free_list) { { 1, 0 } }) - -struct anv_block_pool { - struct anv_device *device; - - struct anv_bo bo; - void *map; - int fd; - uint32_t size; - - /** - * Array of mmaps and gem handles owned by the block pool, reclaimed when - * the block pool is destroyed. - */ - struct anv_vector mmap_cleanups; - - uint32_t block_size; - - uint32_t next_block; - union anv_free_list free_list; -}; - -struct anv_block_state { - union { - struct { - uint32_t next; - uint32_t end; - }; - uint64_t u64; - }; -}; - -struct anv_state { - uint32_t offset; - uint32_t alloc_size; - void *map; -}; - -struct anv_fixed_size_state_pool { - size_t state_size; - union anv_free_list free_list; - struct anv_block_state block; -}; - -#define ANV_MIN_STATE_SIZE_LOG2 6 -#define ANV_MAX_STATE_SIZE_LOG2 10 - -#define ANV_STATE_BUCKETS (ANV_MAX_STATE_SIZE_LOG2 - ANV_MIN_STATE_SIZE_LOG2) - -struct anv_state_pool { - struct anv_block_pool *block_pool; - struct anv_fixed_size_state_pool buckets[ANV_STATE_BUCKETS]; -}; - -struct anv_state_stream { - struct anv_block_pool *block_pool; - uint32_t next; - uint32_t current_block; - uint32_t end; -}; - -void anv_block_pool_init(struct anv_block_pool *pool, - struct anv_device *device, uint32_t block_size); -void anv_block_pool_finish(struct anv_block_pool *pool); -uint32_t anv_block_pool_alloc(struct anv_block_pool *pool); -void anv_block_pool_free(struct anv_block_pool *pool, uint32_t offset); -void anv_state_pool_init(struct anv_state_pool *pool, - struct anv_block_pool *block_pool); -struct anv_state anv_state_pool_alloc(struct anv_state_pool *pool, - size_t state_size, size_t alignment); -void anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state); -void anv_state_stream_init(struct anv_state_stream *stream, - struct anv_block_pool *block_pool); -void anv_state_stream_finish(struct anv_state_stream *stream); -struct anv_state anv_state_stream_alloc(struct anv_state_stream *stream, - uint32_t size, uint32_t alignment); - -/** - * Implements a pool of re-usable BOs. The interface is identical to that - * of block_pool except that each block is its own BO. - */ -struct anv_bo_pool { - struct anv_device *device; - - uint32_t bo_size; - - void *free_list; -}; - -void anv_bo_pool_init(struct anv_bo_pool *pool, - struct anv_device *device, uint32_t block_size); -void anv_bo_pool_finish(struct anv_bo_pool *pool); -VkResult anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo); -void anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo); - -struct anv_physical_device { - struct anv_instance * instance; - uint32_t chipset_id; - bool no_hw; - const char * path; - const char * name; - const struct brw_device_info * info; - int fd; -}; - -struct anv_instance { - void * pAllocUserData; - PFN_vkAllocFunction pfnAlloc; - PFN_vkFreeFunction pfnFree; - uint32_t apiVersion; - uint32_t physicalDeviceCount; - struct anv_physical_device physicalDevice; -}; - -struct anv_meta_state { - struct { - VkPipeline pipeline; - } clear; - - struct { - VkPipeline pipeline; - VkPipelineLayout pipeline_layout; - VkDescriptorSetLayout ds_layout; - } blit; - - struct { - VkDynamicRasterState rs_state; - VkDynamicColorBlendState cb_state; - VkDynamicDepthStencilState ds_state; - } shared; -}; - -struct anv_queue { - struct anv_device * device; - - struct anv_state_pool * pool; - - /** - * Serial number of the most recently completed batch executed on the - * engine. - */ - struct anv_state completed_serial; - - /** - * The next batch submitted to the engine will be assigned this serial - * number. - */ - uint32_t next_serial; - - uint32_t last_collected_serial; -}; - -struct anv_device { - struct anv_instance * instance; - uint32_t chipset_id; - struct brw_device_info info; - int context_id; - int fd; - bool no_hw; - bool dump_aub; - - struct anv_bo_pool batch_bo_pool; - - struct anv_block_pool dynamic_state_block_pool; - struct anv_state_pool dynamic_state_pool; - - struct anv_block_pool instruction_block_pool; - struct anv_block_pool surface_state_block_pool; - struct anv_state_pool surface_state_pool; - - struct anv_meta_state meta_state; - - struct anv_state border_colors; - - struct anv_queue queue; - - struct anv_block_pool scratch_block_pool; - - struct anv_compiler * compiler; - struct anv_aub_writer * aub_writer; - pthread_mutex_t mutex; -}; - -void * -anv_device_alloc(struct anv_device * device, - size_t size, - size_t alignment, - VkSystemAllocType allocType); - -void -anv_device_free(struct anv_device * device, - void * mem); - -void* anv_gem_mmap(struct anv_device *device, - uint32_t gem_handle, uint64_t offset, uint64_t size); -void anv_gem_munmap(void *p, uint64_t size); -uint32_t anv_gem_create(struct anv_device *device, size_t size); -void anv_gem_close(struct anv_device *device, int gem_handle); -int anv_gem_userptr(struct anv_device *device, void *mem, size_t size); -int anv_gem_wait(struct anv_device *device, int gem_handle, int64_t *timeout_ns); -int anv_gem_execbuffer(struct anv_device *device, - struct drm_i915_gem_execbuffer2 *execbuf); -int anv_gem_set_tiling(struct anv_device *device, int gem_handle, - uint32_t stride, uint32_t tiling); -int anv_gem_create_context(struct anv_device *device); -int anv_gem_destroy_context(struct anv_device *device, int context); -int anv_gem_get_param(int fd, uint32_t param); -int anv_gem_get_aperture(struct anv_physical_device *physical_dev, uint64_t *size); -int anv_gem_handle_to_fd(struct anv_device *device, int gem_handle); -int anv_gem_fd_to_handle(struct anv_device *device, int fd); -int anv_gem_userptr(struct anv_device *device, void *mem, size_t size); - -VkResult anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, uint64_t size); - -struct anv_reloc_list { - size_t num_relocs; - size_t array_length; - struct drm_i915_gem_relocation_entry * relocs; - struct anv_bo ** reloc_bos; -}; - -VkResult anv_reloc_list_init(struct anv_reloc_list *list, - struct anv_device *device); -void anv_reloc_list_finish(struct anv_reloc_list *list, - struct anv_device *device); - -uint64_t anv_reloc_list_add(struct anv_reloc_list *list, - struct anv_device *device, - uint32_t offset, struct anv_bo *target_bo, - uint32_t delta); - -struct anv_batch_bo { - struct anv_bo bo; - - /* Bytes actually consumed in this batch BO */ - size_t length; - - /* These offsets reference the per-batch reloc list */ - size_t first_reloc; - size_t num_relocs; - - struct anv_batch_bo * prev_batch_bo; -}; - -struct anv_batch { - struct anv_device * device; - - void * start; - void * end; - void * next; - - struct anv_reloc_list relocs; - - /* This callback is called (with the associated user data) in the event - * that the batch runs out of space. - */ - VkResult (*extend_cb)(struct anv_batch *, void *); - void * user_data; -}; - -void *anv_batch_emit_dwords(struct anv_batch *batch, int num_dwords); -void anv_batch_emit_batch(struct anv_batch *batch, struct anv_batch *other); -uint64_t anv_batch_emit_reloc(struct anv_batch *batch, - void *location, struct anv_bo *bo, uint32_t offset); - -struct anv_address { - struct anv_bo *bo; - uint32_t offset; -}; - -#define __gen_address_type struct anv_address -#define __gen_user_data struct anv_batch - -static inline uint64_t -__gen_combine_address(struct anv_batch *batch, void *location, - const struct anv_address address, uint32_t delta) -{ - if (address.bo == NULL) { - return delta; - } else { - assert(batch->start <= location && location < batch->end); - - return anv_batch_emit_reloc(batch, location, address.bo, address.offset + delta); - } -} - -#include "gen7_pack.h" -#include "gen75_pack.h" -#undef GEN8_3DSTATE_MULTISAMPLE -#include "gen8_pack.h" - -#define anv_batch_emit(batch, cmd, ...) do { \ - struct cmd __template = { \ - cmd ## _header, \ - __VA_ARGS__ \ - }; \ - void *__dst = anv_batch_emit_dwords(batch, cmd ## _length); \ - cmd ## _pack(batch, __dst, &__template); \ - } while (0) - -#define anv_batch_emitn(batch, n, cmd, ...) ({ \ - struct cmd __template = { \ - cmd ## _header, \ - .DwordLength = n - cmd ## _length_bias, \ - __VA_ARGS__ \ - }; \ - void *__dst = anv_batch_emit_dwords(batch, n); \ - cmd ## _pack(batch, __dst, &__template); \ - __dst; \ - }) - -#define anv_batch_emit_merge(batch, dwords0, dwords1) \ - do { \ - uint32_t *dw; \ - \ - assert(ARRAY_SIZE(dwords0) == ARRAY_SIZE(dwords1)); \ - dw = anv_batch_emit_dwords((batch), ARRAY_SIZE(dwords0)); \ - for (uint32_t i = 0; i < ARRAY_SIZE(dwords0); i++) \ - dw[i] = (dwords0)[i] | (dwords1)[i]; \ - VG(VALGRIND_CHECK_MEM_IS_DEFINED(dw, ARRAY_SIZE(dwords0) * 4));\ - } while (0) - -#define GEN8_MOCS { \ - .MemoryTypeLLCeLLCCacheabilityControl = WB, \ - .TargetCache = L3DefertoPATforLLCeLLCselection, \ - .AgeforQUADLRU = 0 \ - } - -struct anv_device_memory { - struct anv_bo bo; - VkDeviceSize map_size; - void * map; -}; - -struct anv_dynamic_vp_state { - struct anv_state sf_clip_vp; - struct anv_state cc_vp; - struct anv_state scissor; -}; - -struct anv_dynamic_rs_state { - uint32_t state_sf[GEN8_3DSTATE_SF_length]; - uint32_t state_raster[GEN8_3DSTATE_RASTER_length]; -}; - -struct anv_dynamic_ds_state { - uint32_t state_wm_depth_stencil[GEN8_3DSTATE_WM_DEPTH_STENCIL_length]; - uint32_t state_color_calc[GEN8_COLOR_CALC_STATE_length]; -}; - -struct anv_dynamic_cb_state { - uint32_t state_color_calc[GEN8_COLOR_CALC_STATE_length]; - -}; - -struct anv_descriptor_slot { - int8_t dynamic_slot; - uint8_t index; -}; - -struct anv_descriptor_set_layout { - struct { - uint32_t surface_count; - struct anv_descriptor_slot *surface_start; - uint32_t sampler_count; - struct anv_descriptor_slot *sampler_start; - } stage[VK_SHADER_STAGE_NUM]; - - uint32_t count; - uint32_t num_dynamic_buffers; - uint32_t shader_stages; - struct anv_descriptor_slot entries[0]; -}; - -struct anv_descriptor { - struct anv_sampler *sampler; - struct anv_surface_view *view; -}; - -struct anv_descriptor_set { - struct anv_descriptor descriptors[0]; -}; - -VkResult -anv_descriptor_set_create(struct anv_device *device, - const struct anv_descriptor_set_layout *layout, - struct anv_descriptor_set **out_set); - -void -anv_descriptor_set_destroy(struct anv_device *device, - struct anv_descriptor_set *set); - -#define MAX_VBS 32 -#define MAX_SETS 8 -#define MAX_RTS 8 - -struct anv_pipeline_layout { - struct { - struct anv_descriptor_set_layout *layout; - uint32_t surface_start[VK_SHADER_STAGE_NUM]; - uint32_t sampler_start[VK_SHADER_STAGE_NUM]; - } set[MAX_SETS]; - - uint32_t num_sets; - - struct { - uint32_t surface_count; - uint32_t sampler_count; - } stage[VK_SHADER_STAGE_NUM]; -}; - -struct anv_buffer { - struct anv_device * device; - VkDeviceSize size; - - /* Set when bound */ - struct anv_bo * bo; - VkDeviceSize offset; -}; - -#define ANV_CMD_BUFFER_PIPELINE_DIRTY (1 << 0) -#define ANV_CMD_BUFFER_RS_DIRTY (1 << 2) -#define ANV_CMD_BUFFER_DS_DIRTY (1 << 3) -#define ANV_CMD_BUFFER_CB_DIRTY (1 << 4) -#define ANV_CMD_BUFFER_VP_DIRTY (1 << 5) -#define ANV_CMD_BUFFER_INDEX_BUFFER_DIRTY (1 << 6) - -struct anv_vertex_binding { - struct anv_buffer * buffer; - VkDeviceSize offset; -}; - -struct anv_descriptor_set_binding { - struct anv_descriptor_set * set; - uint32_t dynamic_offsets[128]; -}; - -/** State required while building cmd buffer */ -struct anv_cmd_state { - uint32_t current_pipeline; - uint32_t vb_dirty; - uint32_t dirty; - uint32_t compute_dirty; - uint32_t descriptors_dirty; - uint32_t scratch_size; - struct anv_pipeline * pipeline; - struct anv_pipeline * compute_pipeline; - struct anv_framebuffer * framebuffer; - struct anv_render_pass * pass; - struct anv_subpass * subpass; - struct anv_dynamic_rs_state * rs_state; - struct anv_dynamic_ds_state * ds_state; - struct anv_dynamic_vp_state * vp_state; - struct anv_dynamic_cb_state * cb_state; - uint32_t state_vf[GEN8_3DSTATE_VF_length]; - struct anv_vertex_binding vertex_bindings[MAX_VBS]; - struct anv_descriptor_set_binding descriptors[MAX_SETS]; -}; - -VkResult anv_cmd_state_init(struct anv_cmd_state *state); -void anv_cmd_state_fini(struct anv_cmd_state *state); - -struct anv_cmd_buffer { - struct anv_device * device; - - struct drm_i915_gem_execbuffer2 execbuf; - struct drm_i915_gem_exec_object2 * exec2_objects; - uint32_t exec2_bo_count; - struct anv_bo ** exec2_bos; - uint32_t exec2_array_length; - bool need_reloc; - uint32_t serial; - - struct anv_batch batch; - struct anv_batch_bo * last_batch_bo; - struct anv_batch_bo * surface_batch_bo; - uint32_t surface_next; - struct anv_reloc_list surface_relocs; - struct anv_state_stream surface_state_stream; - struct anv_state_stream dynamic_state_stream; - - struct anv_cmd_state state; -}; - -struct anv_state -anv_cmd_buffer_alloc_surface_state(struct anv_cmd_buffer *cmd_buffer, - uint32_t size, uint32_t alignment); -struct anv_state -anv_cmd_buffer_alloc_dynamic_state(struct anv_cmd_buffer *cmd_buffer, - uint32_t size, uint32_t alignment); - -VkResult anv_cmd_buffer_new_surface_state_bo(struct anv_cmd_buffer *cmd_buffer); - -void anv_cmd_buffer_emit_state_base_address(struct anv_cmd_buffer *cmd_buffer); - -void anv_cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer, - struct anv_subpass *subpass); - -void anv_cmd_buffer_clear_attachments(struct anv_cmd_buffer *cmd_buffer, - struct anv_render_pass *pass, - const VkClearValue *clear_values); - -void anv_cmd_buffer_dump(struct anv_cmd_buffer *cmd_buffer); -void anv_aub_writer_destroy(struct anv_aub_writer *writer); - -struct anv_fence { - struct anv_bo bo; - struct drm_i915_gem_execbuffer2 execbuf; - struct drm_i915_gem_exec_object2 exec2_objects[1]; - bool ready; -}; - -struct anv_shader_module { - uint32_t size; - char data[0]; -}; - -struct anv_shader { - struct anv_shader_module * module; - char entrypoint[0]; -}; - -struct anv_pipeline { - struct anv_device * device; - struct anv_batch batch; - uint32_t batch_data[256]; - struct anv_shader * shaders[VK_SHADER_STAGE_NUM]; - struct anv_pipeline_layout * layout; - bool use_repclear; - - struct brw_vs_prog_data vs_prog_data; - struct brw_wm_prog_data wm_prog_data; - struct brw_gs_prog_data gs_prog_data; - struct brw_cs_prog_data cs_prog_data; - bool writes_point_size; - struct brw_stage_prog_data * prog_data[VK_SHADER_STAGE_NUM]; - uint32_t scratch_start[VK_SHADER_STAGE_NUM]; - uint32_t total_scratch; - struct { - uint32_t vs_start; - uint32_t vs_size; - uint32_t nr_vs_entries; - uint32_t gs_start; - uint32_t gs_size; - uint32_t nr_gs_entries; - } urb; - - uint32_t active_stages; - struct anv_state_stream program_stream; - struct anv_state blend_state; - uint32_t vs_simd8; - uint32_t ps_simd8; - uint32_t ps_simd16; - uint32_t gs_vec4; - uint32_t gs_vertex_count; - uint32_t cs_simd; - - uint32_t vb_used; - uint32_t binding_stride[MAX_VBS]; - - uint32_t state_sf[GEN8_3DSTATE_SF_length]; - uint32_t state_vf[GEN8_3DSTATE_VF_length]; - uint32_t state_raster[GEN8_3DSTATE_RASTER_length]; - uint32_t state_wm_depth_stencil[GEN8_3DSTATE_WM_DEPTH_STENCIL_length]; - - uint32_t cs_thread_width_max; - uint32_t cs_right_mask; -}; - -struct anv_pipeline_create_info { - bool use_repclear; - bool disable_viewport; - bool disable_scissor; - bool disable_vs; - bool use_rectlist; -}; - -VkResult -anv_pipeline_create(VkDevice device, - const VkGraphicsPipelineCreateInfo *pCreateInfo, - const struct anv_pipeline_create_info *extra, - VkPipeline *pPipeline); - -struct anv_compiler *anv_compiler_create(struct anv_device *device); -void anv_compiler_destroy(struct anv_compiler *compiler); -int anv_compiler_run(struct anv_compiler *compiler, struct anv_pipeline *pipeline); -void anv_compiler_free(struct anv_pipeline *pipeline); - -struct anv_format { - const char *name; - uint16_t surface_format; /**< RENDER_SURFACE_STATE.SurfaceFormat */ - uint8_t cpp; /**< Bytes-per-pixel of anv_format::surface_format. */ - uint8_t num_channels; - uint16_t depth_format; /**< 3DSTATE_DEPTH_BUFFER.SurfaceFormat */ - bool has_stencil; -}; - -const struct anv_format * -anv_format_for_vk_format(VkFormat format); -bool anv_is_vk_format_depth_or_stencil(VkFormat format); - -/** - * A proxy for the color surfaces, depth surfaces, and stencil surfaces. - */ -struct anv_surface { - /** - * Offset from VkImage's base address, as bound by vkBindImageMemory(). - */ - uint32_t offset; - - uint32_t stride; /**< RENDER_SURFACE_STATE.SurfacePitch */ - uint16_t qpitch; /**< RENDER_SURFACE_STATE.QPitch */ - - /** - * \name Alignment of miptree images, in units of pixels. - * - * These fields contain the real alignment values, not the values to be - * given to the GPU. For example, if h_align is 4, then program the GPU - * with HALIGN_4. - * \{ - */ - uint8_t h_align; /**< RENDER_SURFACE_STATE.SurfaceHorizontalAlignment */ - uint8_t v_align; /**< RENDER_SURFACE_STATE.SurfaceVerticalAlignment */ - /** \} */ - - uint8_t tile_mode; /**< RENDER_SURFACE_STATE.TileMode */ -}; - -struct anv_image { - VkImageType type; - VkExtent3D extent; - VkFormat format; - uint32_t levels; - uint32_t array_size; - - VkDeviceSize size; - uint32_t alignment; - - /* Set when bound */ - struct anv_bo *bo; - VkDeviceSize offset; - - struct anv_swap_chain *swap_chain; - - /** RENDER_SURFACE_STATE.SurfaceType */ - uint8_t surf_type; - - /** Primary surface is either color or depth. */ - struct anv_surface primary_surface; - - /** Stencil surface is optional. */ - struct anv_surface stencil_surface; -}; - -struct anv_surface_view { - struct anv_state surface_state; /**< RENDER_SURFACE_STATE */ - struct anv_bo *bo; - uint32_t offset; /**< VkBufferCreateInfo::offset */ - uint32_t range; /**< VkBufferCreateInfo::range */ - VkFormat format; /**< VkBufferCreateInfo::format */ -}; - -struct anv_buffer_view { - struct anv_surface_view view; -}; - -struct anv_image_view { - struct anv_surface_view view; - VkExtent3D extent; -}; - -enum anv_attachment_view_type { - ANV_ATTACHMENT_VIEW_TYPE_COLOR, - ANV_ATTACHMENT_VIEW_TYPE_DEPTH_STENCIL, -}; - -struct anv_attachment_view { - enum anv_attachment_view_type attachment_type; - VkExtent3D extent; -}; - -struct anv_color_attachment_view { - struct anv_attachment_view base; - struct anv_surface_view view; -}; - -struct anv_depth_stencil_view { - struct anv_attachment_view base; - - struct anv_bo *bo; - - uint32_t depth_offset; /**< Offset into bo. */ - uint32_t depth_stride; /**< 3DSTATE_DEPTH_BUFFER.SurfacePitch */ - uint32_t depth_format; /**< 3DSTATE_DEPTH_BUFFER.SurfaceFormat */ - uint16_t depth_qpitch; /**< 3DSTATE_DEPTH_BUFFER.SurfaceQPitch */ - - uint32_t stencil_offset; /**< Offset into bo. */ - uint32_t stencil_stride; /**< 3DSTATE_STENCIL_BUFFER.SurfacePitch */ - uint16_t stencil_qpitch; /**< 3DSTATE_STENCIL_BUFFER.SurfaceQPitch */ -}; - -struct anv_image_create_info { - const VkImageCreateInfo *vk_info; - bool force_tile_mode; - uint8_t tile_mode; -}; - -VkResult anv_image_create(VkDevice _device, - const struct anv_image_create_info *info, - VkImage *pImage); - -void anv_image_view_init(struct anv_image_view *view, - struct anv_device *device, - const VkImageViewCreateInfo* pCreateInfo, - struct anv_cmd_buffer *cmd_buffer); - -void anv_color_attachment_view_init(struct anv_color_attachment_view *view, - struct anv_device *device, - const VkAttachmentViewCreateInfo* pCreateInfo, - struct anv_cmd_buffer *cmd_buffer); -void anv_fill_buffer_surface_state(void *state, VkFormat format, - uint32_t offset, uint32_t range); - -void anv_surface_view_fini(struct anv_device *device, - struct anv_surface_view *view); - -struct anv_sampler { - uint32_t state[4]; -}; - -struct anv_framebuffer { - uint32_t width; - uint32_t height; - uint32_t layers; - - /* Viewport for clears */ - VkDynamicViewportState vp_state; - - uint32_t attachment_count; - const struct anv_attachment_view * attachments[0]; -}; - -struct anv_subpass { - uint32_t input_count; - uint32_t * input_attachments; - uint32_t color_count; - uint32_t * color_attachments; - uint32_t * resolve_attachments; - uint32_t depth_stencil_attachment; -}; - -struct anv_render_pass_attachment { - VkFormat format; - uint32_t samples; - VkAttachmentLoadOp load_op; - VkAttachmentLoadOp stencil_load_op; -}; - -struct anv_render_pass { - uint32_t attachment_count; - uint32_t subpass_count; - - struct anv_render_pass_attachment * attachments; - struct anv_subpass subpasses[0]; -}; - -void anv_device_init_meta(struct anv_device *device); -void anv_device_finish_meta(struct anv_device *device); - -void *anv_lookup_entrypoint(const char *name); - -#define ANV_DEFINE_HANDLE_CASTS(__anv_type, __VkType) \ - \ - static inline struct __anv_type * \ - __anv_type ## _from_handle(__VkType _handle) \ - { \ - return (struct __anv_type *) _handle; \ - } \ - \ - static inline __VkType \ - __anv_type ## _to_handle(struct __anv_type *_obj) \ - { \ - return (__VkType) _obj; \ - } - -#define ANV_DEFINE_NONDISP_HANDLE_CASTS(__anv_type, __VkType) \ - \ - static inline struct __anv_type * \ - __anv_type ## _from_handle(__VkType _handle) \ - { \ - return (struct __anv_type *) _handle.handle; \ - } \ - \ - static inline __VkType \ - __anv_type ## _to_handle(struct __anv_type *_obj) \ - { \ - return (__VkType) { .handle = (uint64_t) _obj }; \ - } - -#define ANV_FROM_HANDLE(__anv_type, __name, __handle) \ - struct __anv_type *__name = __anv_type ## _from_handle(__handle) - -ANV_DEFINE_HANDLE_CASTS(anv_cmd_buffer, VkCmdBuffer) -ANV_DEFINE_HANDLE_CASTS(anv_device, VkDevice) -ANV_DEFINE_HANDLE_CASTS(anv_instance, VkInstance) -ANV_DEFINE_HANDLE_CASTS(anv_physical_device, VkPhysicalDevice) -ANV_DEFINE_HANDLE_CASTS(anv_queue, VkQueue) -ANV_DEFINE_HANDLE_CASTS(anv_swap_chain, VkSwapChainWSI); - -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_attachment_view, VkAttachmentView) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer, VkBuffer) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer_view, VkBufferView); -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set, VkDescriptorSet) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set_layout, VkDescriptorSetLayout) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_device_memory, VkDeviceMemory) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_cb_state, VkDynamicColorBlendState) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_ds_state, VkDynamicDepthStencilState) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_rs_state, VkDynamicRasterState) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_dynamic_vp_state, VkDynamicViewportState) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_fence, VkFence) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_framebuffer, VkFramebuffer) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_image, VkImage) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_image_view, VkImageView); -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_pipeline, VkPipeline) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_pipeline_layout, VkPipelineLayout) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_query_pool, VkQueryPool) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_render_pass, VkRenderPass) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_sampler, VkSampler) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_shader, VkShader) -ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_shader_module, VkShaderModule) - -#define ANV_DEFINE_STRUCT_CASTS(__anv_type, __VkType) \ - \ - static inline const __VkType * \ - __anv_type ## _to_ ## __VkType(const struct __anv_type *__anv_obj) \ - { \ - return (const __VkType *) __anv_obj; \ - } - -#define ANV_COMMON_TO_STRUCT(__VkType, __vk_name, __common_name) \ - const __VkType *__vk_name = anv_common_to_ ## __VkType(__common_name) - -ANV_DEFINE_STRUCT_CASTS(anv_common, VkMemoryBarrier) -ANV_DEFINE_STRUCT_CASTS(anv_common, VkBufferMemoryBarrier) -ANV_DEFINE_STRUCT_CASTS(anv_common, VkImageMemoryBarrier) - -#ifdef __cplusplus -} -#endif diff --git a/src/vulkan/query.c b/src/vulkan/query.c deleted file mode 100644 index b3b85897814..00000000000 --- a/src/vulkan/query.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include "private.h" - -struct anv_query_pool_slot { - uint64_t begin; - uint64_t end; - uint64_t available; -}; - -struct anv_query_pool { - VkQueryType type; - uint32_t slots; - struct anv_bo bo; -}; - -VkResult anv_CreateQueryPool( - VkDevice _device, - const VkQueryPoolCreateInfo* pCreateInfo, - VkQueryPool* pQueryPool) -{ - ANV_FROM_HANDLE(anv_device, 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); - - 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 = anv_query_pool_to_handle(pool); - - return VK_SUCCESS; - - fail: - anv_device_free(device, pool); - - return result; -} - -VkResult anv_DestroyQueryPool( - VkDevice _device, - VkQueryPool _pool) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_query_pool, pool, _pool); - - 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; -} - -VkResult anv_GetQueryPoolResults( - VkDevice _device, - VkQueryPool queryPool, - uint32_t startQuery, - uint32_t queryCount, - size_t* pDataSize, - void* pData, - VkQueryResultFlags flags) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - ANV_FROM_HANDLE(anv_query_pool, 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; -} - -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) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_query_pool, 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) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_query_pool, 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) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_buffer, 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) -{ - ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer); - ANV_FROM_HANDLE(anv_query_pool, pool, queryPool); - ANV_FROM_HANDLE(anv_buffer, 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, - .StallAtPixelScoreboard = 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; - } -} diff --git a/src/vulkan/util.c b/src/vulkan/util.c deleted file mode 100644 index 21cb6484670..00000000000 --- a/src/vulkan/util.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#include "private.h" - -/** Log an error message. */ -void anv_printflike(1, 2) -anv_loge(const char *format, ...) -{ - va_list va; - - va_start(va, format); - anv_loge_v(format, va); - va_end(va); -} - -/** \see anv_loge() */ -void -anv_loge_v(const char *format, va_list va) -{ - fprintf(stderr, "vk: error: "); - vfprintf(stderr, format, va); - fprintf(stderr, "\n"); -} - -void anv_printflike(3, 4) -__anv_finishme(const char *file, int line, const char *format, ...) -{ - va_list ap; - char buffer[256]; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buffer); -} - -void anv_noreturn anv_printflike(1, 2) -anv_abortf(const char *format, ...) -{ - va_list va; - - va_start(va, format); - anv_abortfv(format, va); - va_end(va); -} - -void anv_noreturn -anv_abortfv(const char *format, va_list va) -{ - fprintf(stderr, "vk: error: "); - vfprintf(stderr, format, va); - fprintf(stderr, "\n"); - abort(); -} - -int -anv_vector_init(struct anv_vector *vector, uint32_t element_size, uint32_t size) -{ - assert(is_power_of_two(size)); - assert(element_size < size && is_power_of_two(element_size)); - - vector->head = 0; - vector->tail = 0; - vector->element_size = element_size; - vector->size = size; - vector->data = malloc(size); - - return vector->data != NULL; -} - -void * -anv_vector_add(struct anv_vector *vector) -{ - uint32_t offset, size, split, tail; - void *data; - - if (vector->head - vector->tail == vector->size) { - size = vector->size * 2; - data = malloc(size); - if (data == NULL) - return NULL; - split = align_u32(vector->tail, vector->size); - tail = vector->tail & (vector->size - 1); - if (vector->head - split < vector->size) { - memcpy(data + tail, - vector->data + tail, - split - vector->tail); - memcpy(data + vector->size, - vector->data, vector->head - split); - } else { - memcpy(data + tail, - vector->data + tail, - vector->head - vector->tail); - } - free(vector->data); - vector->data = data; - vector->size = size; - } - - assert(vector->head - vector->tail < vector->size); - - offset = vector->head & (vector->size - 1); - vector->head += vector->element_size; - - return vector->data + offset; -} - -void * -anv_vector_remove(struct anv_vector *vector) -{ - uint32_t offset; - - if (vector->head == vector->tail) - return NULL; - - assert(vector->head - vector->tail <= vector->size); - - offset = vector->tail & (vector->size - 1); - vector->tail += vector->element_size; - - return vector->data + offset; -} diff --git a/src/vulkan/vk_gen.py b/src/vulkan/vk_gen.py deleted file mode 100644 index d481af74ef0..00000000000 --- a/src/vulkan/vk_gen.py +++ /dev/null @@ -1,269 +0,0 @@ -# coding=utf-8 -# -# 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. -# - -import fileinput, re, sys - -# Each function typedef in the vulkan.h header is all on one line and matches -# this regepx. We hope that won't change. - -p = re.compile('typedef ([^ ]*) *\(VKAPI \*PFN_vk([^(]*)\)(.*);') - -entrypoints = [] - -# We generate a static hash table for entry point lookup -# (vkGetProcAddress). We use a linear congruential generator for our hash -# function and a power-of-two size table. The prime numbers are determined -# experimentally. - -none = 0xffff -hash_size = 256 -u32_mask = 2**32 - 1 -hash_mask = hash_size - 1 - -prime_factor = 5024183 -prime_step = 19 - -def hash(name): - h = 0; - for c in name: - h = (h * prime_factor + ord(c)) & u32_mask - - return h - -opt_header = False -opt_code = False - -if (sys.argv[1] == "header"): - opt_header = True - sys.argv.pop() -elif (sys.argv[1] == "code"): - opt_code = True - sys.argv.pop() - -# Parse the entry points in the header - -i = 0 -for line in fileinput.input(): - m = p.match(line) - if (m): - if m.group(2) == 'VoidFunction': - continue - fullname = "vk" + m.group(2) - h = hash(fullname) - entrypoints.append((m.group(1), m.group(2), m.group(3), i, h)) - i = i + 1 - -# For outputting entrypoints.h we generate a anv_EntryPoint() prototype -# per entry point. - -if opt_header: - for type, name, args, num, h in entrypoints: - print "%s anv_%s%s;" % (type, name, args) - print "%s anv_validate_%s%s;" % (type, name, args) - exit() - - - -print """/* - * 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. - */ - -/* This file generated from vk_gen.py, don't edit directly. */ - -#include "private.h" - -struct anv_entrypoint { - uint32_t name; - uint32_t hash; - void *function; - void *validate; -}; - -/* We use a big string constant to avoid lots of reloctions from the entry - * point table to lots of little strings. The entries in the entry point table - * store the index into this big string. - */ - -static const char strings[] =""" - -offsets = [] -i = 0; -for type, name, args, num, h in entrypoints: - print " \"vk%s\\0\"" % name - offsets.append(i) - i += 2 + len(name) + 1 -print """ ; - -/* Weak aliases for all potential validate functions. These will resolve to - * NULL if they're not defined, which lets the resolve_entrypoint() function - * either pick a validate wrapper if available or just plug in the actual - * entry point. - */ -""" - -for type, name, args, num, h in entrypoints: - print "%s anv_validate_%s%s __attribute__ ((weak));" % (type, name, args) - -# Now generate the table of all entry points and their validation functions - -print "\nstatic const struct anv_entrypoint entrypoints[] = {" -for type, name, args, num, h in entrypoints: - print " { %5d, 0x%08x, anv_%s, anv_validate_%s }," % (offsets[num], h, name, name) -print "};\n" - -print """ -#ifdef DEBUG -static bool enable_validate = true; -#else -static bool enable_validate = false; -#endif - -/* We can't use symbols that need resolving (like, oh, getenv) in the resolve - * function. This means that we have to determine whether or not to use the - * validation layer sometime before that. The constructor function attribute asks - * the dynamic linker to invoke determine_validate() at dlopen() time which - * works. - */ -static void __attribute__ ((constructor)) -determine_validate(void) -{ - const char *s = getenv("ANV_VALIDATE"); - - if (s) - enable_validate = atoi(s); -} - -static void * __attribute__ ((noinline)) -resolve_entrypoint(uint32_t index) -{ - if (enable_validate && entrypoints[index].validate) - return entrypoints[index].validate; - - return entrypoints[index].function; -} -""" - -# Now output ifuncs and their resolve helpers for all entry points. The -# resolve helper calls resolve_entrypoint() with the entry point index, which -# lets the resolver look it up in the table. - -for type, name, args, num, h in entrypoints: - print "static void *resolve_%s(void) { return resolve_entrypoint(%d); }" % (name, num) - print "%s vk%s%s\n __attribute__ ((ifunc (\"resolve_%s\"), visibility (\"default\")));\n" % (type, name, args, name) - - -# Now generate the hash table used for entry point look up. This is a -# uint16_t table of entry point indices. We use 0xffff to indicate an entry -# in the hash table is empty. - -map = [none for f in xrange(hash_size)] -collisions = [0 for f in xrange(10)] -for type, name, args, num, h in entrypoints: - level = 0 - while map[h & hash_mask] != none: - h = h + prime_step - level = level + 1 - if level > 9: - collisions[9] += 1 - else: - collisions[level] += 1 - map[h & hash_mask] = num - -print "/* Hash table stats:" -print " * size %d entries" % hash_size -print " * collisions entries" -for i in xrange(10): - if (i == 9): - plus = "+" - else: - plus = " " - - print " * %2d%s %4d" % (i, plus, collisions[i]) -print " */\n" - -print "#define none 0x%04x\n" % none - -print "static const uint16_t map[] = {" -for i in xrange(0, hash_size, 8): - print " ", - for j in xrange(i, i + 8): - if map[j] & 0xffff == 0xffff: - print " none,", - else: - print "0x%04x," % (map[j] & 0xffff), - print - -print "};" - -# Finally we generate the hash table lookup function. The hash function and -# linear probing algorithm matches the hash table generated above. - -print """ -void * -anv_lookup_entrypoint(const char *name) -{ - static const uint32_t prime_factor = %d; - static const uint32_t prime_step = %d; - const struct anv_entrypoint *e; - uint32_t hash, h, i; - const char *p; - - hash = 0; - for (p = name; *p; p++) - hash = hash * prime_factor + *p; - - h = hash; - do { - i = map[h & %d]; - if (i == none) - return NULL; - e = &entrypoints[i]; - h += prime_step; - } while (e->hash != hash); - - if (strcmp(name, strings + e->name) != 0) - return NULL; - - return resolve_entrypoint(i); -} -""" % (prime_factor, prime_step, hash_mask) diff --git a/src/vulkan/x11.c b/src/vulkan/x11.c deleted file mode 100644 index 1e0bdb12bd0..00000000000 --- a/src/vulkan/x11.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 "private.h" - -#include -#include -#include - -static const VkFormat formats[] = { - VK_FORMAT_B5G6R5_UNORM, - VK_FORMAT_B8G8R8A8_UNORM, - VK_FORMAT_B8G8R8A8_SRGB, -}; - -VkResult anv_GetDisplayInfoWSI( - VkDisplayWSI display, - VkDisplayInfoTypeWSI infoType, - size_t* pDataSize, - void* pData) -{ - VkDisplayFormatPropertiesWSI *properties = pData; - size_t size; - - if (pDataSize == NULL) - return VK_ERROR_INVALID_POINTER; - - switch (infoType) { - case VK_DISPLAY_INFO_TYPE_FORMAT_PROPERTIES_WSI: - size = sizeof(properties[0]) * ARRAY_SIZE(formats); - - if (pData == NULL) { - *pDataSize = size; - return VK_SUCCESS; - } - - if (*pDataSize < size) - return vk_error(VK_ERROR_INVALID_VALUE); - - *pDataSize = size; - - for (uint32_t i = 0; i < ARRAY_SIZE(formats); i++) - properties[i].swapChainFormat = formats[i]; - - return VK_SUCCESS; - - default: - return VK_UNSUPPORTED; - } -} - -struct anv_swap_chain { - struct anv_device * device; - xcb_connection_t * conn; - xcb_window_t window; - xcb_gc_t gc; - VkExtent2D extent; - uint32_t count; - struct { - struct anv_image * image; - struct anv_device_memory * memory; - xcb_pixmap_t pixmap; - } images[0]; -}; - -VkResult anv_CreateSwapChainWSI( - VkDevice _device, - const VkSwapChainCreateInfoWSI* pCreateInfo, - VkSwapChainWSI* pSwapChain) -{ - ANV_FROM_HANDLE(anv_device, device, _device); - - struct anv_swap_chain *chain; - xcb_void_cookie_t cookie; - VkResult result; - size_t size; - int ret; - - assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI); - - size = sizeof(*chain) + pCreateInfo->imageCount * sizeof(chain->images[0]); - chain = anv_device_alloc(device, size, 8, - VK_SYSTEM_ALLOC_TYPE_API_OBJECT); - if (chain == NULL) - return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); - - chain->device = device; - chain->conn = (xcb_connection_t *) pCreateInfo->pNativeWindowSystemHandle; - chain->window = (xcb_window_t) (uintptr_t) pCreateInfo->pNativeWindowHandle; - chain->count = pCreateInfo->imageCount; - chain->extent = pCreateInfo->imageExtent; - - for (uint32_t i = 0; i < chain->count; i++) { - VkDeviceMemory memory_h; - VkImage image_h; - struct anv_image *image; - struct anv_surface *surface; - struct anv_device_memory *memory; - - anv_image_create(_device, - &(struct anv_image_create_info) { - .force_tile_mode = true, - .tile_mode = XMAJOR, - .vk_info = - &(VkImageCreateInfo) { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1 - }, - .mipLevels = 1, - .arraySize = 1, - .samples = 1, - /* FIXME: Need a way to use X tiling to allow scanout */ - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .flags = 0, - }}, - &image_h); - - image = anv_image_from_handle(image_h); - surface = &image->primary_surface; - - anv_AllocMemory(_device, - &(VkMemoryAllocInfo) { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, - .allocationSize = image->size, - .memoryTypeIndex = 0, - }, - &memory_h); - - memory = anv_device_memory_from_handle(memory_h); - - anv_BindImageMemory(VK_NULL_HANDLE, anv_image_to_handle(image), - memory_h, 0); - - ret = anv_gem_set_tiling(device, memory->bo.gem_handle, - surface->stride, I915_TILING_X); - if (ret) { - result = vk_error(VK_ERROR_UNKNOWN); - goto fail; - } - - int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle); - if (fd == -1) { - result = vk_error(VK_ERROR_UNKNOWN); - goto fail; - } - - uint32_t bpp = 32; - uint32_t depth = 24; - xcb_pixmap_t pixmap = xcb_generate_id(chain->conn); - - cookie = - xcb_dri3_pixmap_from_buffer_checked(chain->conn, - pixmap, - chain->window, - image->size, - pCreateInfo->imageExtent.width, - pCreateInfo->imageExtent.height, - surface->stride, - depth, bpp, fd); - - chain->images[i].image = image; - chain->images[i].memory = memory; - chain->images[i].pixmap = pixmap; - image->swap_chain = chain; - - xcb_discard_reply(chain->conn, cookie.sequence); - } - - chain->gc = xcb_generate_id(chain->conn); - if (!chain->gc) { - result = vk_error(VK_ERROR_UNKNOWN); - goto fail; - } - - cookie = xcb_create_gc(chain->conn, - chain->gc, - chain->window, - XCB_GC_GRAPHICS_EXPOSURES, - (uint32_t []) { 0 }); - xcb_discard_reply(chain->conn, cookie.sequence); - - *pSwapChain = anv_swap_chain_to_handle(chain); - - return VK_SUCCESS; - - fail: - return result; -} - -VkResult anv_DestroySwapChainWSI( - VkSwapChainWSI _chain) -{ - ANV_FROM_HANDLE(anv_swap_chain, chain, _chain); - - anv_device_free(chain->device, chain); - - return VK_SUCCESS; -} - -VkResult anv_GetSwapChainInfoWSI( - VkSwapChainWSI _chain, - VkSwapChainInfoTypeWSI infoType, - size_t* pDataSize, - void* pData) -{ - ANV_FROM_HANDLE(anv_swap_chain, chain, _chain); - - VkSwapChainImageInfoWSI *images; - size_t size; - - switch (infoType) { - case VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI: - size = sizeof(*images) * chain->count; - if (pData && *pDataSize < size) - return VK_ERROR_INVALID_VALUE; - - *pDataSize = size; - if (!pData) - return VK_SUCCESS; - - images = pData; - for (uint32_t i = 0; i < chain->count; i++) { - images[i].image = anv_image_to_handle(chain->images[i].image); - images[i].memory = anv_device_memory_to_handle(chain->images[i].memory); - } - - return VK_SUCCESS; - - default: - return VK_UNSUPPORTED; - } -} - -VkResult anv_QueuePresentWSI( - VkQueue queue_, - const VkPresentInfoWSI* pPresentInfo) -{ - ANV_FROM_HANDLE(anv_image, image, pPresentInfo->image); - - struct anv_swap_chain *chain = image->swap_chain; - xcb_void_cookie_t cookie; - xcb_pixmap_t pixmap; - - assert(pPresentInfo->sType == VK_STRUCTURE_TYPE_PRESENT_INFO_WSI); - - if (chain == NULL) - return vk_error(VK_ERROR_INVALID_VALUE); - - pixmap = XCB_NONE; - for (uint32_t i = 0; i < chain->count; i++) { - if (image == chain->images[i].image) { - pixmap = chain->images[i].pixmap; - break; - } - } - - if (pixmap == XCB_NONE) - return vk_error(VK_ERROR_INVALID_VALUE); - - cookie = xcb_copy_area(chain->conn, - pixmap, - chain->window, - chain->gc, - 0, 0, - 0, 0, - chain->extent.width, - chain->extent.height); - xcb_discard_reply(chain->conn, cookie.sequence); - - xcb_flush(chain->conn); - - return VK_SUCCESS; -} -- cgit v1.2.3