1/*
2 * Copyright (c) 2015-2016 The Khronos Group Inc.
3 * Copyright (c) 2015-2016 Valve Corporation
4 * Copyright (c) 2015-2016 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and/or associated documentation files (the "Materials"), to
8 * deal in the Materials without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Materials, and to permit persons to whom the Materials are
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice(s) and this permission notice shall be included in
14 * all copies or substantial portions of the Materials.
15 *
16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 *
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23 * USE OR OTHER DEALINGS IN THE MATERIALS.
24 *
25 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
26 * Author: Tony Barbour <tony@LunarG.com>
27 */
28
29#include <iostream>
30#include <string.h> // memset(), memcmp()
31#include <assert.h>
32#include <stdarg.h>
33#include "vktestbinding.h"
34
35namespace {
36
37#define NON_DISPATCHABLE_HANDLE_INIT(create_func, dev, ...)                    \
38    do {                                                                       \
39        handle_type handle;                                                    \
40        if (EXPECT(create_func(dev.handle(), __VA_ARGS__, NULL, &handle) ==    \
41                   VK_SUCCESS))                                                \
42            NonDispHandle::init(dev.handle(), handle);                         \
43    } while (0)
44
45#define NON_DISPATCHABLE_HANDLE_DTOR(cls, destroy_func)                        \
46    cls::~cls() {                                                              \
47        if (initialized())                                                     \
48            destroy_func(device(), handle(), NULL);                            \
49    }
50
51#define STRINGIFY(x) #x
52#define EXPECT(expr)                                                           \
53    ((expr) ? true : expect_failure(STRINGIFY(expr), __FILE__, __LINE__,       \
54                                    __FUNCTION__))
55
56vk_testing::ErrorCallback error_callback;
57
58bool expect_failure(const char *expr, const char *file, unsigned int line,
59                    const char *function) {
60    if (error_callback) {
61        error_callback(expr, file, line, function);
62    } else {
63        std::cerr << file << ":" << line << ": " << function
64                  << ": Expectation `" << expr << "' failed.\n";
65    }
66
67    return false;
68}
69
70template <class T, class S>
71std::vector<T> make_handles(const std::vector<S> &v) {
72    std::vector<T> handles;
73    handles.reserve(v.size());
74    for (typename std::vector<S>::const_iterator it = v.begin(); it != v.end();
75         it++)
76        handles.push_back((*it)->handle());
77    return handles;
78}
79
80VkMemoryAllocateInfo get_resource_alloc_info(const vk_testing::Device &dev,
81                                             const VkMemoryRequirements &reqs,
82                                             VkMemoryPropertyFlags mem_props) {
83    VkMemoryAllocateInfo info =
84        vk_testing::DeviceMemory::alloc_info(reqs.size, 0);
85    dev.phy().set_memory_type(reqs.memoryTypeBits, &info, mem_props);
86
87    return info;
88}
89
90} // namespace
91
92namespace vk_testing {
93
94void set_error_callback(ErrorCallback callback) { error_callback = callback; }
95
96VkPhysicalDeviceProperties PhysicalDevice::properties() const {
97    VkPhysicalDeviceProperties info;
98
99    vkGetPhysicalDeviceProperties(handle(), &info);
100
101    return info;
102}
103
104std::vector<VkQueueFamilyProperties> PhysicalDevice::queue_properties() const {
105    std::vector<VkQueueFamilyProperties> info;
106    uint32_t count;
107
108    // Call once with NULL data to receive count
109    vkGetPhysicalDeviceQueueFamilyProperties(handle(), &count, NULL);
110    info.resize(count);
111    vkGetPhysicalDeviceQueueFamilyProperties(handle(), &count, info.data());
112
113    return info;
114}
115
116VkPhysicalDeviceMemoryProperties PhysicalDevice::memory_properties() const {
117    VkPhysicalDeviceMemoryProperties info;
118
119    vkGetPhysicalDeviceMemoryProperties(handle(), &info);
120
121    return info;
122}
123
124/*
125 * Return list of Global layers available
126 */
127std::vector<VkLayerProperties> GetGlobalLayers() {
128    VkResult err;
129    std::vector<VkLayerProperties> layers;
130    uint32_t layer_count;
131
132    do {
133        layer_count = 0;
134        err = vkEnumerateInstanceLayerProperties(&layer_count, NULL);
135
136        if (err == VK_SUCCESS) {
137            layers.reserve(layer_count);
138            err =
139                vkEnumerateInstanceLayerProperties(&layer_count, layers.data());
140        }
141    } while (err == VK_INCOMPLETE);
142
143    assert(err == VK_SUCCESS);
144
145    return layers;
146}
147
148/*
149 * Return list of Global extensions provided by the ICD / Loader
150 */
151std::vector<VkExtensionProperties> GetGlobalExtensions() {
152    return GetGlobalExtensions(NULL);
153}
154
155/*
156 * Return list of Global extensions provided by the specified layer
157 * If pLayerName is NULL, will return extensions implemented by the loader /
158 * ICDs
159 */
160std::vector<VkExtensionProperties> GetGlobalExtensions(const char *pLayerName) {
161    std::vector<VkExtensionProperties> exts;
162    uint32_t ext_count;
163    VkResult err;
164
165    do {
166        ext_count = 0;
167        err = vkEnumerateInstanceExtensionProperties(pLayerName, &ext_count,
168                                                     NULL);
169
170        if (err == VK_SUCCESS) {
171            exts.resize(ext_count);
172            err = vkEnumerateInstanceExtensionProperties(pLayerName, &ext_count,
173                                                         exts.data());
174        }
175    } while (err == VK_INCOMPLETE);
176
177    assert(err == VK_SUCCESS);
178
179    return exts;
180}
181
182/*
183 * Return list of PhysicalDevice extensions provided by the ICD / Loader
184 */
185std::vector<VkExtensionProperties> PhysicalDevice::extensions() const {
186    return extensions(NULL);
187}
188
189/*
190 * Return list of PhysicalDevice extensions provided by the specified layer
191 * If pLayerName is NULL, will return extensions for ICD / loader.
192 */
193std::vector<VkExtensionProperties>
194PhysicalDevice::extensions(const char *pLayerName) const {
195    std::vector<VkExtensionProperties> exts;
196    VkResult err;
197
198    do {
199        uint32_t extCount = 0;
200        err = vkEnumerateDeviceExtensionProperties(handle(), pLayerName,
201                                                   &extCount, NULL);
202
203        if (err == VK_SUCCESS) {
204            exts.resize(extCount);
205            err = vkEnumerateDeviceExtensionProperties(handle(), pLayerName,
206                                                       &extCount, exts.data());
207        }
208    } while (err == VK_INCOMPLETE);
209
210    assert(err == VK_SUCCESS);
211
212    return exts;
213}
214
215bool PhysicalDevice::set_memory_type(const uint32_t type_bits,
216                                     VkMemoryAllocateInfo *info,
217                                     const VkFlags properties,
218                                     const VkFlags forbid) const {
219    uint32_t type_mask = type_bits;
220    // Search memtypes to find first index with those properties
221    for (uint32_t i = 0; i < memory_properties_.memoryTypeCount; i++) {
222        if ((type_mask & 1) == 1) {
223            // Type is available, does it match user properties?
224            if ((memory_properties_.memoryTypes[i].propertyFlags &
225                 properties) == properties &&
226                (memory_properties_.memoryTypes[i].propertyFlags & forbid) ==
227                    0) {
228                info->memoryTypeIndex = i;
229                return true;
230            }
231        }
232        type_mask >>= 1;
233    }
234    // No memory types matched, return failure
235    return false;
236}
237
238/*
239 * Return list of PhysicalDevice layers
240 */
241std::vector<VkLayerProperties> PhysicalDevice::layers() const {
242    std::vector<VkLayerProperties> layer_props;
243    VkResult err;
244
245    do {
246        uint32_t layer_count = 0;
247        err = vkEnumerateDeviceLayerProperties(handle(), &layer_count, NULL);
248
249        if (err == VK_SUCCESS) {
250            layer_props.reserve(layer_count);
251            err = vkEnumerateDeviceLayerProperties(handle(), &layer_count,
252                                                   layer_props.data());
253        }
254    } while (err == VK_INCOMPLETE);
255
256    assert(err == VK_SUCCESS);
257
258    return layer_props;
259}
260
261Device::~Device() {
262    if (!initialized())
263        return;
264
265    for (int i = 0; i < QUEUE_COUNT; i++) {
266        for (std::vector<Queue *>::iterator it = queues_[i].begin();
267             it != queues_[i].end(); it++)
268            delete *it;
269        queues_[i].clear();
270    }
271
272    vkDestroyDevice(handle(), NULL);
273}
274
275void Device::init(std::vector<const char *> &layers,
276                  std::vector<const char *> &extensions) {
277    // request all queues
278    const std::vector<VkQueueFamilyProperties> queue_props =
279        phy_.queue_properties();
280    std::vector<VkDeviceQueueCreateInfo> queue_info;
281    queue_info.reserve(queue_props.size());
282
283    std::vector<std::vector<float>> queue_priorities;
284
285    for (uint32_t i = 0; i < (uint32_t)queue_props.size(); i++) {
286        VkDeviceQueueCreateInfo qi = {};
287        qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
288        qi.pNext = NULL;
289        qi.queueFamilyIndex = i;
290        qi.queueCount = queue_props[i].queueCount;
291
292        queue_priorities.emplace_back(qi.queueCount, 0.0);
293
294        qi.pQueuePriorities = queue_priorities[i].data();
295        if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
296            graphics_queue_node_index_ = i;
297        }
298        queue_info.push_back(qi);
299    }
300
301    VkDeviceCreateInfo dev_info = {};
302    dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
303    dev_info.pNext = NULL;
304    dev_info.queueCreateInfoCount = queue_info.size();
305    dev_info.pQueueCreateInfos = queue_info.data();
306    dev_info.enabledLayerCount = layers.size();
307    dev_info.ppEnabledLayerNames = layers.data();
308    dev_info.enabledExtensionCount = extensions.size();
309    dev_info.ppEnabledExtensionNames = extensions.data();
310
311    init(dev_info);
312}
313
314void Device::init(const VkDeviceCreateInfo &info) {
315    VkDevice dev;
316
317    if (EXPECT(vkCreateDevice(phy_.handle(), &info, NULL, &dev) == VK_SUCCESS))
318        Handle::init(dev);
319
320    init_queues();
321    init_formats();
322}
323
324void Device::init_queues() {
325    uint32_t queue_node_count;
326
327    // Call with NULL data to get count
328    vkGetPhysicalDeviceQueueFamilyProperties(phy_.handle(), &queue_node_count,
329                                             NULL);
330    EXPECT(queue_node_count >= 1);
331
332    VkQueueFamilyProperties *queue_props =
333        new VkQueueFamilyProperties[queue_node_count];
334
335    vkGetPhysicalDeviceQueueFamilyProperties(phy_.handle(), &queue_node_count,
336                                             queue_props);
337
338    for (uint32_t i = 0; i < queue_node_count; i++) {
339        VkQueue queue;
340
341        for (uint32_t j = 0; j < queue_props[i].queueCount; j++) {
342            // TODO: Need to add support for separate MEMMGR and work queues,
343            // including synchronization
344            vkGetDeviceQueue(handle(), i, j, &queue);
345
346            if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
347                queues_[GRAPHICS].push_back(new Queue(queue, i));
348            }
349
350            if (queue_props[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
351                queues_[COMPUTE].push_back(new Queue(queue, i));
352            }
353
354            if (queue_props[i].queueFlags & VK_QUEUE_TRANSFER_BIT) {
355                queues_[DMA].push_back(new Queue(queue, i));
356            }
357        }
358    }
359
360    delete[] queue_props;
361
362    EXPECT(!queues_[GRAPHICS].empty() || !queues_[COMPUTE].empty());
363}
364
365void Device::init_formats() {
366    for (int f = VK_FORMAT_BEGIN_RANGE; f <= VK_FORMAT_END_RANGE; f++) {
367        const VkFormat fmt = static_cast<VkFormat>(f);
368        const VkFormatProperties props = format_properties(fmt);
369
370        if (props.linearTilingFeatures) {
371            const Format tmp = {fmt, VK_IMAGE_TILING_LINEAR,
372                                props.linearTilingFeatures};
373            formats_.push_back(tmp);
374        }
375
376        if (props.optimalTilingFeatures) {
377            const Format tmp = {fmt, VK_IMAGE_TILING_OPTIMAL,
378                                props.optimalTilingFeatures};
379            formats_.push_back(tmp);
380        }
381    }
382
383    EXPECT(!formats_.empty());
384}
385
386VkFormatProperties Device::format_properties(VkFormat format) {
387    VkFormatProperties data;
388    vkGetPhysicalDeviceFormatProperties(phy().handle(), format, &data);
389
390    return data;
391}
392
393void Device::wait() { EXPECT(vkDeviceWaitIdle(handle()) == VK_SUCCESS); }
394
395VkResult Device::wait(const std::vector<const Fence *> &fences, bool wait_all,
396                      uint64_t timeout) {
397    const std::vector<VkFence> fence_handles = make_handles<VkFence>(fences);
398    VkResult err = vkWaitForFences(handle(), fence_handles.size(),
399                                   fence_handles.data(), wait_all, timeout);
400    EXPECT(err == VK_SUCCESS || err == VK_TIMEOUT);
401
402    return err;
403}
404
405void Device::update_descriptor_sets(
406    const std::vector<VkWriteDescriptorSet> &writes,
407    const std::vector<VkCopyDescriptorSet> &copies) {
408    vkUpdateDescriptorSets(handle(), writes.size(), writes.data(),
409                           copies.size(), copies.data());
410}
411
412void Queue::submit(const std::vector<const CommandBuffer *> &cmds,
413                   Fence &fence) {
414    const std::vector<VkCommandBuffer> cmd_handles =
415        make_handles<VkCommandBuffer>(cmds);
416    VkSubmitInfo submit_info;
417    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
418    submit_info.pNext = NULL;
419    submit_info.waitSemaphoreCount = 0;
420    submit_info.pWaitSemaphores = NULL;
421    submit_info.pWaitDstStageMask = NULL;
422    submit_info.commandBufferCount = (uint32_t)cmd_handles.size();
423    submit_info.pCommandBuffers = cmd_handles.data();
424    submit_info.signalSemaphoreCount = 0;
425    submit_info.pSignalSemaphores = NULL;
426
427    EXPECT(vkQueueSubmit(handle(), 1, &submit_info, fence.handle()) ==
428           VK_SUCCESS);
429}
430
431void Queue::submit(const CommandBuffer &cmd, Fence &fence) {
432    submit(std::vector<const CommandBuffer *>(1, &cmd), fence);
433}
434
435void Queue::submit(const CommandBuffer &cmd) {
436    Fence fence;
437    submit(cmd, fence);
438}
439
440void Queue::wait() { EXPECT(vkQueueWaitIdle(handle()) == VK_SUCCESS); }
441
442DeviceMemory::~DeviceMemory() {
443    if (initialized())
444        vkFreeMemory(device(), handle(), NULL);
445}
446
447void DeviceMemory::init(const Device &dev, const VkMemoryAllocateInfo &info) {
448    NON_DISPATCHABLE_HANDLE_INIT(vkAllocateMemory, dev, &info);
449}
450
451const void *DeviceMemory::map(VkFlags flags) const {
452    void *data;
453    if (!EXPECT(vkMapMemory(device(), handle(), 0, VK_WHOLE_SIZE, flags,
454                            &data) == VK_SUCCESS))
455        data = NULL;
456
457    return data;
458}
459
460void *DeviceMemory::map(VkFlags flags) {
461    void *data;
462    if (!EXPECT(vkMapMemory(device(), handle(), 0, VK_WHOLE_SIZE, flags,
463                            &data) == VK_SUCCESS))
464        data = NULL;
465
466    return data;
467}
468
469void DeviceMemory::unmap() const { vkUnmapMemory(device(), handle()); }
470
471NON_DISPATCHABLE_HANDLE_DTOR(Fence, vkDestroyFence)
472
473void Fence::init(const Device &dev, const VkFenceCreateInfo &info) {
474    NON_DISPATCHABLE_HANDLE_INIT(vkCreateFence, dev, &info);
475}
476
477NON_DISPATCHABLE_HANDLE_DTOR(Semaphore, vkDestroySemaphore)
478
479void Semaphore::init(const Device &dev, const VkSemaphoreCreateInfo &info) {
480    NON_DISPATCHABLE_HANDLE_INIT(vkCreateSemaphore, dev, &info);
481}
482
483NON_DISPATCHABLE_HANDLE_DTOR(Event, vkDestroyEvent)
484
485void Event::init(const Device &dev, const VkEventCreateInfo &info) {
486    NON_DISPATCHABLE_HANDLE_INIT(vkCreateEvent, dev, &info);
487}
488
489void Event::set() { EXPECT(vkSetEvent(device(), handle()) == VK_SUCCESS); }
490
491void Event::reset() { EXPECT(vkResetEvent(device(), handle()) == VK_SUCCESS); }
492
493NON_DISPATCHABLE_HANDLE_DTOR(QueryPool, vkDestroyQueryPool)
494
495void QueryPool::init(const Device &dev, const VkQueryPoolCreateInfo &info) {
496    NON_DISPATCHABLE_HANDLE_INIT(vkCreateQueryPool, dev, &info);
497}
498
499VkResult QueryPool::results(uint32_t first, uint32_t count, size_t size,
500                            void *data, size_t stride) {
501    VkResult err = vkGetQueryPoolResults(device(), handle(), first, count, size,
502                                         data, stride, 0);
503    EXPECT(err == VK_SUCCESS || err == VK_NOT_READY);
504
505    return err;
506}
507
508NON_DISPATCHABLE_HANDLE_DTOR(Buffer, vkDestroyBuffer)
509
510void Buffer::init(const Device &dev, const VkBufferCreateInfo &info,
511                  VkMemoryPropertyFlags mem_props) {
512    init_no_mem(dev, info);
513
514    internal_mem_.init(
515        dev, get_resource_alloc_info(dev, memory_requirements(), mem_props));
516    bind_memory(internal_mem_, 0);
517}
518
519void Buffer::init_no_mem(const Device &dev, const VkBufferCreateInfo &info) {
520    NON_DISPATCHABLE_HANDLE_INIT(vkCreateBuffer, dev, &info);
521    create_info_ = info;
522}
523
524VkMemoryRequirements Buffer::memory_requirements() const {
525    VkMemoryRequirements reqs;
526
527    vkGetBufferMemoryRequirements(device(), handle(), &reqs);
528
529    return reqs;
530}
531
532void Buffer::bind_memory(const DeviceMemory &mem, VkDeviceSize mem_offset) {
533    EXPECT(vkBindBufferMemory(device(), handle(), mem.handle(), mem_offset) ==
534           VK_SUCCESS);
535}
536
537NON_DISPATCHABLE_HANDLE_DTOR(BufferView, vkDestroyBufferView)
538
539void BufferView::init(const Device &dev, const VkBufferViewCreateInfo &info) {
540    NON_DISPATCHABLE_HANDLE_INIT(vkCreateBufferView, dev, &info);
541}
542
543NON_DISPATCHABLE_HANDLE_DTOR(Image, vkDestroyImage)
544
545void Image::init(const Device &dev, const VkImageCreateInfo &info,
546                 VkMemoryPropertyFlags mem_props) {
547    init_no_mem(dev, info);
548
549    internal_mem_.init(
550        dev, get_resource_alloc_info(dev, memory_requirements(), mem_props));
551    bind_memory(internal_mem_, 0);
552}
553
554void Image::init_no_mem(const Device &dev, const VkImageCreateInfo &info) {
555    NON_DISPATCHABLE_HANDLE_INIT(vkCreateImage, dev, &info);
556    init_info(dev, info);
557}
558
559void Image::init_info(const Device &dev, const VkImageCreateInfo &info) {
560    create_info_ = info;
561
562    for (std::vector<Device::Format>::const_iterator it = dev.formats().begin();
563         it != dev.formats().end(); it++) {
564        if (memcmp(&it->format, &create_info_.format, sizeof(it->format)) ==
565                0 &&
566            it->tiling == create_info_.tiling) {
567            format_features_ = it->features;
568            break;
569        }
570    }
571}
572
573VkMemoryRequirements Image::memory_requirements() const {
574    VkMemoryRequirements reqs;
575
576    vkGetImageMemoryRequirements(device(), handle(), &reqs);
577
578    return reqs;
579}
580
581void Image::bind_memory(const DeviceMemory &mem, VkDeviceSize mem_offset) {
582    EXPECT(vkBindImageMemory(device(), handle(), mem.handle(), mem_offset) ==
583           VK_SUCCESS);
584}
585
586VkSubresourceLayout
587Image::subresource_layout(const VkImageSubresource &subres) const {
588    VkSubresourceLayout data;
589    size_t size = sizeof(data);
590    vkGetImageSubresourceLayout(device(), handle(), &subres, &data);
591    if (size != sizeof(data))
592        memset(&data, 0, sizeof(data));
593
594    return data;
595}
596
597VkSubresourceLayout
598Image::subresource_layout(const VkImageSubresourceLayers &subrescopy) const {
599    VkSubresourceLayout data;
600    VkImageSubresource subres =
601        subresource(image_aspect(subrescopy.aspectMask), subrescopy.mipLevel,
602                    subrescopy.baseArrayLayer);
603    size_t size = sizeof(data);
604    vkGetImageSubresourceLayout(device(), handle(), &subres, &data);
605    if (size != sizeof(data))
606        memset(&data, 0, sizeof(data));
607
608    return data;
609}
610
611bool Image::transparent() const {
612    return (
613        create_info_.tiling == VK_IMAGE_TILING_LINEAR &&
614        create_info_.samples == VK_SAMPLE_COUNT_1_BIT &&
615        !(create_info_.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
616                                VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)));
617}
618
619NON_DISPATCHABLE_HANDLE_DTOR(ImageView, vkDestroyImageView)
620
621void ImageView::init(const Device &dev, const VkImageViewCreateInfo &info) {
622    NON_DISPATCHABLE_HANDLE_INIT(vkCreateImageView, dev, &info);
623}
624
625NON_DISPATCHABLE_HANDLE_DTOR(ShaderModule, vkDestroyShaderModule)
626
627void ShaderModule::init(const Device &dev,
628                        const VkShaderModuleCreateInfo &info) {
629    NON_DISPATCHABLE_HANDLE_INIT(vkCreateShaderModule, dev, &info);
630}
631
632VkResult ShaderModule::init_try(const Device &dev,
633                                const VkShaderModuleCreateInfo &info) {
634    VkShaderModule mod;
635
636    VkResult err = vkCreateShaderModule(dev.handle(), &info, NULL, &mod);
637    if (err == VK_SUCCESS)
638        NonDispHandle::init(dev.handle(), mod);
639
640    return err;
641}
642
643NON_DISPATCHABLE_HANDLE_DTOR(Pipeline, vkDestroyPipeline)
644
645void Pipeline::init(const Device &dev,
646                    const VkGraphicsPipelineCreateInfo &info) {
647    VkPipelineCache cache;
648    VkPipelineCacheCreateInfo ci;
649    memset((void *)&ci, 0, sizeof(VkPipelineCacheCreateInfo));
650    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
651    VkResult err = vkCreatePipelineCache(dev.handle(), &ci, NULL, &cache);
652    if (err == VK_SUCCESS) {
653        NON_DISPATCHABLE_HANDLE_INIT(vkCreateGraphicsPipelines, dev, cache, 1,
654                                     &info);
655        vkDestroyPipelineCache(dev.handle(), cache, NULL);
656    }
657}
658
659VkResult Pipeline::init_try(const Device &dev,
660                            const VkGraphicsPipelineCreateInfo &info) {
661    VkPipeline pipe;
662    VkPipelineCache cache;
663    VkPipelineCacheCreateInfo ci;
664    memset((void *)&ci, 0, sizeof(VkPipelineCacheCreateInfo));
665    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
666    VkResult err = vkCreatePipelineCache(dev.handle(), &ci, NULL, &cache);
667    EXPECT(err == VK_SUCCESS);
668    if (err == VK_SUCCESS) {
669        err = vkCreateGraphicsPipelines(dev.handle(), cache, 1, &info, NULL,
670                                        &pipe);
671        if (err == VK_SUCCESS) {
672            NonDispHandle::init(dev.handle(), pipe);
673        }
674        vkDestroyPipelineCache(dev.handle(), cache, NULL);
675    }
676
677    return err;
678}
679
680void Pipeline::init(const Device &dev,
681                    const VkComputePipelineCreateInfo &info) {
682    VkPipelineCache cache;
683    VkPipelineCacheCreateInfo ci;
684    memset((void *)&ci, 0, sizeof(VkPipelineCacheCreateInfo));
685    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
686    VkResult err = vkCreatePipelineCache(dev.handle(), &ci, NULL, &cache);
687    if (err == VK_SUCCESS) {
688        NON_DISPATCHABLE_HANDLE_INIT(vkCreateComputePipelines, dev, cache, 1,
689                                     &info);
690        vkDestroyPipelineCache(dev.handle(), cache, NULL);
691    }
692}
693
694NON_DISPATCHABLE_HANDLE_DTOR(PipelineLayout, vkDestroyPipelineLayout)
695
696void PipelineLayout::init(
697    const Device &dev, VkPipelineLayoutCreateInfo &info,
698    const std::vector<const DescriptorSetLayout *> &layouts) {
699    const std::vector<VkDescriptorSetLayout> layout_handles =
700        make_handles<VkDescriptorSetLayout>(layouts);
701    info.pSetLayouts = layout_handles.data();
702
703    NON_DISPATCHABLE_HANDLE_INIT(vkCreatePipelineLayout, dev, &info);
704}
705
706NON_DISPATCHABLE_HANDLE_DTOR(Sampler, vkDestroySampler)
707
708void Sampler::init(const Device &dev, const VkSamplerCreateInfo &info) {
709    NON_DISPATCHABLE_HANDLE_INIT(vkCreateSampler, dev, &info);
710}
711
712NON_DISPATCHABLE_HANDLE_DTOR(DescriptorSetLayout, vkDestroyDescriptorSetLayout)
713
714void DescriptorSetLayout::init(const Device &dev,
715                               const VkDescriptorSetLayoutCreateInfo &info) {
716    NON_DISPATCHABLE_HANDLE_INIT(vkCreateDescriptorSetLayout, dev, &info);
717}
718
719NON_DISPATCHABLE_HANDLE_DTOR(DescriptorPool, vkDestroyDescriptorPool)
720
721void DescriptorPool::init(const Device &dev,
722                          const VkDescriptorPoolCreateInfo &info) {
723    setDynamicUsage(info.flags &
724                    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT);
725    NON_DISPATCHABLE_HANDLE_INIT(vkCreateDescriptorPool, dev, &info);
726}
727
728void DescriptorPool::reset() {
729    EXPECT(vkResetDescriptorPool(device(), handle(), 0) == VK_SUCCESS);
730}
731
732std::vector<DescriptorSet *> DescriptorPool::alloc_sets(
733    const Device &dev,
734    const std::vector<const DescriptorSetLayout *> &layouts) {
735    const std::vector<VkDescriptorSetLayout> layout_handles =
736        make_handles<VkDescriptorSetLayout>(layouts);
737
738    std::vector<VkDescriptorSet> set_handles;
739    set_handles.resize(layout_handles.size());
740
741    VkDescriptorSetAllocateInfo alloc_info = {};
742    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
743    alloc_info.descriptorSetCount = layout_handles.size();
744    alloc_info.descriptorPool = handle();
745    alloc_info.pSetLayouts = layout_handles.data();
746    VkResult err =
747        vkAllocateDescriptorSets(device(), &alloc_info, set_handles.data());
748    EXPECT(err == VK_SUCCESS);
749
750    std::vector<DescriptorSet *> sets;
751    for (std::vector<VkDescriptorSet>::const_iterator it = set_handles.begin();
752         it != set_handles.end(); it++) {
753        // do descriptor sets need memories bound?
754        DescriptorSet *descriptorSet = new DescriptorSet(dev, this, *it);
755        sets.push_back(descriptorSet);
756    }
757    return sets;
758}
759
760std::vector<DescriptorSet *>
761DescriptorPool::alloc_sets(const Device &dev, const DescriptorSetLayout &layout,
762                           uint32_t count) {
763    return alloc_sets(dev,
764                      std::vector<const DescriptorSetLayout *>(count, &layout));
765}
766
767DescriptorSet *DescriptorPool::alloc_sets(const Device &dev,
768                                          const DescriptorSetLayout &layout) {
769    std::vector<DescriptorSet *> set = alloc_sets(dev, layout, 1);
770    return (set.empty()) ? NULL : set[0];
771}
772
773DescriptorSet::~DescriptorSet() {
774    if (initialized()) {
775        // Only call vkFree* on sets allocated from pool with usage *_DYNAMIC
776        if (containing_pool_->getDynamicUsage()) {
777            VkDescriptorSet sets[1] = {handle()};
778            EXPECT(vkFreeDescriptorSets(device(), containing_pool_->GetObj(), 1,
779                                        sets) == VK_SUCCESS);
780        }
781    }
782}
783
784NON_DISPATCHABLE_HANDLE_DTOR(CommandPool, vkDestroyCommandPool)
785
786void CommandPool::init(const Device &dev, const VkCommandPoolCreateInfo &info) {
787    NON_DISPATCHABLE_HANDLE_INIT(vkCreateCommandPool, dev, &info);
788}
789
790CommandBuffer::~CommandBuffer() {
791    if (initialized()) {
792        VkCommandBuffer cmds[] = {handle()};
793        vkFreeCommandBuffers(dev_handle_, cmd_pool_, 1, cmds);
794    }
795}
796
797void CommandBuffer::init(const Device &dev,
798                         const VkCommandBufferAllocateInfo &info) {
799    VkCommandBuffer cmd;
800
801    // Make sure commandPool is set
802    assert(info.commandPool);
803
804    if (EXPECT(vkAllocateCommandBuffers(dev.handle(), &info, &cmd) ==
805               VK_SUCCESS)) {
806        Handle::init(cmd);
807        dev_handle_ = dev.handle();
808        cmd_pool_ = info.commandPool;
809    }
810}
811
812void CommandBuffer::begin(const VkCommandBufferBeginInfo *info) {
813    EXPECT(vkBeginCommandBuffer(handle(), info) == VK_SUCCESS);
814}
815
816void CommandBuffer::begin() {
817    VkCommandBufferBeginInfo info = {};
818    VkCommandBufferInheritanceInfo hinfo = {};
819    info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
820    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
821    info.pInheritanceInfo = &hinfo;
822    hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
823    hinfo.pNext = NULL;
824    hinfo.renderPass = VK_NULL_HANDLE;
825    hinfo.subpass = 0;
826    hinfo.framebuffer = VK_NULL_HANDLE;
827    hinfo.occlusionQueryEnable = VK_FALSE;
828    hinfo.queryFlags = 0;
829    hinfo.pipelineStatistics = 0;
830
831    begin(&info);
832}
833
834void CommandBuffer::end() {
835    EXPECT(vkEndCommandBuffer(handle()) == VK_SUCCESS);
836}
837
838void CommandBuffer::reset(VkCommandBufferResetFlags flags) {
839    EXPECT(vkResetCommandBuffer(handle(), flags) == VK_SUCCESS);
840}
841
842}; // namespace vk_testing
843