让Vulkan告诉你你的显卡有多强
让Vulkan告诉你你的显卡有多强
邹晓航0号
养猪的
关注他
45 人赞同了该文章
很多人在写图形程序的时候,都会有个疑问,那就是我自己的显卡到底有多强呢,我的显卡兹磁不兹磁tessellation shader呢,geometry shader呢,多重采样到底最大兹磁采样次数是多少呢。当然,在opengl里面这些信息是可以获得的,但是为了更好的跟上时代的发展,我们就需要学习学习下一代图形API了, 由于之前对opengl比较了解,对dx仅仅是看过dx11龙书的水平,因此我就选取opengl的下一代API,Vulkan来作为主要的API。本篇文章是系列的第一篇,将利用Vulkan来探索你的显卡的机能。
首先,vulkan是可以作为你的应用程序的子系统嵌入到你的应用中去的,因此为了不引入vulkan相关的全局变量到你的应用程序环境中去,vulkan使用了VkInstance来抽象实例概念,如图所示:
因此,我们首先创建一个VkInstance变量:
VkInstance instance; res = vkCreateInstance(&ici, nullptr, &instance);
我们来看一下vkCreateInstance的定义
VkResult vkCreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
Vulkan生成所谓的对象都是有套路的,首先你要自己定义XXXCreateInfo对象,然后在这个对象里面填入一些控制创建行为的参数,然后将这个参数传入相应的create函数,这个函数会通过一个对象指针返回创建出来的对象。你可能要疑问,那个pAllocator是个什么鬼,其实Vulkan是允许应用程序实现自己的对象内存分配算法的,毕竟Vulkan的目标是高性能图形API嘛,但是我们暂时不需要操心这个传入nullptr就行了,Vulkan会使用默认的内存分配算法。
VkInstanceCreateInfo对象生成代码如下:
VkInstanceCreateInfo ici = {}; ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; ici.pNext = nullptr; ici.pApplicationInfo = nullptr;
这里又要设计另一种Vulkan的套路了。很多Vulkan的结构体都会有sType和pNext这两个成员,sType就是这个结构体的类型了,但是为什么还需要将结构体的类型再传一次呢,不是多此一举吗毕竟程序员打字还是很累的。这里我认为Vulkan是这样考虑的,第一就是设置了sType的值能让一些validator或者是debuger等快速的对这个结构体进行合法性验证,其次是当一些接口采用的是void*形式的时候我们就能利用sType重新获得这个指针指向的结构体类型,最后就是一些Vulkan的扩展可能会把sType设为扩展结构体的类型值,这样就能在扩展中获得支持,同时pNext传入扩展的特殊数据进去。通常我们只需要把sType设为VK_STRUCTURE_TYPE_XXX_CREATE_INFO,把pNext设为nullptr就行了。
当创建好了instance后,我们就可以通过instance来查询我们的系统到底有多少个GPU了
uint32_t gpuCount; res = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr); std::vector<VkPhysicalDevice> gpus(gpuCount); res = vkEnumeratePhysicalDevices(instance, &gpuCount, gpus.data()); assert(gpuCount > 0);
这里又要涉及到Vulkan的套路了(Vulkan怎么这么多套路,心累。。。)。首先,来看一下vkEnumeratePhysicalDevices的函数定义:
VkResult vkEnumeratePhysicalDevices( VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
instance参数就是我们之前生成的vkInstance,pPhysicalDevices返回的就是我们系统GPU的数组了,pPhysicalDeviceCount就是这个数组的大小。但是我们事先并不知道这个大小啊,我们需要的不就是要查询这个大小吗,怎么查询函数又要我们传入这个值呢,一脸懵逼.jpg。这里就是Vulkan的套路了,首先分两步走,第一先设pPhysicalDevices为nullptr,这时vulkan就会忽略这个参数,同时把查到的数组大小通过pPhysicalDeviceCount返回给程序员,第二步就不需要我介绍怎么做了吧,看上面的代码。注意的是几乎所有的查询类函数都是这样的套路。
当我们获得了GPU数组对象后我们就可以遍历这个数组,然后查看每个GPU的性能了。vkGetPhysicalDeviceProperties和vkGetPhysicalDeviceFeatures函数分别返回GPU的general属性和GPU支持的一些扩展特性。废话不多说上完整代码:
#include <vulkan\vulkan.h> #include <iostream> #include <cassert> #include <vector> using namespace std; int main() { VkResult res; VkInstanceCreateInfo ici = {}; ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; ici.pNext = nullptr; ici.pApplicationInfo = nullptr; VkInstance instance; res = vkCreateInstance(&ici, nullptr, &instance); if (res == VK_ERROR_INCOMPATIBLE_DRIVER) { cout << "Your driver is imcompatible!!!" << endl; } else if (res) { cout << "You can not create VkInstance" << endl; } uint32_t gpuCount; res = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr); std::vector<VkPhysicalDevice> gpus(gpuCount); res = vkEnumeratePhysicalDevices(instance, &gpuCount, gpus.data()); assert(gpuCount > 0); for (const auto& gpu : gpus) { //typedef struct VkPhysicalDeviceProperties { //uint32_t apiVersion; //uint32_t driverVersion; //uint32_t vendorID; //uint32_t deviceID; //VkPhysicalDeviceType deviceType; //char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; //uint8_t pipelineCacheUUID[VK_UUID_SIZE]; //VkPhysicalDeviceLimits limits; //VkPhysicalDeviceSparseProperties sparseProperties; //} VkPhysicalDeviceProperties; VkPhysicalDeviceProperties prop; vkGetPhysicalDeviceProperties(gpu, &prop); cout << "=============================================" << endl; cout << "Your gpu is " << prop.deviceName << endl; //typedef struct VkPhysicalDeviceLimits { //uint32_t maxImageDimension1D; //uint32_t maxImageDimension2D; //uint32_t maxImageDimension3D; //uint32_t maxImageDimensionCube; //uint32_t maxImageArrayLayers; //uint32_t maxTexelBufferElements; //uint32_t maxUniformBufferRange; //uint32_t maxStorageBufferRange; //uint32_t maxPushConstantsSize; //uint32_t maxMemoryAllocationCount; //uint32_t maxSamplerAllocationCount; //VkDeviceSize bufferImageGranularity; //VkDeviceSize sparseAddressSpaceSize; //uint32_t maxBoundDescriptorSets; //uint32_t maxPerStageDescriptorSamplers; //uint32_t maxPerStageDescriptorUniformBuffers; //uint32_t maxPerStageDescriptorStorageBuffers; //uint32_t maxPerStageDescriptorSampledImages; //uint32_t maxPerStageDescriptorStorageImages; //uint32_t maxPerStageDescriptorInputAttachments; //uint32_t maxPerStageResources; //uint32_t maxDescriptorSetSamplers; //uint32_t maxDescriptorSetUniformBuffers; //uint32_t maxDescriptorSetUniformBuffersDynamic; //uint32_t maxDescriptorSetStorageBuffers; //uint32_t maxDescriptorSetStorageBuffersDynamic; //uint32_t maxDescriptorSetSampledImages; //uint32_t maxDescriptorSetStorageImages; //uint32_t maxDescriptorSetInputAttachments; //uint32_t maxVertexInputAttributes; //uint32_t maxVertexInputBindings; //uint32_t maxVertexInputAttributeOffset; //uint32_t maxVertexInputBindingStride; //uint32_t maxVertexOutputComponents; //uint32_t maxTessellationGenerationLevel; //uint32_t maxTessellationPatchSize; //uint32_t maxTessellationControlPerVertexInputComponents; //uint32_t maxTessellationControlPerVertexOutputComponents; //uint32_t maxTessellationControlPerPatchOutputComponents; //uint32_t maxTessellationControlTotalOutputComponents; //uint32_t maxTessellationEvaluationInputComponents; //uint32_t maxTessellationEvaluationOutputComponents; //uint32_t maxGeometryShaderInvocations; //uint32_t maxGeometryInputComponents; //uint32_t maxGeometryOutputComponents; //uint32_t maxGeometryOutputVertices; //uint32_t maxGeometryTotalOutputComponents; //uint32_t maxFragmentInputComponents; //uint32_t maxFragmentOutputAttachments; //uint32_t maxFragmentDualSrcAttachments; //uint32_t maxFragmentCombinedOutputResources; //uint32_t maxComputeSharedMemorySize; //uint32_t maxComputeWorkGroupCount[3]; //uint32_t maxComputeWorkGroupInvocations; //uint32_t maxComputeWorkGroupSize[3]; //uint32_t subPixelPrecisionBits; //uint32_t subTexelPrecisionBits; //uint32_t mipmapPrecisionBits; //uint32_t maxDrawIndexedIndexValue; //uint32_t maxDrawIndirectCount; //float maxSamplerLodBias; //float maxSamplerAnisotropy; //uint32_t maxViewports; //uint32_t maxViewportDimensions[2]; //float viewportBoundsRange[2]; //uint32_t viewportSubPixelBits; //size_t minMemoryMapAlignment; //VkDeviceSize minTexelBufferOffsetAlignment; //VkDeviceSize minUniformBufferOffsetAlignment; //VkDeviceSize minStorageBufferOffsetAlignment; //int32_t minTexelOffset; //uint32_t maxTexelOffset; //int32_t minTexelGatherOffset; //uint32_t maxTexelGatherOffset; //float minInterpolationOffset; //float maxInterpolationOffset; //uint32_t subPixelInterpolationOffsetBits; //uint32_t maxFramebufferWidth; //uint32_t maxFramebufferHeight; //uint32_t maxFramebufferLayers; //VkSampleCountFlags framebufferColorSampleCounts; //VkSampleCountFlags framebufferDepthSampleCounts; //VkSampleCountFlags framebufferStencilSampleCounts; //VkSampleCountFlags framebufferNoAttachmentsSampleCounts; //uint32_t maxColorAttachments; //VkSampleCountFlags sampledImageColorSampleCounts; //VkSampleCountFlags sampledImageIntegerSampleCounts; //VkSampleCountFlags sampledImageDepthSampleCounts; //VkSampleCountFlags sampledImageStencilSampleCounts; //VkSampleCountFlags storageImageSampleCounts; //uint32_t maxSampleMaskWords; //VkBool32 timestampComputeAndGraphics; //float timestampPeriod; //uint32_t maxClipDistances; //uint32_t maxCullDistances; //uint32_t maxCombinedClipAndCullDistances; //uint32_t discreteQueuePriorities; //float pointSizeRange[2]; //float lineWidthRange[2]; //float pointSizeGranularity; //float lineWidthGranularity; //VkBool32 strictLines; //VkBool32 standardSampleLocations; //VkDeviceSize optimalBufferCopyOffsetAlignment; //VkDeviceSize optimalBufferCopyRowPitchAlignment; //VkDeviceSize nonCoherentAtomSize; //} VkPhysicalDeviceLimits; cout << "\tmaxImageDimension1D:" << prop.limits.maxImageDimension1D << endl; cout << "\tmaxImageDimension2D:" << prop.limits.maxImageDimension2D << endl; cout << "\tmaxImageDimension3D:" << prop.limits.maxImageDimension3D << endl; cout << "\tmaxImageDimensionCube:" << prop.limits.maxImageDimensionCube << endl; cout << "\tmaxImageArrayLayers:" << prop.limits.maxImageArrayLayers << endl; cout << "\tmaxTexelBufferElements:" << prop.limits.maxTexelBufferElements << endl; cout << "\tmaxVertexInputAttributes:" << prop.limits.maxVertexInputAttributes << endl; cout << "\tmaxFragmentOutputAttachments:" << prop.limits.maxFragmentOutputAttachments << endl; cout << "\tmaxFramebufferWidth:" << prop.limits.maxFramebufferWidth << endl; cout << "\tmaxFramebufferHeight:" << prop.limits.maxFramebufferHeight << endl; cout << "\tmaxFramebufferLayers:" << prop.limits.maxFramebufferLayers << endl; cout << "\tframebufferColorSampleCounts:" << prop.limits.framebufferColorSampleCounts << endl; cout << "\tframebufferDepthSampleCounts:" << prop.limits.framebufferDepthSampleCounts << endl; cout << "\tframebufferStencilSampleCounts:" << prop.limits.framebufferStencilSampleCounts << endl; cout << "\tmaxColorAttachments:" << prop.limits.maxColorAttachments << endl << endl; //typedef struct VkPhysicalDeviceFeatures { //VkBool32 robustBufferAccess; //VkBool32 fullDrawIndexUint32; //VkBool32 imageCubeArray; //VkBool32 independentBlend; //VkBool32 geometryShader; //VkBool32 tessellationShader; //VkBool32 sampleRateShading; //VkBool32 dualSrcBlend; //VkBool32 logicOp; //VkBool32 multiDrawIndirect; //VkBool32 drawIndirectFirstInstance; //VkBool32 depthClamp; //VkBool32 depthBiasClamp; //VkBool32 fillModeNonSolid; //VkBool32 depthBounds; //VkBool32 wideLines; //VkBool32 largePoints; //VkBool32 alphaToOne; //VkBool32 multiViewport; //VkBool32 samplerAnisotropy; //VkBool32 textureCompressionETC2; //VkBool32 textureCompressionASTC_LDR; //VkBool32 textureCompressionBC; //VkBool32 occlusionQueryPrecise; //VkBool32 pipelineStatisticsQuery; //VkBool32 vertexPipelineStoresAndAtomics; //VkBool32 fragmentStoresAndAtomics; //VkBool32 shaderTessellationAndGeometryPointSize; //VkBool32 shaderImageGatherExtended; //VkBool32 shaderStorageImageExtendedFormats; //VkBool32 shaderStorageImageMultisample; //VkBool32 shaderStorageImageReadWithoutFormat; //VkBool32 shaderStorageImageWriteWithoutFormat; //VkBool32 shaderUniformBufferArrayDynamicIndexing; //VkBool32 shaderSampledImageArrayDynamicIndexing; //VkBool32 shaderStorageBufferArrayDynamicIndexing; //VkBool32 shaderStorageImageArrayDynamicIndexing; //VkBool32 shaderClipDistance; //VkBool32 shaderCullDistance; //VkBool32 shaderFloat64; //VkBool32 shaderInt64; //VkBool32 shaderInt16; //VkBool32 shaderResourceResidency; //VkBool32 shaderResourceMinLod; //VkBool32 sparseBinding; //VkBool32 sparseResidencyBuffer; //VkBool32 sparseResidencyImage2D; //VkBool32 sparseResidencyImage3D; //VkBool32 sparseResidency2Samples; //VkBool32 sparseResidency4Samples; //VkBool32 sparseResidency8Samples; //VkBool32 sparseResidency16Samples; //VkBool32 sparseResidencyAliased; //VkBool32 variableMultisampleRate; //VkBool32 inheritedQueries; //} VkPhysicalDeviceFeatures; VkPhysicalDeviceFeatures feature; vkGetPhysicalDeviceFeatures(gpu, &feature); cout << "\tgeometryShader:" << boolalpha << (feature.geometryShader == 1) << endl; cout << "\ttessellationShader:" << boolalpha << (feature.tessellationShader == 1) << endl; cout << "\timageCubeArray:" << boolalpha << (feature.imageCubeArray == 1) << endl; cout << "\tindependentBlend:" << boolalpha << (feature.independentBlend == 1) << endl; cout << "\tmultiViewport:" << boolalpha << (feature.multiViewport == 1) << endl; cout << "\tsamplerAnisotropy:" << boolalpha << (feature.samplerAnisotropy == 1) << endl; cout << "\ttextureCompressionETC2:" << boolalpha << (feature.textureCompressionETC2 == 1) << endl; cout << "\ttextureCompressionASTC_LDR:" << boolalpha << (feature.textureCompressionASTC_LDR == 1) << endl; cout << "\ttextureCompressionBC:" << boolalpha << (feature.textureCompressionBC == 1)<< endl; } vkDestroyInstance(instance, nullptr); system("pause"); return 0; }
最后送上两张图:
编辑于 2017-01-14