mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix, Test] (DirectVulkan, SelfTest, MG_IntegrationTest, TraceReplay): snapshot sampler/image feedback and add Program 203 diagnostics
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "DriverPost.h"
|
||||
#include "DriverPostProgram203Witness.h"
|
||||
#include "DriverPostProgram203WitnessSpv.h"
|
||||
#include "MG_Util/BackendLoaders/OpenGL/Loader.h"
|
||||
#include <Config.h>
|
||||
#include <MGGitHash.h>
|
||||
@@ -24,6 +26,8 @@
|
||||
#include <MG_Util/Texture/TextureFormatProcessor.h>
|
||||
#include <MG_Util/Async/ShaderCompilePool.h>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
@@ -1454,6 +1458,437 @@ namespace MobileGL::MG_Util::SelfTest {
|
||||
disabledNote);
|
||||
}
|
||||
|
||||
// Native Program-203 compute witness. This deliberately uses a separate
|
||||
// throwaway Vulkan device rather than the real renderer's queues, and it
|
||||
// treats MOBILEGL_DISABLE_SUBGROUP as irrelevant: the row reports what the
|
||||
// driver does, not what MobileGL elects to advertise to applications.
|
||||
void ProbeVulkanProgram203Witness(ReportBuilder& builder, PFN_vkGetInstanceProcAddr getInstanceProcAddr,
|
||||
VkInstance instance, VkPhysicalDevice physicalDevice,
|
||||
Uint32 computeQueueFamilyIndex,
|
||||
const VkPhysicalDeviceProperties& properties,
|
||||
Bool subgroupPropertiesAvailable,
|
||||
const VkPhysicalDeviceSubgroupProperties& subgroupProperties) {
|
||||
constexpr const char* RowName = "Subgroup first-reduction witness";
|
||||
const auto fail = [&](String detail) { builder.Fail(RowName, Move(detail)); };
|
||||
|
||||
if (!subgroupPropertiesAvailable) {
|
||||
fail("vkGetPhysicalDeviceProperties2 could not provide raw Vulkan subgroup properties");
|
||||
return;
|
||||
}
|
||||
|
||||
Program203WitnessLimits limits{};
|
||||
limits.computeStageSupported =
|
||||
(subgroupProperties.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0;
|
||||
limits.basicSubgroupSupported =
|
||||
(subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
|
||||
limits.arithmeticSubgroupSupported =
|
||||
(subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) != 0;
|
||||
limits.subgroupSize = subgroupProperties.subgroupSize;
|
||||
limits.maxComputeWorkGroupInvocations = properties.limits.maxComputeWorkGroupInvocations;
|
||||
limits.maxComputeWorkGroupSize = {properties.limits.maxComputeWorkGroupSize[0],
|
||||
properties.limits.maxComputeWorkGroupSize[1],
|
||||
properties.limits.maxComputeWorkGroupSize[2]};
|
||||
limits.maxComputeSharedMemorySize = properties.limits.maxComputeSharedMemorySize;
|
||||
limits.maxPerStageDescriptorStorageBuffers = properties.limits.maxPerStageDescriptorStorageBuffers;
|
||||
limits.maxDescriptorSetStorageBuffers = properties.limits.maxDescriptorSetStorageBuffers;
|
||||
limits.maxBoundDescriptorSets = properties.limits.maxBoundDescriptorSets;
|
||||
limits.maxStorageBufferRange = properties.limits.maxStorageBufferRange;
|
||||
|
||||
const Program203WitnessEligibilityResult eligibility = EvaluateProgram203WitnessEligibility(limits);
|
||||
if (eligibility.eligibility == Program203WitnessEligibility::SkipUnsupportedNativeFeatureSet) {
|
||||
builder.Info(RowName, eligibility.detail);
|
||||
return;
|
||||
}
|
||||
if (eligibility.eligibility == Program203WitnessEligibility::FailInadequateLimits) {
|
||||
fail(eligibility.detail);
|
||||
return;
|
||||
}
|
||||
if (computeQueueFamilyIndex == std::numeric_limits<Uint32>::max()) {
|
||||
fail("no compute queue family is available for the native Vulkan witness");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vkGetPhysicalDeviceMemoryPropertiesFn =
|
||||
reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(
|
||||
getInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties"));
|
||||
const auto vkCreateDeviceFn =
|
||||
reinterpret_cast<PFN_vkCreateDevice>(getInstanceProcAddr(instance, "vkCreateDevice"));
|
||||
const auto vkDestroyDeviceFn =
|
||||
reinterpret_cast<PFN_vkDestroyDevice>(getInstanceProcAddr(instance, "vkDestroyDevice"));
|
||||
const auto vkGetDeviceQueueFn =
|
||||
reinterpret_cast<PFN_vkGetDeviceQueue>(getInstanceProcAddr(instance, "vkGetDeviceQueue"));
|
||||
const auto vkCreateBufferFn =
|
||||
reinterpret_cast<PFN_vkCreateBuffer>(getInstanceProcAddr(instance, "vkCreateBuffer"));
|
||||
const auto vkDestroyBufferFn =
|
||||
reinterpret_cast<PFN_vkDestroyBuffer>(getInstanceProcAddr(instance, "vkDestroyBuffer"));
|
||||
const auto vkGetBufferMemoryRequirementsFn = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(
|
||||
getInstanceProcAddr(instance, "vkGetBufferMemoryRequirements"));
|
||||
const auto vkAllocateMemoryFn =
|
||||
reinterpret_cast<PFN_vkAllocateMemory>(getInstanceProcAddr(instance, "vkAllocateMemory"));
|
||||
const auto vkFreeMemoryFn =
|
||||
reinterpret_cast<PFN_vkFreeMemory>(getInstanceProcAddr(instance, "vkFreeMemory"));
|
||||
const auto vkBindBufferMemoryFn =
|
||||
reinterpret_cast<PFN_vkBindBufferMemory>(getInstanceProcAddr(instance, "vkBindBufferMemory"));
|
||||
const auto vkMapMemoryFn =
|
||||
reinterpret_cast<PFN_vkMapMemory>(getInstanceProcAddr(instance, "vkMapMemory"));
|
||||
const auto vkUnmapMemoryFn =
|
||||
reinterpret_cast<PFN_vkUnmapMemory>(getInstanceProcAddr(instance, "vkUnmapMemory"));
|
||||
const auto vkCreateDescriptorSetLayoutFn = reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(
|
||||
getInstanceProcAddr(instance, "vkCreateDescriptorSetLayout"));
|
||||
const auto vkDestroyDescriptorSetLayoutFn = reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(
|
||||
getInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout"));
|
||||
const auto vkCreateDescriptorPoolFn =
|
||||
reinterpret_cast<PFN_vkCreateDescriptorPool>(getInstanceProcAddr(instance, "vkCreateDescriptorPool"));
|
||||
const auto vkDestroyDescriptorPoolFn = reinterpret_cast<PFN_vkDestroyDescriptorPool>(
|
||||
getInstanceProcAddr(instance, "vkDestroyDescriptorPool"));
|
||||
const auto vkAllocateDescriptorSetsFn = reinterpret_cast<PFN_vkAllocateDescriptorSets>(
|
||||
getInstanceProcAddr(instance, "vkAllocateDescriptorSets"));
|
||||
const auto vkUpdateDescriptorSetsFn =
|
||||
reinterpret_cast<PFN_vkUpdateDescriptorSets>(getInstanceProcAddr(instance, "vkUpdateDescriptorSets"));
|
||||
const auto vkCreateShaderModuleFn =
|
||||
reinterpret_cast<PFN_vkCreateShaderModule>(getInstanceProcAddr(instance, "vkCreateShaderModule"));
|
||||
const auto vkDestroyShaderModuleFn =
|
||||
reinterpret_cast<PFN_vkDestroyShaderModule>(getInstanceProcAddr(instance, "vkDestroyShaderModule"));
|
||||
const auto vkCreatePipelineLayoutFn =
|
||||
reinterpret_cast<PFN_vkCreatePipelineLayout>(getInstanceProcAddr(instance, "vkCreatePipelineLayout"));
|
||||
const auto vkDestroyPipelineLayoutFn = reinterpret_cast<PFN_vkDestroyPipelineLayout>(
|
||||
getInstanceProcAddr(instance, "vkDestroyPipelineLayout"));
|
||||
const auto vkCreateComputePipelinesFn = reinterpret_cast<PFN_vkCreateComputePipelines>(
|
||||
getInstanceProcAddr(instance, "vkCreateComputePipelines"));
|
||||
const auto vkDestroyPipelineFn =
|
||||
reinterpret_cast<PFN_vkDestroyPipeline>(getInstanceProcAddr(instance, "vkDestroyPipeline"));
|
||||
const auto vkCreateCommandPoolFn =
|
||||
reinterpret_cast<PFN_vkCreateCommandPool>(getInstanceProcAddr(instance, "vkCreateCommandPool"));
|
||||
const auto vkDestroyCommandPoolFn =
|
||||
reinterpret_cast<PFN_vkDestroyCommandPool>(getInstanceProcAddr(instance, "vkDestroyCommandPool"));
|
||||
const auto vkAllocateCommandBuffersFn = reinterpret_cast<PFN_vkAllocateCommandBuffers>(
|
||||
getInstanceProcAddr(instance, "vkAllocateCommandBuffers"));
|
||||
const auto vkBeginCommandBufferFn =
|
||||
reinterpret_cast<PFN_vkBeginCommandBuffer>(getInstanceProcAddr(instance, "vkBeginCommandBuffer"));
|
||||
const auto vkEndCommandBufferFn =
|
||||
reinterpret_cast<PFN_vkEndCommandBuffer>(getInstanceProcAddr(instance, "vkEndCommandBuffer"));
|
||||
const auto vkCmdBindPipelineFn =
|
||||
reinterpret_cast<PFN_vkCmdBindPipeline>(getInstanceProcAddr(instance, "vkCmdBindPipeline"));
|
||||
const auto vkCmdBindDescriptorSetsFn = reinterpret_cast<PFN_vkCmdBindDescriptorSets>(
|
||||
getInstanceProcAddr(instance, "vkCmdBindDescriptorSets"));
|
||||
const auto vkCmdDispatchFn =
|
||||
reinterpret_cast<PFN_vkCmdDispatch>(getInstanceProcAddr(instance, "vkCmdDispatch"));
|
||||
const auto vkCmdPipelineBarrierFn =
|
||||
reinterpret_cast<PFN_vkCmdPipelineBarrier>(getInstanceProcAddr(instance, "vkCmdPipelineBarrier"));
|
||||
const auto vkCreateFenceFn =
|
||||
reinterpret_cast<PFN_vkCreateFence>(getInstanceProcAddr(instance, "vkCreateFence"));
|
||||
const auto vkDestroyFenceFn =
|
||||
reinterpret_cast<PFN_vkDestroyFence>(getInstanceProcAddr(instance, "vkDestroyFence"));
|
||||
const auto vkQueueSubmitFn =
|
||||
reinterpret_cast<PFN_vkQueueSubmit>(getInstanceProcAddr(instance, "vkQueueSubmit"));
|
||||
const auto vkWaitForFencesFn =
|
||||
reinterpret_cast<PFN_vkWaitForFences>(getInstanceProcAddr(instance, "vkWaitForFences"));
|
||||
const auto vkDeviceWaitIdleFn =
|
||||
reinterpret_cast<PFN_vkDeviceWaitIdle>(getInstanceProcAddr(instance, "vkDeviceWaitIdle"));
|
||||
|
||||
if (vkGetPhysicalDeviceMemoryPropertiesFn == nullptr || vkCreateDeviceFn == nullptr ||
|
||||
vkDestroyDeviceFn == nullptr || vkGetDeviceQueueFn == nullptr || vkCreateBufferFn == nullptr ||
|
||||
vkDestroyBufferFn == nullptr || vkGetBufferMemoryRequirementsFn == nullptr ||
|
||||
vkAllocateMemoryFn == nullptr || vkFreeMemoryFn == nullptr || vkBindBufferMemoryFn == nullptr ||
|
||||
vkMapMemoryFn == nullptr || vkUnmapMemoryFn == nullptr || vkCreateDescriptorSetLayoutFn == nullptr ||
|
||||
vkDestroyDescriptorSetLayoutFn == nullptr || vkCreateDescriptorPoolFn == nullptr ||
|
||||
vkDestroyDescriptorPoolFn == nullptr || vkAllocateDescriptorSetsFn == nullptr ||
|
||||
vkUpdateDescriptorSetsFn == nullptr || vkCreateShaderModuleFn == nullptr ||
|
||||
vkDestroyShaderModuleFn == nullptr || vkCreatePipelineLayoutFn == nullptr ||
|
||||
vkDestroyPipelineLayoutFn == nullptr || vkCreateComputePipelinesFn == nullptr ||
|
||||
vkDestroyPipelineFn == nullptr || vkCreateCommandPoolFn == nullptr || vkDestroyCommandPoolFn == nullptr ||
|
||||
vkAllocateCommandBuffersFn == nullptr || vkBeginCommandBufferFn == nullptr ||
|
||||
vkEndCommandBufferFn == nullptr || vkCmdBindPipelineFn == nullptr ||
|
||||
vkCmdBindDescriptorSetsFn == nullptr || vkCmdDispatchFn == nullptr ||
|
||||
vkCmdPipelineBarrierFn == nullptr || vkCreateFenceFn == nullptr || vkDestroyFenceFn == nullptr ||
|
||||
vkQueueSubmitFn == nullptr || vkWaitForFencesFn == nullptr || vkDeviceWaitIdleFn == nullptr) {
|
||||
fail("vkGetInstanceProcAddr could not resolve the Vulkan entry points required for the witness");
|
||||
return;
|
||||
}
|
||||
|
||||
const Float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueInfo{};
|
||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueInfo.queueFamilyIndex = computeQueueFamilyIndex;
|
||||
queueInfo.queueCount = 1;
|
||||
queueInfo.pQueuePriorities = &queuePriority;
|
||||
|
||||
VkDeviceCreateInfo deviceInfo{};
|
||||
deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
deviceInfo.queueCreateInfoCount = 1;
|
||||
deviceInfo.pQueueCreateInfos = &queueInfo;
|
||||
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateDeviceFn(physicalDevice, &deviceInfo, nullptr, &device);
|
||||
if (result != VK_SUCCESS || device == VK_NULL_HANDLE) {
|
||||
fail(format("vkCreateDevice failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkBuffer outputBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory outputMemory = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
||||
VkShaderModule shaderModule = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
void* mappedOutput = nullptr;
|
||||
Bool fenceWaitTimedOut = false;
|
||||
const ScopeGuard destroyDeviceObjects([&]() {
|
||||
if (fenceWaitTimedOut) {
|
||||
// Match ProbeVulkanTimerQuery: the command may still execute
|
||||
// after a timeout, so intentionally retain every device-owned
|
||||
// resource rather than risking a forever wait or UAF in the ICD.
|
||||
return;
|
||||
}
|
||||
vkDeviceWaitIdleFn(device);
|
||||
if (fence != VK_NULL_HANDLE) vkDestroyFenceFn(device, fence, nullptr);
|
||||
if (commandPool != VK_NULL_HANDLE) vkDestroyCommandPoolFn(device, commandPool, nullptr);
|
||||
if (pipeline != VK_NULL_HANDLE) vkDestroyPipelineFn(device, pipeline, nullptr);
|
||||
if (pipelineLayout != VK_NULL_HANDLE) vkDestroyPipelineLayoutFn(device, pipelineLayout, nullptr);
|
||||
if (shaderModule != VK_NULL_HANDLE) vkDestroyShaderModuleFn(device, shaderModule, nullptr);
|
||||
if (descriptorPool != VK_NULL_HANDLE) vkDestroyDescriptorPoolFn(device, descriptorPool, nullptr);
|
||||
if (descriptorSetLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayoutFn(device, descriptorSetLayout, nullptr);
|
||||
}
|
||||
if (mappedOutput != nullptr) vkUnmapMemoryFn(device, outputMemory);
|
||||
if (outputBuffer != VK_NULL_HANDLE) vkDestroyBufferFn(device, outputBuffer, nullptr);
|
||||
if (outputMemory != VK_NULL_HANDLE) vkFreeMemoryFn(device, outputMemory, nullptr);
|
||||
vkDestroyDeviceFn(device, nullptr);
|
||||
});
|
||||
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
vkGetDeviceQueueFn(device, computeQueueFamilyIndex, 0, &queue);
|
||||
if (queue == VK_NULL_HANDLE) {
|
||||
fail("vkGetDeviceQueue returned a null compute queue");
|
||||
return;
|
||||
}
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = sizeof(Program203WitnessOutput);
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
result = vkCreateBufferFn(device, &bufferInfo, nullptr, &outputBuffer);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateBuffer(output SSBO) failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memoryRequirements{};
|
||||
vkGetBufferMemoryRequirementsFn(device, outputBuffer, &memoryRequirements);
|
||||
VkPhysicalDeviceMemoryProperties memoryProperties{};
|
||||
vkGetPhysicalDeviceMemoryPropertiesFn(physicalDevice, &memoryProperties);
|
||||
Uint32 memoryTypeIndex = std::numeric_limits<Uint32>::max();
|
||||
for (Uint32 index = 0; index < memoryProperties.memoryTypeCount; ++index) {
|
||||
const Bool compatible = (memoryRequirements.memoryTypeBits & (1u << index)) != 0u;
|
||||
const VkMemoryPropertyFlags required = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
if (compatible && (memoryProperties.memoryTypes[index].propertyFlags & required) == required) {
|
||||
memoryTypeIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (memoryTypeIndex == std::numeric_limits<Uint32>::max()) {
|
||||
fail("no host-visible/coherent memory type is compatible with the output SSBO");
|
||||
return;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo memoryInfo{};
|
||||
memoryInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memoryInfo.allocationSize = memoryRequirements.size;
|
||||
memoryInfo.memoryTypeIndex = memoryTypeIndex;
|
||||
result = vkAllocateMemoryFn(device, &memoryInfo, nullptr, &outputMemory);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkAllocateMemory(output SSBO) failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
result = vkBindBufferMemoryFn(device, outputBuffer, outputMemory, 0);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkBindBufferMemory(output SSBO) failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
result = vkMapMemoryFn(device, outputMemory, 0, sizeof(Program203WitnessOutput), 0, &mappedOutput);
|
||||
if (result != VK_SUCCESS || mappedOutput == nullptr) {
|
||||
fail(format("vkMapMemory(output SSBO) failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
std::memset(mappedOutput, 0xa5, sizeof(Program203WitnessOutput));
|
||||
|
||||
VkDescriptorSetLayoutBinding outputBinding{};
|
||||
outputBinding.binding = 0;
|
||||
outputBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
outputBinding.descriptorCount = 1;
|
||||
outputBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{};
|
||||
descriptorSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
descriptorSetLayoutInfo.bindingCount = 1;
|
||||
descriptorSetLayoutInfo.pBindings = &outputBinding;
|
||||
result = vkCreateDescriptorSetLayoutFn(device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateDescriptorSetLayout failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkDescriptorPoolSize poolSize{};
|
||||
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
poolSize.descriptorCount = 1;
|
||||
VkDescriptorPoolCreateInfo descriptorPoolInfo{};
|
||||
descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptorPoolInfo.maxSets = 1;
|
||||
descriptorPoolInfo.poolSizeCount = 1;
|
||||
descriptorPoolInfo.pPoolSizes = &poolSize;
|
||||
result = vkCreateDescriptorPoolFn(device, &descriptorPoolInfo, nullptr, &descriptorPool);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateDescriptorPool failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||
VkDescriptorSetAllocateInfo descriptorSetInfo{};
|
||||
descriptorSetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptorSetInfo.descriptorPool = descriptorPool;
|
||||
descriptorSetInfo.descriptorSetCount = 1;
|
||||
descriptorSetInfo.pSetLayouts = &descriptorSetLayout;
|
||||
result = vkAllocateDescriptorSetsFn(device, &descriptorSetInfo, &descriptorSet);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkAllocateDescriptorSets failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
VkDescriptorBufferInfo outputDescriptor{};
|
||||
outputDescriptor.buffer = outputBuffer;
|
||||
outputDescriptor.offset = 0;
|
||||
outputDescriptor.range = sizeof(Program203WitnessOutput);
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = descriptorSet;
|
||||
descriptorWrite.dstBinding = 0;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
descriptorWrite.pBufferInfo = &outputDescriptor;
|
||||
vkUpdateDescriptorSetsFn(device, 1, &descriptorWrite, 0, nullptr);
|
||||
|
||||
VkShaderModuleCreateInfo shaderModuleInfo{};
|
||||
shaderModuleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
shaderModuleInfo.codeSize = sizeof(kDriverPostProgram203WitnessSpv);
|
||||
shaderModuleInfo.pCode = kDriverPostProgram203WitnessSpv;
|
||||
result = vkCreateShaderModuleFn(device, &shaderModuleInfo, nullptr, &shaderModule);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateShaderModule failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = 1;
|
||||
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
|
||||
result = vkCreatePipelineLayoutFn(device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreatePipelineLayout failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStage{};
|
||||
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
shaderStage.module = shaderModule;
|
||||
shaderStage.pName = "main";
|
||||
VkComputePipelineCreateInfo pipelineInfo{};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stage = shaderStage;
|
||||
pipelineInfo.layout = pipelineLayout;
|
||||
result = vkCreateComputePipelinesFn(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateComputePipelines failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkCommandPoolCreateInfo commandPoolInfo{};
|
||||
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
commandPoolInfo.queueFamilyIndex = computeQueueFamilyIndex;
|
||||
result = vkCreateCommandPoolFn(device, &commandPoolInfo, nullptr, &commandPool);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateCommandPool failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
VkCommandBufferAllocateInfo commandBufferInfo{};
|
||||
commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
commandBufferInfo.commandPool = commandPool;
|
||||
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
commandBufferInfo.commandBufferCount = 1;
|
||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||
result = vkAllocateCommandBuffersFn(device, &commandBufferInfo, &commandBuffer);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkAllocateCommandBuffers failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkCommandBufferBeginInfo commandBufferBeginInfo{};
|
||||
commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
result = vkBeginCommandBufferFn(commandBuffer, &commandBufferBeginInfo);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkBeginCommandBuffer failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
vkCmdBindPipelineFn(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
||||
vkCmdBindDescriptorSetsFn(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1,
|
||||
&descriptorSet, 0, nullptr);
|
||||
vkCmdDispatchFn(commandBuffer, 1, 1, 1);
|
||||
VkBufferMemoryBarrier hostReadBarrier{};
|
||||
hostReadBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||
hostReadBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
hostReadBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
|
||||
hostReadBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
hostReadBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
hostReadBarrier.buffer = outputBuffer;
|
||||
hostReadBarrier.offset = 0;
|
||||
hostReadBarrier.size = sizeof(Program203WitnessOutput);
|
||||
vkCmdPipelineBarrierFn(commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
|
||||
0, nullptr, 1, &hostReadBarrier, 0, nullptr);
|
||||
result = vkEndCommandBufferFn(commandBuffer);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkEndCommandBuffer failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
result = vkCreateFenceFn(device, &fenceInfo, nullptr, &fence);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkCreateFence failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
result = vkQueueSubmitFn(queue, 1, &submitInfo, fence);
|
||||
if (result != VK_SUCCESS) {
|
||||
fail(format("vkQueueSubmit failed (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr Uint64 FenceTimeoutNs = 5'000'000'000ull;
|
||||
result = vkWaitForFencesFn(device, 1, &fence, VK_TRUE, FenceTimeoutNs);
|
||||
if (result != VK_SUCCESS) {
|
||||
fenceWaitTimedOut = true;
|
||||
fail(format("vkWaitForFences did not signal within 5 s (VkResult = {})", static_cast<Int>(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
Program203WitnessOutput output{};
|
||||
std::memcpy(&output, mappedOutput, sizeof(output));
|
||||
const Program203WitnessValidationResult validation = ValidateProgram203Witness(output);
|
||||
if (!validation.ok) {
|
||||
fail(validation.detail);
|
||||
return;
|
||||
}
|
||||
builder.Pass(RowName, validation.detail);
|
||||
}
|
||||
|
||||
// Everything the "MobileGL reported ..." rows need from the Vulkan device probe.
|
||||
struct VulkanProbeSummary {
|
||||
Bool devicePropsValid = false;
|
||||
@@ -1669,6 +2104,7 @@ namespace MobileGL::MG_Util::SelfTest {
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
Uint32 graphicsQueueFamilyIndex = 0;
|
||||
Uint32 graphicsQueueTimestampValidBits = 0;
|
||||
Uint32 computeQueueFamilyIndex = std::numeric_limits<Uint32>::max();
|
||||
for (VkPhysicalDevice candidate : devices) {
|
||||
Uint32 queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyPropertiesFn(candidate, &queueFamilyCount, nullptr);
|
||||
@@ -1684,6 +2120,13 @@ namespace MobileGL::MG_Util::SelfTest {
|
||||
}
|
||||
}
|
||||
if (physicalDevice != VK_NULL_HANDLE) {
|
||||
for (Uint32 familyIndex = 0; familyIndex < queueFamilyCount; ++familyIndex) {
|
||||
const VkQueueFamilyProperties& family = queueFamilies[familyIndex];
|
||||
if (family.queueCount > 0 && (family.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) {
|
||||
computeQueueFamilyIndex = familyIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2020,13 +2463,15 @@ namespace MobileGL::MG_Util::SelfTest {
|
||||
"change every N instances change every one");
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSubgroupProperties subgroupProperties{};
|
||||
Bool subgroupPropertiesAvailable = false;
|
||||
if (vkGetPhysicalDeviceProperties2Fn != nullptr && properties.apiVersion >= VK_API_VERSION_1_1) {
|
||||
VkPhysicalDeviceSubgroupProperties subgroupProperties{};
|
||||
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
|
||||
VkPhysicalDeviceProperties2 properties2{};
|
||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
properties2.pNext = &subgroupProperties;
|
||||
vkGetPhysicalDeviceProperties2Fn(physicalDevice, &properties2);
|
||||
subgroupPropertiesAvailable = true;
|
||||
const Bool subgroupUsable = subgroupProperties.subgroupSize > 0 &&
|
||||
(subgroupProperties.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0 &&
|
||||
(subgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
|
||||
@@ -2046,6 +2491,9 @@ namespace MobileGL::MG_Util::SelfTest {
|
||||
builder.Warn("Compute shader subgroup", "subgroup properties could not be queried");
|
||||
}
|
||||
|
||||
ProbeVulkanProgram203Witness(builder, getInstanceProcAddr, instance, physicalDevice, computeQueueFamilyIndex,
|
||||
properties, subgroupPropertiesAvailable, subgroupProperties);
|
||||
|
||||
if (HasVkExtension(deviceExtensions, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME)) {
|
||||
builder.Pass("VK_KHR_draw_indirect_count",
|
||||
"supported (count-buffer indirect draws run as single native "
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// MobileGL - MobileGL/MG_Util/SelfTest/DriverPostProgram203Witness.comp
|
||||
// Copyright (c) 2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
//
|
||||
// Native Vulkan GLSL 450 witness for Program 203's first subgroup reduction.
|
||||
// It is intentionally independent of the GL 430 integration scenario. The body
|
||||
// below preserves Program 203's source reduction; the surrounding diagnostics
|
||||
// only observe its topology and cache handoffs.
|
||||
|
||||
#version 450
|
||||
#extension GL_KHR_shader_subgroup_basic : require
|
||||
#extension GL_KHR_shader_subgroup_arithmetic : require
|
||||
|
||||
layout(local_size_x = 32, local_size_y = 16, local_size_z = 1) in;
|
||||
|
||||
const uint kTopologyNonuniformNumSubgroups = 1u << 0u;
|
||||
const uint kTopologyInvalidNumSubgroups = 1u << 1u;
|
||||
const uint kTopologyInvalidSubgroupId = 1u << 2u;
|
||||
const uint kTopologyInvalidSubgroupLane = 1u << 3u;
|
||||
const uint kWitnessMagic = 0x50323033u;
|
||||
|
||||
layout(std430, set = 0, binding = 0) buffer Program203WitnessOutput {
|
||||
uint magic;
|
||||
uint topologyFlags;
|
||||
uint numSubgroups;
|
||||
uint loopLength;
|
||||
uint seenSubgroupMask;
|
||||
|
||||
uvec4 owner511;
|
||||
|
||||
uint lastLaneWriterCount[32];
|
||||
uint indexedInputTotal[32];
|
||||
|
||||
vec2 rawPrefix[32];
|
||||
vec2 scanCache[6][32];
|
||||
vec2 finalAverage;
|
||||
} outWitness;
|
||||
|
||||
// Program 203's cache stays separate from all diagnostic shared state. In
|
||||
// particular, no instrumentation stores through prefixSumCache except source
|
||||
// writes retained below.
|
||||
shared vec2 prefixSumCache[32];
|
||||
shared uint canonicalNumSubgroups;
|
||||
shared uint topologyFlagsShared;
|
||||
shared uint seenSubgroupMaskShared;
|
||||
shared uint lastLaneWriterCountShared[32];
|
||||
shared uint indexedInputTotalShared[32];
|
||||
|
||||
void main() {
|
||||
const uint localInvocationIndex = gl_LocalInvocationIndex;
|
||||
|
||||
// Host memory is deliberately poisoned before dispatch. Initialize only
|
||||
// shared atomic diagnostic state; owner, average, and magic remain poisoned
|
||||
// until their required post-source-barrier writes below.
|
||||
if (localInvocationIndex == 0u) {
|
||||
canonicalNumSubgroups = 0u;
|
||||
topologyFlagsShared = 0u;
|
||||
seenSubgroupMaskShared = 0u;
|
||||
}
|
||||
if (localInvocationIndex < 32u) {
|
||||
lastLaneWriterCountShared[localInvocationIndex] = 0u;
|
||||
indexedInputTotalShared[localInvocationIndex] = 0u;
|
||||
}
|
||||
memoryBarrierShared();
|
||||
barrier();
|
||||
|
||||
// Invocation zero defines the canonical domain. It is broadcast through
|
||||
// shared memory before every invocation records its own raw observation.
|
||||
if (localInvocationIndex == 0u) {
|
||||
canonicalNumSubgroups = gl_NumSubgroups;
|
||||
outWitness.numSubgroups = gl_NumSubgroups;
|
||||
}
|
||||
barrier();
|
||||
|
||||
const uint canonicalN = canonicalNumSubgroups;
|
||||
if (gl_NumSubgroups != canonicalN)
|
||||
atomicOr(topologyFlagsShared, kTopologyNonuniformNumSubgroups);
|
||||
if (gl_NumSubgroups < 2u || gl_NumSubgroups > 32u)
|
||||
atomicOr(topologyFlagsShared, kTopologyInvalidNumSubgroups);
|
||||
if (gl_SubgroupID >= canonicalN || gl_SubgroupID >= 32u)
|
||||
atomicOr(topologyFlagsShared, kTopologyInvalidSubgroupId);
|
||||
if (gl_SubgroupSize == 0u || gl_SubgroupInvocationID >= gl_SubgroupSize)
|
||||
atomicOr(topologyFlagsShared, kTopologyInvalidSubgroupLane);
|
||||
|
||||
// Keep all atomic collection bounded by the canonical valid domain. A
|
||||
// nonuniform/broken report reaches the uniform safety branch below instead
|
||||
// of making some lanes return before a barrier.
|
||||
const bool canonicalDomain = canonicalN >= 2u && canonicalN <= 32u;
|
||||
const bool idInCanonicalDomain = canonicalDomain && gl_SubgroupID < canonicalN;
|
||||
if (idInCanonicalDomain) {
|
||||
atomicOr(seenSubgroupMaskShared, 1u << gl_SubgroupID);
|
||||
atomicAdd(indexedInputTotalShared[gl_SubgroupID], localInvocationIndex + 1u);
|
||||
if (gl_SubgroupSize != 0u && gl_SubgroupInvocationID == gl_SubgroupSize - 1u)
|
||||
atomicAdd(lastLaneWriterCountShared[gl_SubgroupID], 1u);
|
||||
}
|
||||
memoryBarrierShared();
|
||||
barrier();
|
||||
|
||||
if (localInvocationIndex == 0u)
|
||||
outWitness.seenSubgroupMask = seenSubgroupMaskShared;
|
||||
if (localInvocationIndex < 32u) {
|
||||
outWitness.lastLaneWriterCount[localInvocationIndex] = lastLaneWriterCountShared[localInvocationIndex];
|
||||
outWitness.indexedInputTotal[localInvocationIndex] = indexedInputTotalShared[localInvocationIndex];
|
||||
}
|
||||
|
||||
// This branch is uniform after collection and is solely a safety guard for
|
||||
// broken topology reports. The valid side retains Program 203 verbatim.
|
||||
const bool sourceDomain = canonicalDomain && topologyFlagsShared == 0u;
|
||||
if (sourceDomain) {
|
||||
vec2 sampleLuminance = vec2(float(gl_LocalInvocationIndex + 1u), 0.0);
|
||||
sampleLuminance = subgroupInclusiveAdd(sampleLuminance);
|
||||
|
||||
if (gl_SubgroupInvocationID == gl_SubgroupSize - 1u)
|
||||
prefixSumCache[gl_SubgroupID] = sampleLuminance;
|
||||
barrier();
|
||||
|
||||
if (gl_LocalInvocationIndex < gl_NumSubgroups)
|
||||
outWitness.rawPrefix[gl_LocalInvocationIndex] = prefixSumCache[gl_LocalInvocationIndex];
|
||||
barrier();
|
||||
|
||||
uint loopLength = uint(findMSB(gl_NumSubgroups));
|
||||
loopLength += uint(gl_NumSubgroups - (1u << (loopLength - 1u)) > 0u);
|
||||
if (gl_LocalInvocationIndex == 0u)
|
||||
outWitness.loopLength = loopLength;
|
||||
|
||||
for (uint scanStage = 0u; scanStage < loopLength; ++scanStage) {
|
||||
if ((gl_SubgroupID & (1u << scanStage)) > 0u) {
|
||||
sampleLuminance += prefixSumCache[(gl_SubgroupID >> scanStage << scanStage) - 1u];
|
||||
if (gl_SubgroupInvocationID == gl_SubgroupSize - 1u)
|
||||
prefixSumCache[gl_SubgroupID] = sampleLuminance;
|
||||
}
|
||||
barrier();
|
||||
|
||||
if (gl_LocalInvocationIndex < gl_NumSubgroups)
|
||||
outWitness.scanCache[scanStage][gl_LocalInvocationIndex] =
|
||||
prefixSumCache[gl_LocalInvocationIndex];
|
||||
// A second, diagnostic-only barrier prevents a faster invocation
|
||||
// from entering the next source stage while another reads this cache.
|
||||
barrier();
|
||||
}
|
||||
|
||||
if (gl_LocalInvocationIndex == 511u)
|
||||
prefixSumCache[0] = sampleLuminance / 512.0;
|
||||
barrier();
|
||||
|
||||
if (gl_LocalInvocationIndex == 511u) {
|
||||
outWitness.owner511 = uvec4(gl_SubgroupSize, gl_NumSubgroups, gl_SubgroupID,
|
||||
gl_SubgroupInvocationID);
|
||||
outWitness.finalAverage = prefixSumCache[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Both sides of the uniform branch reach this barrier. The magic is the
|
||||
// completion latch and therefore cannot be written before the final barrier.
|
||||
barrier();
|
||||
if (localInvocationIndex == 0u) {
|
||||
outWitness.topologyFlags = topologyFlagsShared;
|
||||
outWitness.magic = kWitnessMagic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
// MobileGL - MobileGL/MG_Util/SelfTest/DriverPostProgram203Witness.cpp
|
||||
// Copyright (c) 2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "DriverPostProgram203Witness.h"
|
||||
|
||||
#include <bit>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace MobileGL::MG_Util::SelfTest {
|
||||
namespace {
|
||||
[[nodiscard]] Program203WitnessValidationResult Failure(Program203WitnessValidationFailure failure,
|
||||
std::string detail,
|
||||
std::uint32_t scanStage = 0u,
|
||||
std::uint32_t subgroup = 0u) {
|
||||
Program203WitnessValidationResult result;
|
||||
result.ok = false;
|
||||
result.failure = failure;
|
||||
result.scanStage = scanStage;
|
||||
result.subgroup = subgroup;
|
||||
result.detail = std::move(detail);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t FloatBits(float value) {
|
||||
return std::bit_cast<std::uint32_t>(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SameBits(float lhs, float rhs) {
|
||||
return FloatBits(lhs) == FloatBits(rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool SameBits(const Program203WitnessVec2& lhs, const Program203WitnessVec2& rhs) {
|
||||
return SameBits(lhs.x, rhs.x) && SameBits(lhs.y, rhs.y);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Vec2String(const Program203WitnessVec2& value) {
|
||||
std::ostringstream output;
|
||||
output << '(' << value.x << ',' << value.y << ')';
|
||||
return output.str();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::uint32_t ExpectedSeenSubgroupMask(std::uint32_t numSubgroups) {
|
||||
return numSubgroups == kProgram203WitnessMaxSubgroups ? 0xffffffffu : (1u << numSubgroups) - 1u;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string JoinRequirements(const std::vector<std::string>& requirements) {
|
||||
std::ostringstream output;
|
||||
for (std::size_t i = 0; i < requirements.size(); ++i) {
|
||||
if (i != 0u) output << "; ";
|
||||
output << requirements[i];
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Program203WitnessEligibilityResult
|
||||
EvaluateProgram203WitnessEligibility(const Program203WitnessLimits& limits) {
|
||||
// This classification deliberately precedes numeric limits. An absent native
|
||||
// compute/basic/arithmetic subgroup contract means there is nothing to witness,
|
||||
// whereas every resource/entry-point failure on a capable device is a POST FAIL.
|
||||
if (!limits.computeStageSupported || !limits.basicSubgroupSupported || !limits.arithmeticSubgroupSupported) {
|
||||
std::vector<std::string> missing;
|
||||
if (!limits.computeStageSupported) missing.emplace_back("VK_SHADER_STAGE_COMPUTE_BIT");
|
||||
if (!limits.basicSubgroupSupported) missing.emplace_back("VK_SUBGROUP_FEATURE_BASIC_BIT");
|
||||
if (!limits.arithmeticSubgroupSupported) missing.emplace_back("VK_SUBGROUP_FEATURE_ARITHMETIC_BIT");
|
||||
return {Program203WitnessEligibility::SkipUnsupportedNativeFeatureSet,
|
||||
"skipped because the native compute/basic/arithmetic subgroup feature set is unsupported (missing " +
|
||||
JoinRequirements(missing) + ')'};
|
||||
}
|
||||
|
||||
std::vector<std::string> inadequate;
|
||||
if (limits.subgroupSize == 0u) {
|
||||
inadequate.emplace_back("subgroupSize == 0");
|
||||
}
|
||||
if (limits.maxComputeWorkGroupInvocations < kProgram203WitnessInvocationCount) {
|
||||
inadequate.emplace_back("maxComputeWorkGroupInvocations < 512");
|
||||
}
|
||||
if (limits.maxComputeWorkGroupSize[0] < 32u || limits.maxComputeWorkGroupSize[1] < 16u ||
|
||||
limits.maxComputeWorkGroupSize[2] < 1u) {
|
||||
inadequate.emplace_back("maxComputeWorkGroupSize does not cover 32x16x1");
|
||||
}
|
||||
if (limits.maxComputeSharedMemorySize < kProgram203WitnessSharedMemoryBytes) {
|
||||
inadequate.emplace_back("maxComputeSharedMemorySize < " +
|
||||
std::to_string(kProgram203WitnessSharedMemoryBytes));
|
||||
}
|
||||
if (limits.maxPerStageDescriptorStorageBuffers < 1u) {
|
||||
inadequate.emplace_back("maxPerStageDescriptorStorageBuffers < 1");
|
||||
}
|
||||
if (limits.maxDescriptorSetStorageBuffers < 1u) {
|
||||
inadequate.emplace_back("maxDescriptorSetStorageBuffers < 1");
|
||||
}
|
||||
if (limits.maxBoundDescriptorSets < 1u) {
|
||||
inadequate.emplace_back("maxBoundDescriptorSets < 1");
|
||||
}
|
||||
if (limits.maxStorageBufferRange < sizeof(Program203WitnessOutput)) {
|
||||
inadequate.emplace_back("maxStorageBufferRange < " +
|
||||
std::to_string(sizeof(Program203WitnessOutput)));
|
||||
}
|
||||
if (!inadequate.empty()) {
|
||||
return {Program203WitnessEligibility::FailInadequateLimits,
|
||||
"insufficient Vulkan limits for a 32x16x1 workgroup, one output SSBO, and " +
|
||||
std::to_string(kProgram203WitnessSharedMemoryBytes) + " bytes of shared memory: " +
|
||||
JoinRequirements(inadequate)};
|
||||
}
|
||||
return {Program203WitnessEligibility::Execute, {}};
|
||||
}
|
||||
|
||||
std::uint32_t ComputeProgram203WitnessLoopLength(std::uint32_t numSubgroups) {
|
||||
if (numSubgroups < 2u || numSubgroups > kProgram203WitnessMaxSubgroups) return 0u;
|
||||
|
||||
// Exact C++ spelling of the source's findMSB-based calculation. In
|
||||
// particular, its final iteration for powers of two is intentional.
|
||||
std::uint32_t loopLength = 0u;
|
||||
for (std::uint32_t value = numSubgroups; value > 1u; value >>= 1u) {
|
||||
++loopLength;
|
||||
}
|
||||
loopLength += static_cast<std::uint32_t>(numSubgroups - (1u << (loopLength - 1u)) > 0u);
|
||||
return loopLength;
|
||||
}
|
||||
|
||||
Program203WitnessValidationResult ValidateProgram203Witness(const Program203WitnessOutput& output) {
|
||||
// 1. Completion. A poisoned or unwritten result must never turn into a
|
||||
// topology diagnosis, because it says nothing about execution.
|
||||
if (output.magic != kProgram203WitnessMagic) {
|
||||
std::ostringstream detail;
|
||||
detail << "completion: magic was 0x" << std::hex << output.magic << ", expected 0x"
|
||||
<< kProgram203WitnessMagic;
|
||||
return Failure(Program203WitnessValidationFailure::Completion, detail.str());
|
||||
}
|
||||
|
||||
// 2. Observed topology. All checks consume observations written by the
|
||||
// shader, rather than inferring subgroup layout from invocation indices.
|
||||
const std::uint32_t numSubgroups = output.numSubgroups;
|
||||
if (numSubgroups < 2u || numSubgroups > kProgram203WitnessMaxSubgroups) {
|
||||
std::ostringstream detail;
|
||||
detail << "topology: canonical gl_NumSubgroups=" << numSubgroups << " is outside [2, 32]";
|
||||
return Failure(Program203WitnessValidationFailure::Topology, detail.str());
|
||||
}
|
||||
if ((output.topologyFlags & Program203WitnessNonuniformNumSubgroups) != 0u) {
|
||||
return Failure(Program203WitnessValidationFailure::Topology,
|
||||
"topology: gl_NumSubgroups differed across workgroup");
|
||||
}
|
||||
if ((output.topologyFlags & Program203WitnessInvalidNumSubgroups) != 0u) {
|
||||
return Failure(Program203WitnessValidationFailure::Topology,
|
||||
"topology: an invocation reported gl_NumSubgroups outside [2, 32]");
|
||||
}
|
||||
if ((output.topologyFlags & Program203WitnessInvalidSubgroupId) != 0u) {
|
||||
return Failure(Program203WitnessValidationFailure::Topology,
|
||||
"topology: an invocation reported an invalid gl_SubgroupID");
|
||||
}
|
||||
if ((output.topologyFlags & Program203WitnessInvalidSubgroupLane) != 0u) {
|
||||
return Failure(Program203WitnessValidationFailure::Topology,
|
||||
"topology: an invocation reported an invalid subgroup lane");
|
||||
}
|
||||
if ((output.topologyFlags & ~(Program203WitnessNonuniformNumSubgroups |
|
||||
Program203WitnessInvalidNumSubgroups |
|
||||
Program203WitnessInvalidSubgroupId |
|
||||
Program203WitnessInvalidSubgroupLane)) != 0u) {
|
||||
std::ostringstream detail;
|
||||
detail << "topology: unknown topology flags 0x" << std::hex << output.topologyFlags;
|
||||
return Failure(Program203WitnessValidationFailure::Topology, detail.str());
|
||||
}
|
||||
const std::uint32_t expectedMask = ExpectedSeenSubgroupMask(numSubgroups);
|
||||
if (output.seenSubgroupMask != expectedMask) {
|
||||
std::ostringstream detail;
|
||||
detail << "topology: seen subgroup-ID mask was 0x" << std::hex << output.seenSubgroupMask
|
||||
<< ", expected 0x" << expectedMask;
|
||||
return Failure(Program203WitnessValidationFailure::Topology, detail.str());
|
||||
}
|
||||
const std::uint32_t expectedLoopLength = ComputeProgram203WitnessLoopLength(numSubgroups);
|
||||
if (output.loopLength != expectedLoopLength) {
|
||||
std::ostringstream detail;
|
||||
detail << "topology: loopLength was " << std::dec << output.loopLength << ", expected "
|
||||
<< expectedLoopLength;
|
||||
return Failure(Program203WitnessValidationFailure::Topology, detail.str());
|
||||
}
|
||||
for (std::uint32_t subgroup = 0u; subgroup < numSubgroups; ++subgroup) {
|
||||
if (output.lastLaneWriterCount[subgroup] != 1u) {
|
||||
std::ostringstream detail;
|
||||
detail << "topology: subgroup " << subgroup << " has "
|
||||
<< output.lastLaneWriterCount[subgroup] << " source last-lane writers, expected exactly 1";
|
||||
return Failure(Program203WitnessValidationFailure::Topology, detail.str(), 0u, subgroup);
|
||||
}
|
||||
}
|
||||
if (output.owner511.y != numSubgroups) {
|
||||
std::ostringstream detail;
|
||||
detail << "final owner: invocation 511 reported gl_NumSubgroups=" << output.owner511.y << ", expected "
|
||||
<< numSubgroups;
|
||||
return Failure(Program203WitnessValidationFailure::FinalOwner, detail.str());
|
||||
}
|
||||
if (output.owner511.z != numSubgroups - 1u) {
|
||||
std::ostringstream detail;
|
||||
detail << "final owner: invocation 511 is not in the highest subgroup (id" << output.owner511.z
|
||||
<< ", expected id" << (numSubgroups - 1u) << ')';
|
||||
return Failure(Program203WitnessValidationFailure::FinalOwner, detail.str());
|
||||
}
|
||||
if (output.owner511.x == 0u || output.owner511.w != output.owner511.x - 1u) {
|
||||
std::ostringstream detail;
|
||||
detail << "final owner: invocation 511 is not the last lane of highest subgroup (size "
|
||||
<< output.owner511.x << ", lane " << output.owner511.w << ')';
|
||||
return Failure(Program203WitnessValidationFailure::FinalOwner, detail.str());
|
||||
}
|
||||
|
||||
// 3. Initial subgroup handoff. The atomic scalar totals are independent
|
||||
// of subgroupInclusiveAdd; their sum and the cache values establish that
|
||||
// the final lanes handed off the native vector inclusive-add results.
|
||||
std::uint64_t indexedTotal = 0u;
|
||||
for (std::uint32_t subgroup = 0u; subgroup < numSubgroups; ++subgroup) {
|
||||
indexedTotal += output.indexedInputTotal[subgroup];
|
||||
}
|
||||
if (indexedTotal != 131328u) {
|
||||
std::ostringstream detail;
|
||||
detail << "initial subgroup handoff: indexed input total was " << indexedTotal << ", expected 131328";
|
||||
return Failure(Program203WitnessValidationFailure::InitialSubgroupHandoff, detail.str());
|
||||
}
|
||||
for (std::uint32_t subgroup = 0u; subgroup < numSubgroups; ++subgroup) {
|
||||
const Program203WitnessVec2 expected = {static_cast<float>(output.indexedInputTotal[subgroup]), 0.0f};
|
||||
if (!SameBits(output.rawPrefix[subgroup], expected)) {
|
||||
std::ostringstream detail;
|
||||
detail << "initial subgroup handoff: subgroup " << subgroup << " rawPrefix observed "
|
||||
<< Vec2String(output.rawPrefix[subgroup]) << ", expected " << Vec2String(expected);
|
||||
return Failure(Program203WitnessValidationFailure::InitialSubgroupHandoff, detail.str(), 0u,
|
||||
subgroup);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Source scan. Do not substitute a conventional scan: this reproduces
|
||||
// the source cache index expression and stage ordering word for word.
|
||||
std::array<Program203WitnessVec2, kProgram203WitnessMaxSubgroups> expectedCache = output.rawPrefix;
|
||||
for (std::uint32_t scanStage = 0u; scanStage < expectedLoopLength; ++scanStage) {
|
||||
auto cacheAfterStage = expectedCache;
|
||||
for (std::uint32_t subgroup = 0u; subgroup < numSubgroups; ++subgroup) {
|
||||
if ((subgroup & (1u << scanStage)) > 0u) {
|
||||
const std::uint32_t sourceCacheIndex = (subgroup >> scanStage << scanStage) - 1u;
|
||||
cacheAfterStage[subgroup].x += expectedCache[sourceCacheIndex].x;
|
||||
cacheAfterStage[subgroup].y += expectedCache[sourceCacheIndex].y;
|
||||
}
|
||||
}
|
||||
expectedCache = cacheAfterStage;
|
||||
for (std::uint32_t subgroup = 0u; subgroup < numSubgroups; ++subgroup) {
|
||||
if (!SameBits(output.scanCache[scanStage][subgroup], expectedCache[subgroup])) {
|
||||
std::ostringstream detail;
|
||||
detail << "source scan stage " << scanStage << ", subgroup " << subgroup << ": observed "
|
||||
<< Vec2String(output.scanCache[scanStage][subgroup]) << ", expected "
|
||||
<< Vec2String(expectedCache[subgroup]);
|
||||
return Failure(Program203WitnessValidationFailure::SourceScan, detail.str(), scanStage, subgroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. The owner contract was checked above with the other topology facts;
|
||||
// this final result remains a separate exact-vector check.
|
||||
const Program203WitnessVec2 expectedAverage = {256.5f, 0.0f};
|
||||
if (!SameBits(output.finalAverage, expectedAverage)) {
|
||||
std::ostringstream detail;
|
||||
detail << "final average: observed " << Vec2String(output.finalAverage) << ", expected "
|
||||
<< Vec2String(expectedAverage);
|
||||
return Failure(Program203WitnessValidationFailure::FinalAverage, detail.str());
|
||||
}
|
||||
|
||||
std::ostringstream detail;
|
||||
detail << "N=" << numSubgroups << ", owner511=id" << output.owner511.z << "/lane" << output.owner511.w
|
||||
<< ", " << expectedLoopLength << " scan stages, average=" << Vec2String(output.finalAverage);
|
||||
Program203WitnessValidationResult result;
|
||||
result.ok = true;
|
||||
result.failure = Program203WitnessValidationFailure::None;
|
||||
result.detail = detail.str();
|
||||
return result;
|
||||
}
|
||||
} // namespace MobileGL::MG_Util::SelfTest
|
||||
@@ -0,0 +1,151 @@
|
||||
// MobileGL - MobileGL/MG_Util/SelfTest/DriverPostProgram203Witness.h
|
||||
// Copyright (c) 2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
//
|
||||
// Compact, native-Vulkan Program-203 first-reduction witness ABI and its pure
|
||||
// validator. The types below deliberately mirror DriverPostProgram203Witness.comp's
|
||||
// single std430 storage block; changing either side requires updating the static
|
||||
// layout assertions here.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace MobileGL::MG_Util::SelfTest {
|
||||
constexpr std::uint32_t kProgram203WitnessMagic = 0x50323033u; // "P203"
|
||||
constexpr std::uint32_t kProgram203WitnessInvocationCount = 512u;
|
||||
constexpr std::uint32_t kProgram203WitnessMaxSubgroups = 32u;
|
||||
constexpr std::uint32_t kProgram203WitnessMaxScanStages = 6u;
|
||||
|
||||
// These bit values are shared with the GLSL source. They document failures in
|
||||
// topology observations rather than guessing a topology from local IDs on the host.
|
||||
enum Program203WitnessTopologyFlag : std::uint32_t {
|
||||
Program203WitnessNonuniformNumSubgroups = 1u << 0u,
|
||||
Program203WitnessInvalidNumSubgroups = 1u << 1u,
|
||||
Program203WitnessInvalidSubgroupId = 1u << 2u,
|
||||
Program203WitnessInvalidSubgroupLane = 1u << 3u,
|
||||
};
|
||||
|
||||
struct alignas(8) Program203WitnessVec2 {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct alignas(16) Program203WitnessUVec4 {
|
||||
std::uint32_t x;
|
||||
std::uint32_t y;
|
||||
std::uint32_t z;
|
||||
std::uint32_t w;
|
||||
};
|
||||
|
||||
// std430 layout of DriverPostProgram203Witness.comp's Program203WitnessOutput block.
|
||||
struct alignas(16) Program203WitnessOutput {
|
||||
std::uint32_t magic;
|
||||
std::uint32_t topologyFlags;
|
||||
std::uint32_t numSubgroups;
|
||||
std::uint32_t loopLength;
|
||||
std::uint32_t seenSubgroupMask;
|
||||
|
||||
Program203WitnessUVec4 owner511;
|
||||
|
||||
std::array<std::uint32_t, kProgram203WitnessMaxSubgroups> lastLaneWriterCount;
|
||||
std::array<std::uint32_t, kProgram203WitnessMaxSubgroups> indexedInputTotal;
|
||||
|
||||
std::array<Program203WitnessVec2, kProgram203WitnessMaxSubgroups> rawPrefix;
|
||||
std::array<std::array<Program203WitnessVec2, kProgram203WitnessMaxSubgroups>,
|
||||
kProgram203WitnessMaxScanStages>
|
||||
scanCache;
|
||||
Program203WitnessVec2 finalAverage;
|
||||
};
|
||||
|
||||
static_assert(std::is_standard_layout_v<Program203WitnessVec2>);
|
||||
static_assert(std::is_standard_layout_v<Program203WitnessUVec4>);
|
||||
static_assert(std::is_standard_layout_v<Program203WitnessOutput>);
|
||||
static_assert(sizeof(Program203WitnessVec2) == 8u);
|
||||
static_assert(alignof(Program203WitnessVec2) == 8u);
|
||||
static_assert(sizeof(Program203WitnessUVec4) == 16u);
|
||||
static_assert(alignof(Program203WitnessUVec4) == 16u);
|
||||
static_assert(offsetof(Program203WitnessOutput, magic) == 0u);
|
||||
static_assert(offsetof(Program203WitnessOutput, topologyFlags) == 4u);
|
||||
static_assert(offsetof(Program203WitnessOutput, numSubgroups) == 8u);
|
||||
static_assert(offsetof(Program203WitnessOutput, loopLength) == 12u);
|
||||
static_assert(offsetof(Program203WitnessOutput, seenSubgroupMask) == 16u);
|
||||
static_assert(offsetof(Program203WitnessOutput, owner511) == 32u);
|
||||
static_assert(offsetof(Program203WitnessOutput, lastLaneWriterCount) == 48u);
|
||||
static_assert(offsetof(Program203WitnessOutput, indexedInputTotal) == 176u);
|
||||
static_assert(offsetof(Program203WitnessOutput, rawPrefix) == 304u);
|
||||
static_assert(offsetof(Program203WitnessOutput, scanCache) == 560u);
|
||||
static_assert(offsetof(Program203WitnessOutput, finalAverage) == 2096u);
|
||||
static_assert(sizeof(Program203WitnessOutput) == 2112u);
|
||||
|
||||
// The witness uses prefixSumCache[32], three scalar shared diagnostics, and
|
||||
// two 32-entry scalar diagnostic arrays in the GLSL source. Keep this
|
||||
// independent of the output SSBO size.
|
||||
constexpr std::uint32_t kProgram203WitnessSharedMemoryBytes =
|
||||
kProgram203WitnessMaxSubgroups * sizeof(Program203WitnessVec2) +
|
||||
3u * sizeof(std::uint32_t) +
|
||||
2u * kProgram203WitnessMaxSubgroups * sizeof(std::uint32_t);
|
||||
|
||||
enum class Program203WitnessEligibility {
|
||||
Execute,
|
||||
SkipUnsupportedNativeFeatureSet,
|
||||
FailInadequateLimits,
|
||||
};
|
||||
|
||||
// The raw physical-device conditions needed by the native witness. This is
|
||||
// intentionally distinct from MobileGL's advertised-extension policy.
|
||||
struct Program203WitnessLimits {
|
||||
bool computeStageSupported = false;
|
||||
bool basicSubgroupSupported = false;
|
||||
bool arithmeticSubgroupSupported = false;
|
||||
std::uint32_t subgroupSize = 0u;
|
||||
|
||||
std::uint32_t maxComputeWorkGroupInvocations = 0u;
|
||||
std::array<std::uint32_t, 3> maxComputeWorkGroupSize{};
|
||||
std::uint32_t maxComputeSharedMemorySize = 0u;
|
||||
std::uint32_t maxPerStageDescriptorStorageBuffers = 0u;
|
||||
std::uint32_t maxDescriptorSetStorageBuffers = 0u;
|
||||
std::uint32_t maxBoundDescriptorSets = 0u;
|
||||
std::uint64_t maxStorageBufferRange = 0u;
|
||||
};
|
||||
|
||||
struct Program203WitnessEligibilityResult {
|
||||
Program203WitnessEligibility eligibility = Program203WitnessEligibility::FailInadequateLimits;
|
||||
std::string detail;
|
||||
};
|
||||
|
||||
enum class Program203WitnessValidationFailure {
|
||||
None,
|
||||
Completion,
|
||||
Topology,
|
||||
InitialSubgroupHandoff,
|
||||
SourceScan,
|
||||
FinalOwner,
|
||||
FinalAverage,
|
||||
};
|
||||
|
||||
struct Program203WitnessValidationResult {
|
||||
bool ok = false;
|
||||
Program203WitnessValidationFailure failure = Program203WitnessValidationFailure::Completion;
|
||||
std::uint32_t scanStage = 0u;
|
||||
std::uint32_t subgroup = 0u;
|
||||
std::string detail;
|
||||
};
|
||||
|
||||
[[nodiscard]] Program203WitnessEligibilityResult
|
||||
EvaluateProgram203WitnessEligibility(const Program203WitnessLimits& limits);
|
||||
|
||||
// Mirrors the source's findMSB expression for valid N in [2, 32].
|
||||
[[nodiscard]] std::uint32_t ComputeProgram203WitnessLoopLength(std::uint32_t numSubgroups);
|
||||
|
||||
[[nodiscard]] Program203WitnessValidationResult
|
||||
ValidateProgram203Witness(const Program203WitnessOutput& output);
|
||||
} // namespace MobileGL::MG_Util::SelfTest
|
||||
@@ -0,0 +1,291 @@
|
||||
// MobileGL - MobileGL/MG_Util/SelfTest/DriverPostProgram203WitnessSpv.h
|
||||
// Copyright (c) 2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
//
|
||||
// Generated from DriverPostProgram203Witness.comp with:
|
||||
// glslangValidator --target-env vulkan1.1 -V DriverPostProgram203Witness.comp
|
||||
// Validated with spirv-val --target-env vulkan1.1. Do not edit words by hand.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace MobileGL::MG_Util::SelfTest {
|
||||
inline constexpr std::uint32_t kDriverPostProgram203WitnessSpv[] = {
|
||||
0x07230203u, 0x00010300u, 0x0008000bu, 0x00000145u, 0x00000000u, 0x00020011u, 0x00000001u, 0x00020011u,
|
||||
0x0000003du, 0x00020011u, 0x0000003fu, 0x0006000bu, 0x00000001u, 0x4c534c47u, 0x6474732eu, 0x3035342eu,
|
||||
0x00000000u, 0x0003000eu, 0x00000000u, 0x00000001u, 0x000a000fu, 0x00000005u, 0x00000004u, 0x6e69616du,
|
||||
0x00000000u, 0x0000000au, 0x0000002au, 0x00000050u, 0x0000005eu, 0x00000064u, 0x00060010u, 0x00000004u,
|
||||
0x00000011u, 0x00000020u, 0x00000010u, 0x00000001u, 0x00030003u, 0x00000002u, 0x000001c2u, 0x000a0004u,
|
||||
0x4b5f4c47u, 0x735f5248u, 0x65646168u, 0x75735f72u, 0x6f726762u, 0x615f7075u, 0x68746972u, 0x6974656du,
|
||||
0x00000063u, 0x00090004u, 0x4b5f4c47u, 0x735f5248u, 0x65646168u, 0x75735f72u, 0x6f726762u, 0x625f7075u,
|
||||
0x63697361u, 0x00000000u, 0x00040005u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x00080005u, 0x00000008u,
|
||||
0x61636f6cu, 0x766e496cu, 0x7461636fu, 0x496e6f69u, 0x7865646eu, 0x00000000u, 0x00080005u, 0x0000000au,
|
||||
0x4c5f6c67u, 0x6c61636fu, 0x6f766e49u, 0x69746163u, 0x6e496e6fu, 0x00786564u, 0x00080005u, 0x00000013u,
|
||||
0x6f6e6163u, 0x6163696eu, 0x6d754e6cu, 0x67627553u, 0x70756f72u, 0x00000073u, 0x00070005u, 0x00000014u,
|
||||
0x6f706f74u, 0x79676f6cu, 0x67616c46u, 0x61685373u, 0x00646572u, 0x00080005u, 0x00000015u, 0x6e656573u,
|
||||
0x67627553u, 0x70756f72u, 0x6b73614du, 0x72616853u, 0x00006465u, 0x00090005u, 0x0000001du, 0x7473616cu,
|
||||
0x656e614cu, 0x74697257u, 0x6f437265u, 0x53746e75u, 0x65726168u, 0x00000064u, 0x00080005u, 0x00000020u,
|
||||
0x65646e69u, 0x49646578u, 0x7475706eu, 0x61746f54u, 0x6168536cu, 0x00646572u, 0x00060005u, 0x0000002au,
|
||||
0x4e5f6c67u, 0x75536d75u, 0x6f726762u, 0x00737075u, 0x00080005u, 0x00000035u, 0x676f7250u, 0x326d6172u,
|
||||
0x69573330u, 0x73656e74u, 0x74754f73u, 0x00747570u, 0x00050006u, 0x00000035u, 0x00000000u, 0x6967616du,
|
||||
0x00000063u, 0x00070006u, 0x00000035u, 0x00000001u, 0x6f706f74u, 0x79676f6cu, 0x67616c46u, 0x00000073u,
|
||||
0x00070006u, 0x00000035u, 0x00000002u, 0x536d756eu, 0x72676275u, 0x7370756fu, 0x00000000u, 0x00060006u,
|
||||
0x00000035u, 0x00000003u, 0x706f6f6cu, 0x676e654cu, 0x00006874u, 0x00080006u, 0x00000035u, 0x00000004u,
|
||||
0x6e656573u, 0x67627553u, 0x70756f72u, 0x6b73614du, 0x00000000u, 0x00060006u, 0x00000035u, 0x00000005u,
|
||||
0x656e776fu, 0x31313572u, 0x00000000u, 0x00080006u, 0x00000035u, 0x00000006u, 0x7473616cu, 0x656e614cu,
|
||||
0x74697257u, 0x6f437265u, 0x00746e75u, 0x00080006u, 0x00000035u, 0x00000007u, 0x65646e69u, 0x49646578u,
|
||||
0x7475706eu, 0x61746f54u, 0x0000006cu, 0x00060006u, 0x00000035u, 0x00000008u, 0x50776172u, 0x69666572u,
|
||||
0x00000078u, 0x00060006u, 0x00000035u, 0x00000009u, 0x6e616373u, 0x68636143u, 0x00000065u, 0x00070006u,
|
||||
0x00000035u, 0x0000000au, 0x616e6966u, 0x6576416cu, 0x65676172u, 0x00000000u, 0x00050005u, 0x00000037u,
|
||||
0x5774756fu, 0x656e7469u, 0x00007373u, 0x00050005u, 0x0000003du, 0x6f6e6163u, 0x6163696eu, 0x00004e6cu,
|
||||
0x00060005u, 0x00000050u, 0x535f6c67u, 0x72676275u, 0x4970756fu, 0x00000044u, 0x00060005u, 0x0000005eu,
|
||||
0x535f6c67u, 0x72676275u, 0x5370756fu, 0x00657a69u, 0x00080005u, 0x00000064u, 0x535f6c67u, 0x72676275u,
|
||||
0x4970756fu, 0x636f766eu, 0x6f697461u, 0x0044496eu, 0x00060005u, 0x0000006eu, 0x6f6e6163u, 0x6163696eu,
|
||||
0x6d6f446cu, 0x006e6961u, 0x00070005u, 0x00000074u, 0x6e496469u, 0x6f6e6143u, 0x6163696eu, 0x6d6f446cu,
|
||||
0x006e6961u, 0x00060005u, 0x000000acu, 0x72756f73u, 0x6f446563u, 0x6e69616du, 0x00000000u, 0x00060005u,
|
||||
0x000000b7u, 0x706d6173u, 0x754c656cu, 0x616e696du, 0x0065636eu, 0x00060005u, 0x000000c8u, 0x66657270u,
|
||||
0x75537869u, 0x6361436du, 0x00006568u, 0x00050005u, 0x000000d9u, 0x706f6f6cu, 0x676e654cu, 0x00006874u,
|
||||
0x00050005u, 0x000000edu, 0x6e616373u, 0x67617453u, 0x00000065u, 0x00040047u, 0x0000000au, 0x0000000bu,
|
||||
0x0000001du, 0x00040047u, 0x0000002au, 0x0000000bu, 0x00000026u, 0x00040047u, 0x0000002du, 0x00000006u,
|
||||
0x00000004u, 0x00040047u, 0x0000002eu, 0x00000006u, 0x00000004u, 0x00040047u, 0x00000031u, 0x00000006u,
|
||||
0x00000008u, 0x00040047u, 0x00000032u, 0x00000006u, 0x00000008u, 0x00040047u, 0x00000034u, 0x00000006u,
|
||||
0x00000100u, 0x00030047u, 0x00000035u, 0x00000002u, 0x00050048u, 0x00000035u, 0x00000000u, 0x00000023u,
|
||||
0x00000000u, 0x00050048u, 0x00000035u, 0x00000001u, 0x00000023u, 0x00000004u, 0x00050048u, 0x00000035u,
|
||||
0x00000002u, 0x00000023u, 0x00000008u, 0x00050048u, 0x00000035u, 0x00000003u, 0x00000023u, 0x0000000cu,
|
||||
0x00050048u, 0x00000035u, 0x00000004u, 0x00000023u, 0x00000010u, 0x00050048u, 0x00000035u, 0x00000005u,
|
||||
0x00000023u, 0x00000020u, 0x00050048u, 0x00000035u, 0x00000006u, 0x00000023u, 0x00000030u, 0x00050048u,
|
||||
0x00000035u, 0x00000007u, 0x00000023u, 0x000000b0u, 0x00050048u, 0x00000035u, 0x00000008u, 0x00000023u,
|
||||
0x00000130u, 0x00050048u, 0x00000035u, 0x00000009u, 0x00000023u, 0x00000230u, 0x00050048u, 0x00000035u,
|
||||
0x0000000au, 0x00000023u, 0x00000830u, 0x00040047u, 0x00000037u, 0x00000021u, 0x00000000u, 0x00040047u,
|
||||
0x00000037u, 0x00000022u, 0x00000000u, 0x00040047u, 0x00000050u, 0x0000000bu, 0x00000028u, 0x00030047u,
|
||||
0x0000005eu, 0x00000000u, 0x00040047u, 0x0000005eu, 0x0000000bu, 0x00000024u, 0x00030047u, 0x0000005fu,
|
||||
0x00000000u, 0x00030047u, 0x00000064u, 0x00000000u, 0x00040047u, 0x00000064u, 0x0000000bu, 0x00000029u,
|
||||
0x00030047u, 0x00000065u, 0x00000000u, 0x00030047u, 0x00000066u, 0x00000000u, 0x00030047u, 0x00000087u,
|
||||
0x00000000u, 0x00030047u, 0x0000008bu, 0x00000000u, 0x00030047u, 0x0000008cu, 0x00000000u, 0x00030047u,
|
||||
0x0000008du, 0x00000000u, 0x00030047u, 0x000000c0u, 0x00000000u, 0x00030047u, 0x000000c1u, 0x00000000u,
|
||||
0x00030047u, 0x000000c2u, 0x00000000u, 0x00030047u, 0x00000107u, 0x00000000u, 0x00030047u, 0x00000108u,
|
||||
0x00000000u, 0x00030047u, 0x00000109u, 0x00000000u, 0x00030047u, 0x0000012fu, 0x00000000u, 0x00030047u,
|
||||
0x00000132u, 0x00000000u, 0x00040047u, 0x00000144u, 0x0000000bu, 0x00000019u, 0x00020013u, 0x00000002u,
|
||||
0x00030021u, 0x00000003u, 0x00000002u, 0x00040015u, 0x00000006u, 0x00000020u, 0x00000000u, 0x00040020u,
|
||||
0x00000007u, 0x00000007u, 0x00000006u, 0x00040020u, 0x00000009u, 0x00000001u, 0x00000006u, 0x0004003bu,
|
||||
0x00000009u, 0x0000000au, 0x00000001u, 0x0004002bu, 0x00000006u, 0x0000000du, 0x00000000u, 0x00020014u,
|
||||
0x0000000eu, 0x00040020u, 0x00000012u, 0x00000004u, 0x00000006u, 0x0004003bu, 0x00000012u, 0x00000013u,
|
||||
0x00000004u, 0x0004003bu, 0x00000012u, 0x00000014u, 0x00000004u, 0x0004003bu, 0x00000012u, 0x00000015u,
|
||||
0x00000004u, 0x0004002bu, 0x00000006u, 0x00000017u, 0x00000020u, 0x0004001cu, 0x0000001bu, 0x00000006u,
|
||||
0x00000017u, 0x00040020u, 0x0000001cu, 0x00000004u, 0x0000001bu, 0x0004003bu, 0x0000001cu, 0x0000001du,
|
||||
0x00000004u, 0x0004003bu, 0x0000001cu, 0x00000020u, 0x00000004u, 0x0004002bu, 0x00000006u, 0x00000023u,
|
||||
0x00000001u, 0x0004002bu, 0x00000006u, 0x00000024u, 0x00000108u, 0x0004002bu, 0x00000006u, 0x00000025u,
|
||||
0x00000002u, 0x0004003bu, 0x00000009u, 0x0000002au, 0x00000001u, 0x00040017u, 0x0000002cu, 0x00000006u,
|
||||
0x00000004u, 0x0004001cu, 0x0000002du, 0x00000006u, 0x00000017u, 0x0004001cu, 0x0000002eu, 0x00000006u,
|
||||
0x00000017u, 0x00030016u, 0x0000002fu, 0x00000020u, 0x00040017u, 0x00000030u, 0x0000002fu, 0x00000002u,
|
||||
0x0004001cu, 0x00000031u, 0x00000030u, 0x00000017u, 0x0004001cu, 0x00000032u, 0x00000030u, 0x00000017u,
|
||||
0x0004002bu, 0x00000006u, 0x00000033u, 0x00000006u, 0x0004001cu, 0x00000034u, 0x00000032u, 0x00000033u,
|
||||
0x000d001eu, 0x00000035u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x00000006u, 0x0000002cu,
|
||||
0x0000002du, 0x0000002eu, 0x00000031u, 0x00000034u, 0x00000030u, 0x00040020u, 0x00000036u, 0x0000000cu,
|
||||
0x00000035u, 0x0004003bu, 0x00000036u, 0x00000037u, 0x0000000cu, 0x00040015u, 0x00000038u, 0x00000020u,
|
||||
0x00000001u, 0x0004002bu, 0x00000038u, 0x00000039u, 0x00000002u, 0x00040020u, 0x0000003bu, 0x0000000cu,
|
||||
0x00000006u, 0x0004003bu, 0x00000009u, 0x00000050u, 0x00000001u, 0x0004002bu, 0x00000006u, 0x0000005cu,
|
||||
0x00000004u, 0x0004003bu, 0x00000009u, 0x0000005eu, 0x00000001u, 0x0004003bu, 0x00000009u, 0x00000064u,
|
||||
0x00000001u, 0x0004002bu, 0x00000006u, 0x0000006bu, 0x00000008u, 0x00040020u, 0x0000006du, 0x00000007u,
|
||||
0x0000000eu, 0x0004002bu, 0x00000038u, 0x00000099u, 0x00000004u, 0x0004002bu, 0x00000038u, 0x000000a0u,
|
||||
0x00000006u, 0x0004002bu, 0x00000038u, 0x000000a6u, 0x00000007u, 0x00040020u, 0x000000b6u, 0x00000007u,
|
||||
0x00000030u, 0x0004002bu, 0x0000002fu, 0x000000bbu, 0x00000000u, 0x0004002bu, 0x00000006u, 0x000000beu,
|
||||
0x00000003u, 0x0004001cu, 0x000000c6u, 0x00000030u, 0x00000017u, 0x00040020u, 0x000000c7u, 0x00000004u,
|
||||
0x000000c6u, 0x0004003bu, 0x000000c7u, 0x000000c8u, 0x00000004u, 0x00040020u, 0x000000cbu, 0x00000004u,
|
||||
0x00000030u, 0x0004002bu, 0x00000038u, 0x000000d2u, 0x00000008u, 0x00040020u, 0x000000d7u, 0x0000000cu,
|
||||
0x00000030u, 0x0004002bu, 0x00000038u, 0x000000eau, 0x00000003u, 0x0004002bu, 0x00000038u, 0x00000115u,
|
||||
0x00000009u, 0x0004002bu, 0x00000038u, 0x0000011du, 0x00000001u, 0x0004002bu, 0x00000006u, 0x00000120u,
|
||||
0x000001ffu, 0x0004002bu, 0x00000038u, 0x00000124u, 0x00000000u, 0x0004002bu, 0x0000002fu, 0x00000126u,
|
||||
0x44000000u, 0x0004002bu, 0x00000038u, 0x0000012eu, 0x00000005u, 0x00040020u, 0x00000134u, 0x0000000cu,
|
||||
0x0000002cu, 0x0004002bu, 0x00000038u, 0x00000136u, 0x0000000au, 0x0004002bu, 0x00000006u, 0x00000140u,
|
||||
0x50323033u, 0x00040017u, 0x00000142u, 0x00000006u, 0x00000003u, 0x0004002bu, 0x00000006u, 0x00000143u,
|
||||
0x00000010u, 0x0006002cu, 0x00000142u, 0x00000144u, 0x00000017u, 0x00000143u, 0x00000023u, 0x00050036u,
|
||||
0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200f8u, 0x00000005u, 0x0004003bu, 0x00000007u,
|
||||
0x00000008u, 0x00000007u, 0x0004003bu, 0x00000007u, 0x0000003du, 0x00000007u, 0x0004003bu, 0x0000006du,
|
||||
0x0000006eu, 0x00000007u, 0x0004003bu, 0x0000006du, 0x00000074u, 0x00000007u, 0x0004003bu, 0x0000006du,
|
||||
0x000000acu, 0x00000007u, 0x0004003bu, 0x000000b6u, 0x000000b7u, 0x00000007u, 0x0004003bu, 0x00000007u,
|
||||
0x000000d9u, 0x00000007u, 0x0004003bu, 0x00000007u, 0x000000edu, 0x00000007u, 0x0004003du, 0x00000006u,
|
||||
0x0000000bu, 0x0000000au, 0x0003003eu, 0x00000008u, 0x0000000bu, 0x0004003du, 0x00000006u, 0x0000000cu,
|
||||
0x00000008u, 0x000500aau, 0x0000000eu, 0x0000000fu, 0x0000000cu, 0x0000000du, 0x000300f7u, 0x00000011u,
|
||||
0x00000000u, 0x000400fau, 0x0000000fu, 0x00000010u, 0x00000011u, 0x000200f8u, 0x00000010u, 0x0003003eu,
|
||||
0x00000013u, 0x0000000du, 0x0003003eu, 0x00000014u, 0x0000000du, 0x0003003eu, 0x00000015u, 0x0000000du,
|
||||
0x000200f9u, 0x00000011u, 0x000200f8u, 0x00000011u, 0x0004003du, 0x00000006u, 0x00000016u, 0x00000008u,
|
||||
0x000500b0u, 0x0000000eu, 0x00000018u, 0x00000016u, 0x00000017u, 0x000300f7u, 0x0000001au, 0x00000000u,
|
||||
0x000400fau, 0x00000018u, 0x00000019u, 0x0000001au, 0x000200f8u, 0x00000019u, 0x0004003du, 0x00000006u,
|
||||
0x0000001eu, 0x00000008u, 0x00050041u, 0x00000012u, 0x0000001fu, 0x0000001du, 0x0000001eu, 0x0003003eu,
|
||||
0x0000001fu, 0x0000000du, 0x0004003du, 0x00000006u, 0x00000021u, 0x00000008u, 0x00050041u, 0x00000012u,
|
||||
0x00000022u, 0x00000020u, 0x00000021u, 0x0003003eu, 0x00000022u, 0x0000000du, 0x000200f9u, 0x0000001au,
|
||||
0x000200f8u, 0x0000001au, 0x000300e1u, 0x00000023u, 0x00000024u, 0x000400e0u, 0x00000025u, 0x00000025u,
|
||||
0x00000024u, 0x0004003du, 0x00000006u, 0x00000026u, 0x00000008u, 0x000500aau, 0x0000000eu, 0x00000027u,
|
||||
0x00000026u, 0x0000000du, 0x000300f7u, 0x00000029u, 0x00000000u, 0x000400fau, 0x00000027u, 0x00000028u,
|
||||
0x00000029u, 0x000200f8u, 0x00000028u, 0x0004003du, 0x00000006u, 0x0000002bu, 0x0000002au, 0x0003003eu,
|
||||
0x00000013u, 0x0000002bu, 0x0004003du, 0x00000006u, 0x0000003au, 0x0000002au, 0x00050041u, 0x0000003bu,
|
||||
0x0000003cu, 0x00000037u, 0x00000039u, 0x0003003eu, 0x0000003cu, 0x0000003au, 0x000200f9u, 0x00000029u,
|
||||
0x000200f8u, 0x00000029u, 0x000400e0u, 0x00000025u, 0x00000025u, 0x00000024u, 0x0004003du, 0x00000006u,
|
||||
0x0000003eu, 0x00000013u, 0x0003003eu, 0x0000003du, 0x0000003eu, 0x0004003du, 0x00000006u, 0x0000003fu,
|
||||
0x0000002au, 0x0004003du, 0x00000006u, 0x00000040u, 0x0000003du, 0x000500abu, 0x0000000eu, 0x00000041u,
|
||||
0x0000003fu, 0x00000040u, 0x000300f7u, 0x00000043u, 0x00000000u, 0x000400fau, 0x00000041u, 0x00000042u,
|
||||
0x00000043u, 0x000200f8u, 0x00000042u, 0x000700f1u, 0x00000006u, 0x00000044u, 0x00000014u, 0x00000023u,
|
||||
0x0000000du, 0x00000023u, 0x000200f9u, 0x00000043u, 0x000200f8u, 0x00000043u, 0x0004003du, 0x00000006u,
|
||||
0x00000045u, 0x0000002au, 0x000500b0u, 0x0000000eu, 0x00000046u, 0x00000045u, 0x00000025u, 0x000400a8u,
|
||||
0x0000000eu, 0x00000047u, 0x00000046u, 0x000300f7u, 0x00000049u, 0x00000000u, 0x000400fau, 0x00000047u,
|
||||
0x00000048u, 0x00000049u, 0x000200f8u, 0x00000048u, 0x0004003du, 0x00000006u, 0x0000004au, 0x0000002au,
|
||||
0x000500acu, 0x0000000eu, 0x0000004bu, 0x0000004au, 0x00000017u, 0x000200f9u, 0x00000049u, 0x000200f8u,
|
||||
0x00000049u, 0x000700f5u, 0x0000000eu, 0x0000004cu, 0x00000046u, 0x00000043u, 0x0000004bu, 0x00000048u,
|
||||
0x000300f7u, 0x0000004eu, 0x00000000u, 0x000400fau, 0x0000004cu, 0x0000004du, 0x0000004eu, 0x000200f8u,
|
||||
0x0000004du, 0x000700f1u, 0x00000006u, 0x0000004fu, 0x00000014u, 0x00000023u, 0x0000000du, 0x00000025u,
|
||||
0x000200f9u, 0x0000004eu, 0x000200f8u, 0x0000004eu, 0x0004003du, 0x00000006u, 0x00000051u, 0x00000050u,
|
||||
0x0004003du, 0x00000006u, 0x00000052u, 0x0000003du, 0x000500aeu, 0x0000000eu, 0x00000053u, 0x00000051u,
|
||||
0x00000052u, 0x000400a8u, 0x0000000eu, 0x00000054u, 0x00000053u, 0x000300f7u, 0x00000056u, 0x00000000u,
|
||||
0x000400fau, 0x00000054u, 0x00000055u, 0x00000056u, 0x000200f8u, 0x00000055u, 0x0004003du, 0x00000006u,
|
||||
0x00000057u, 0x00000050u, 0x000500aeu, 0x0000000eu, 0x00000058u, 0x00000057u, 0x00000017u, 0x000200f9u,
|
||||
0x00000056u, 0x000200f8u, 0x00000056u, 0x000700f5u, 0x0000000eu, 0x00000059u, 0x00000053u, 0x0000004eu,
|
||||
0x00000058u, 0x00000055u, 0x000300f7u, 0x0000005bu, 0x00000000u, 0x000400fau, 0x00000059u, 0x0000005au,
|
||||
0x0000005bu, 0x000200f8u, 0x0000005au, 0x000700f1u, 0x00000006u, 0x0000005du, 0x00000014u, 0x00000023u,
|
||||
0x0000000du, 0x0000005cu, 0x000200f9u, 0x0000005bu, 0x000200f8u, 0x0000005bu, 0x0004003du, 0x00000006u,
|
||||
0x0000005fu, 0x0000005eu, 0x000500aau, 0x0000000eu, 0x00000060u, 0x0000005fu, 0x0000000du, 0x000400a8u,
|
||||
0x0000000eu, 0x00000061u, 0x00000060u, 0x000300f7u, 0x00000063u, 0x00000000u, 0x000400fau, 0x00000061u,
|
||||
0x00000062u, 0x00000063u, 0x000200f8u, 0x00000062u, 0x0004003du, 0x00000006u, 0x00000065u, 0x00000064u,
|
||||
0x0004003du, 0x00000006u, 0x00000066u, 0x0000005eu, 0x000500aeu, 0x0000000eu, 0x00000067u, 0x00000065u,
|
||||
0x00000066u, 0x000200f9u, 0x00000063u, 0x000200f8u, 0x00000063u, 0x000700f5u, 0x0000000eu, 0x00000068u,
|
||||
0x00000060u, 0x0000005bu, 0x00000067u, 0x00000062u, 0x000300f7u, 0x0000006au, 0x00000000u, 0x000400fau,
|
||||
0x00000068u, 0x00000069u, 0x0000006au, 0x000200f8u, 0x00000069u, 0x000700f1u, 0x00000006u, 0x0000006cu,
|
||||
0x00000014u, 0x00000023u, 0x0000000du, 0x0000006bu, 0x000200f9u, 0x0000006au, 0x000200f8u, 0x0000006au,
|
||||
0x0004003du, 0x00000006u, 0x0000006fu, 0x0000003du, 0x000500aeu, 0x0000000eu, 0x00000070u, 0x0000006fu,
|
||||
0x00000025u, 0x0004003du, 0x00000006u, 0x00000071u, 0x0000003du, 0x000500b2u, 0x0000000eu, 0x00000072u,
|
||||
0x00000071u, 0x00000017u, 0x000500a7u, 0x0000000eu, 0x00000073u, 0x00000070u, 0x00000072u, 0x0003003eu,
|
||||
0x0000006eu, 0x00000073u, 0x0004003du, 0x0000000eu, 0x00000075u, 0x0000006eu, 0x000300f7u, 0x00000077u,
|
||||
0x00000000u, 0x000400fau, 0x00000075u, 0x00000076u, 0x00000077u, 0x000200f8u, 0x00000076u, 0x0004003du,
|
||||
0x00000006u, 0x00000078u, 0x00000050u, 0x0004003du, 0x00000006u, 0x00000079u, 0x0000003du, 0x000500b0u,
|
||||
0x0000000eu, 0x0000007au, 0x00000078u, 0x00000079u, 0x000200f9u, 0x00000077u, 0x000200f8u, 0x00000077u,
|
||||
0x000700f5u, 0x0000000eu, 0x0000007bu, 0x00000075u, 0x0000006au, 0x0000007au, 0x00000076u, 0x0003003eu,
|
||||
0x00000074u, 0x0000007bu, 0x0004003du, 0x0000000eu, 0x0000007cu, 0x00000074u, 0x000300f7u, 0x0000007eu,
|
||||
0x00000000u, 0x000400fau, 0x0000007cu, 0x0000007du, 0x0000007eu, 0x000200f8u, 0x0000007du, 0x0004003du,
|
||||
0x00000006u, 0x0000007fu, 0x00000050u, 0x000500c4u, 0x00000006u, 0x00000080u, 0x00000023u, 0x0000007fu,
|
||||
0x000700f1u, 0x00000006u, 0x00000081u, 0x00000015u, 0x00000023u, 0x0000000du, 0x00000080u, 0x0004003du,
|
||||
0x00000006u, 0x00000082u, 0x00000050u, 0x00050041u, 0x00000012u, 0x00000083u, 0x00000020u, 0x00000082u,
|
||||
0x0004003du, 0x00000006u, 0x00000084u, 0x00000008u, 0x00050080u, 0x00000006u, 0x00000085u, 0x00000084u,
|
||||
0x00000023u, 0x000700eau, 0x00000006u, 0x00000086u, 0x00000083u, 0x00000023u, 0x0000000du, 0x00000085u,
|
||||
0x0004003du, 0x00000006u, 0x00000087u, 0x0000005eu, 0x000500abu, 0x0000000eu, 0x00000088u, 0x00000087u,
|
||||
0x0000000du, 0x000300f7u, 0x0000008au, 0x00000000u, 0x000400fau, 0x00000088u, 0x00000089u, 0x0000008au,
|
||||
0x000200f8u, 0x00000089u, 0x0004003du, 0x00000006u, 0x0000008bu, 0x00000064u, 0x0004003du, 0x00000006u,
|
||||
0x0000008cu, 0x0000005eu, 0x00050082u, 0x00000006u, 0x0000008du, 0x0000008cu, 0x00000023u, 0x000500aau,
|
||||
0x0000000eu, 0x0000008eu, 0x0000008bu, 0x0000008du, 0x000200f9u, 0x0000008au, 0x000200f8u, 0x0000008au,
|
||||
0x000700f5u, 0x0000000eu, 0x0000008fu, 0x00000088u, 0x0000007du, 0x0000008eu, 0x00000089u, 0x000300f7u,
|
||||
0x00000091u, 0x00000000u, 0x000400fau, 0x0000008fu, 0x00000090u, 0x00000091u, 0x000200f8u, 0x00000090u,
|
||||
0x0004003du, 0x00000006u, 0x00000092u, 0x00000050u, 0x00050041u, 0x00000012u, 0x00000093u, 0x0000001du,
|
||||
0x00000092u, 0x000700eau, 0x00000006u, 0x00000094u, 0x00000093u, 0x00000023u, 0x0000000du, 0x00000023u,
|
||||
0x000200f9u, 0x00000091u, 0x000200f8u, 0x00000091u, 0x000200f9u, 0x0000007eu, 0x000200f8u, 0x0000007eu,
|
||||
0x000300e1u, 0x00000023u, 0x00000024u, 0x000400e0u, 0x00000025u, 0x00000025u, 0x00000024u, 0x0004003du,
|
||||
0x00000006u, 0x00000095u, 0x00000008u, 0x000500aau, 0x0000000eu, 0x00000096u, 0x00000095u, 0x0000000du,
|
||||
0x000300f7u, 0x00000098u, 0x00000000u, 0x000400fau, 0x00000096u, 0x00000097u, 0x00000098u, 0x000200f8u,
|
||||
0x00000097u, 0x0004003du, 0x00000006u, 0x0000009au, 0x00000015u, 0x00050041u, 0x0000003bu, 0x0000009bu,
|
||||
0x00000037u, 0x00000099u, 0x0003003eu, 0x0000009bu, 0x0000009au, 0x000200f9u, 0x00000098u, 0x000200f8u,
|
||||
0x00000098u, 0x0004003du, 0x00000006u, 0x0000009cu, 0x00000008u, 0x000500b0u, 0x0000000eu, 0x0000009du,
|
||||
0x0000009cu, 0x00000017u, 0x000300f7u, 0x0000009fu, 0x00000000u, 0x000400fau, 0x0000009du, 0x0000009eu,
|
||||
0x0000009fu, 0x000200f8u, 0x0000009eu, 0x0004003du, 0x00000006u, 0x000000a1u, 0x00000008u, 0x0004003du,
|
||||
0x00000006u, 0x000000a2u, 0x00000008u, 0x00050041u, 0x00000012u, 0x000000a3u, 0x0000001du, 0x000000a2u,
|
||||
0x0004003du, 0x00000006u, 0x000000a4u, 0x000000a3u, 0x00060041u, 0x0000003bu, 0x000000a5u, 0x00000037u,
|
||||
0x000000a0u, 0x000000a1u, 0x0003003eu, 0x000000a5u, 0x000000a4u, 0x0004003du, 0x00000006u, 0x000000a7u,
|
||||
0x00000008u, 0x0004003du, 0x00000006u, 0x000000a8u, 0x00000008u, 0x00050041u, 0x00000012u, 0x000000a9u,
|
||||
0x00000020u, 0x000000a8u, 0x0004003du, 0x00000006u, 0x000000aau, 0x000000a9u, 0x00060041u, 0x0000003bu,
|
||||
0x000000abu, 0x00000037u, 0x000000a6u, 0x000000a7u, 0x0003003eu, 0x000000abu, 0x000000aau, 0x000200f9u,
|
||||
0x0000009fu, 0x000200f8u, 0x0000009fu, 0x0004003du, 0x0000000eu, 0x000000adu, 0x0000006eu, 0x000300f7u,
|
||||
0x000000afu, 0x00000000u, 0x000400fau, 0x000000adu, 0x000000aeu, 0x000000afu, 0x000200f8u, 0x000000aeu,
|
||||
0x0004003du, 0x00000006u, 0x000000b0u, 0x00000014u, 0x000500aau, 0x0000000eu, 0x000000b1u, 0x000000b0u,
|
||||
0x0000000du, 0x000200f9u, 0x000000afu, 0x000200f8u, 0x000000afu, 0x000700f5u, 0x0000000eu, 0x000000b2u,
|
||||
0x000000adu, 0x0000009fu, 0x000000b1u, 0x000000aeu, 0x0003003eu, 0x000000acu, 0x000000b2u, 0x0004003du,
|
||||
0x0000000eu, 0x000000b3u, 0x000000acu, 0x000300f7u, 0x000000b5u, 0x00000000u, 0x000400fau, 0x000000b3u,
|
||||
0x000000b4u, 0x000000b5u, 0x000200f8u, 0x000000b4u, 0x0004003du, 0x00000006u, 0x000000b8u, 0x0000000au,
|
||||
0x00050080u, 0x00000006u, 0x000000b9u, 0x000000b8u, 0x00000023u, 0x00040070u, 0x0000002fu, 0x000000bau,
|
||||
0x000000b9u, 0x00050050u, 0x00000030u, 0x000000bcu, 0x000000bau, 0x000000bbu, 0x0003003eu, 0x000000b7u,
|
||||
0x000000bcu, 0x0004003du, 0x00000030u, 0x000000bdu, 0x000000b7u, 0x0006015eu, 0x00000030u, 0x000000bfu,
|
||||
0x000000beu, 0x00000001u, 0x000000bdu, 0x0003003eu, 0x000000b7u, 0x000000bfu, 0x0004003du, 0x00000006u,
|
||||
0x000000c0u, 0x00000064u, 0x0004003du, 0x00000006u, 0x000000c1u, 0x0000005eu, 0x00050082u, 0x00000006u,
|
||||
0x000000c2u, 0x000000c1u, 0x00000023u, 0x000500aau, 0x0000000eu, 0x000000c3u, 0x000000c0u, 0x000000c2u,
|
||||
0x000300f7u, 0x000000c5u, 0x00000000u, 0x000400fau, 0x000000c3u, 0x000000c4u, 0x000000c5u, 0x000200f8u,
|
||||
0x000000c4u, 0x0004003du, 0x00000006u, 0x000000c9u, 0x00000050u, 0x0004003du, 0x00000030u, 0x000000cau,
|
||||
0x000000b7u, 0x00050041u, 0x000000cbu, 0x000000ccu, 0x000000c8u, 0x000000c9u, 0x0003003eu, 0x000000ccu,
|
||||
0x000000cau, 0x000200f9u, 0x000000c5u, 0x000200f8u, 0x000000c5u, 0x000400e0u, 0x00000025u, 0x00000025u,
|
||||
0x00000024u, 0x0004003du, 0x00000006u, 0x000000cdu, 0x0000000au, 0x0004003du, 0x00000006u, 0x000000ceu,
|
||||
0x0000002au, 0x000500b0u, 0x0000000eu, 0x000000cfu, 0x000000cdu, 0x000000ceu, 0x000300f7u, 0x000000d1u,
|
||||
0x00000000u, 0x000400fau, 0x000000cfu, 0x000000d0u, 0x000000d1u, 0x000200f8u, 0x000000d0u, 0x0004003du,
|
||||
0x00000006u, 0x000000d3u, 0x0000000au, 0x0004003du, 0x00000006u, 0x000000d4u, 0x0000000au, 0x00050041u,
|
||||
0x000000cbu, 0x000000d5u, 0x000000c8u, 0x000000d4u, 0x0004003du, 0x00000030u, 0x000000d6u, 0x000000d5u,
|
||||
0x00060041u, 0x000000d7u, 0x000000d8u, 0x00000037u, 0x000000d2u, 0x000000d3u, 0x0003003eu, 0x000000d8u,
|
||||
0x000000d6u, 0x000200f9u, 0x000000d1u, 0x000200f8u, 0x000000d1u, 0x000400e0u, 0x00000025u, 0x00000025u,
|
||||
0x00000024u, 0x0004003du, 0x00000006u, 0x000000dau, 0x0000002au, 0x0006000cu, 0x00000038u, 0x000000dbu,
|
||||
0x00000001u, 0x0000004bu, 0x000000dau, 0x0004007cu, 0x00000006u, 0x000000dcu, 0x000000dbu, 0x0003003eu,
|
||||
0x000000d9u, 0x000000dcu, 0x0004003du, 0x00000006u, 0x000000ddu, 0x0000002au, 0x0004003du, 0x00000006u,
|
||||
0x000000deu, 0x000000d9u, 0x00050082u, 0x00000006u, 0x000000dfu, 0x000000deu, 0x00000023u, 0x000500c4u,
|
||||
0x00000006u, 0x000000e0u, 0x00000023u, 0x000000dfu, 0x00050082u, 0x00000006u, 0x000000e1u, 0x000000ddu,
|
||||
0x000000e0u, 0x000500acu, 0x0000000eu, 0x000000e2u, 0x000000e1u, 0x0000000du, 0x000600a9u, 0x00000006u,
|
||||
0x000000e3u, 0x000000e2u, 0x00000023u, 0x0000000du, 0x0004003du, 0x00000006u, 0x000000e4u, 0x000000d9u,
|
||||
0x00050080u, 0x00000006u, 0x000000e5u, 0x000000e4u, 0x000000e3u, 0x0003003eu, 0x000000d9u, 0x000000e5u,
|
||||
0x0004003du, 0x00000006u, 0x000000e6u, 0x0000000au, 0x000500aau, 0x0000000eu, 0x000000e7u, 0x000000e6u,
|
||||
0x0000000du, 0x000300f7u, 0x000000e9u, 0x00000000u, 0x000400fau, 0x000000e7u, 0x000000e8u, 0x000000e9u,
|
||||
0x000200f8u, 0x000000e8u, 0x0004003du, 0x00000006u, 0x000000ebu, 0x000000d9u, 0x00050041u, 0x0000003bu,
|
||||
0x000000ecu, 0x00000037u, 0x000000eau, 0x0003003eu, 0x000000ecu, 0x000000ebu, 0x000200f9u, 0x000000e9u,
|
||||
0x000200f8u, 0x000000e9u, 0x0003003eu, 0x000000edu, 0x0000000du, 0x000200f9u, 0x000000eeu, 0x000200f8u,
|
||||
0x000000eeu, 0x000400f6u, 0x000000f0u, 0x000000f1u, 0x00000000u, 0x000200f9u, 0x000000f2u, 0x000200f8u,
|
||||
0x000000f2u, 0x0004003du, 0x00000006u, 0x000000f3u, 0x000000edu, 0x0004003du, 0x00000006u, 0x000000f4u,
|
||||
0x000000d9u, 0x000500b0u, 0x0000000eu, 0x000000f5u, 0x000000f3u, 0x000000f4u, 0x000400fau, 0x000000f5u,
|
||||
0x000000efu, 0x000000f0u, 0x000200f8u, 0x000000efu, 0x0004003du, 0x00000006u, 0x000000f6u, 0x00000050u,
|
||||
0x0004003du, 0x00000006u, 0x000000f7u, 0x000000edu, 0x000500c4u, 0x00000006u, 0x000000f8u, 0x00000023u,
|
||||
0x000000f7u, 0x000500c7u, 0x00000006u, 0x000000f9u, 0x000000f6u, 0x000000f8u, 0x000500acu, 0x0000000eu,
|
||||
0x000000fau, 0x000000f9u, 0x0000000du, 0x000300f7u, 0x000000fcu, 0x00000000u, 0x000400fau, 0x000000fau,
|
||||
0x000000fbu, 0x000000fcu, 0x000200f8u, 0x000000fbu, 0x0004003du, 0x00000006u, 0x000000fdu, 0x00000050u,
|
||||
0x0004003du, 0x00000006u, 0x000000feu, 0x000000edu, 0x000500c2u, 0x00000006u, 0x000000ffu, 0x000000fdu,
|
||||
0x000000feu, 0x0004003du, 0x00000006u, 0x00000100u, 0x000000edu, 0x000500c4u, 0x00000006u, 0x00000101u,
|
||||
0x000000ffu, 0x00000100u, 0x00050082u, 0x00000006u, 0x00000102u, 0x00000101u, 0x00000023u, 0x00050041u,
|
||||
0x000000cbu, 0x00000103u, 0x000000c8u, 0x00000102u, 0x0004003du, 0x00000030u, 0x00000104u, 0x00000103u,
|
||||
0x0004003du, 0x00000030u, 0x00000105u, 0x000000b7u, 0x00050081u, 0x00000030u, 0x00000106u, 0x00000105u,
|
||||
0x00000104u, 0x0003003eu, 0x000000b7u, 0x00000106u, 0x0004003du, 0x00000006u, 0x00000107u, 0x00000064u,
|
||||
0x0004003du, 0x00000006u, 0x00000108u, 0x0000005eu, 0x00050082u, 0x00000006u, 0x00000109u, 0x00000108u,
|
||||
0x00000023u, 0x000500aau, 0x0000000eu, 0x0000010au, 0x00000107u, 0x00000109u, 0x000300f7u, 0x0000010cu,
|
||||
0x00000000u, 0x000400fau, 0x0000010au, 0x0000010bu, 0x0000010cu, 0x000200f8u, 0x0000010bu, 0x0004003du,
|
||||
0x00000006u, 0x0000010du, 0x00000050u, 0x0004003du, 0x00000030u, 0x0000010eu, 0x000000b7u, 0x00050041u,
|
||||
0x000000cbu, 0x0000010fu, 0x000000c8u, 0x0000010du, 0x0003003eu, 0x0000010fu, 0x0000010eu, 0x000200f9u,
|
||||
0x0000010cu, 0x000200f8u, 0x0000010cu, 0x000200f9u, 0x000000fcu, 0x000200f8u, 0x000000fcu, 0x000400e0u,
|
||||
0x00000025u, 0x00000025u, 0x00000024u, 0x0004003du, 0x00000006u, 0x00000110u, 0x0000000au, 0x0004003du,
|
||||
0x00000006u, 0x00000111u, 0x0000002au, 0x000500b0u, 0x0000000eu, 0x00000112u, 0x00000110u, 0x00000111u,
|
||||
0x000300f7u, 0x00000114u, 0x00000000u, 0x000400fau, 0x00000112u, 0x00000113u, 0x00000114u, 0x000200f8u,
|
||||
0x00000113u, 0x0004003du, 0x00000006u, 0x00000116u, 0x000000edu, 0x0004003du, 0x00000006u, 0x00000117u,
|
||||
0x0000000au, 0x0004003du, 0x00000006u, 0x00000118u, 0x0000000au, 0x00050041u, 0x000000cbu, 0x00000119u,
|
||||
0x000000c8u, 0x00000118u, 0x0004003du, 0x00000030u, 0x0000011au, 0x00000119u, 0x00070041u, 0x000000d7u,
|
||||
0x0000011bu, 0x00000037u, 0x00000115u, 0x00000116u, 0x00000117u, 0x0003003eu, 0x0000011bu, 0x0000011au,
|
||||
0x000200f9u, 0x00000114u, 0x000200f8u, 0x00000114u, 0x000400e0u, 0x00000025u, 0x00000025u, 0x00000024u,
|
||||
0x000200f9u, 0x000000f1u, 0x000200f8u, 0x000000f1u, 0x0004003du, 0x00000006u, 0x0000011cu, 0x000000edu,
|
||||
0x00050080u, 0x00000006u, 0x0000011eu, 0x0000011cu, 0x0000011du, 0x0003003eu, 0x000000edu, 0x0000011eu,
|
||||
0x000200f9u, 0x000000eeu, 0x000200f8u, 0x000000f0u, 0x0004003du, 0x00000006u, 0x0000011fu, 0x0000000au,
|
||||
0x000500aau, 0x0000000eu, 0x00000121u, 0x0000011fu, 0x00000120u, 0x000300f7u, 0x00000123u, 0x00000000u,
|
||||
0x000400fau, 0x00000121u, 0x00000122u, 0x00000123u, 0x000200f8u, 0x00000122u, 0x0004003du, 0x00000030u,
|
||||
0x00000125u, 0x000000b7u, 0x00050050u, 0x00000030u, 0x00000127u, 0x00000126u, 0x00000126u, 0x00050088u,
|
||||
0x00000030u, 0x00000128u, 0x00000125u, 0x00000127u, 0x00050041u, 0x000000cbu, 0x00000129u, 0x000000c8u,
|
||||
0x00000124u, 0x0003003eu, 0x00000129u, 0x00000128u, 0x000200f9u, 0x00000123u, 0x000200f8u, 0x00000123u,
|
||||
0x000400e0u, 0x00000025u, 0x00000025u, 0x00000024u, 0x0004003du, 0x00000006u, 0x0000012au, 0x0000000au,
|
||||
0x000500aau, 0x0000000eu, 0x0000012bu, 0x0000012au, 0x00000120u, 0x000300f7u, 0x0000012du, 0x00000000u,
|
||||
0x000400fau, 0x0000012bu, 0x0000012cu, 0x0000012du, 0x000200f8u, 0x0000012cu, 0x0004003du, 0x00000006u,
|
||||
0x0000012fu, 0x0000005eu, 0x0004003du, 0x00000006u, 0x00000130u, 0x0000002au, 0x0004003du, 0x00000006u,
|
||||
0x00000131u, 0x00000050u, 0x0004003du, 0x00000006u, 0x00000132u, 0x00000064u, 0x00070050u, 0x0000002cu,
|
||||
0x00000133u, 0x0000012fu, 0x00000130u, 0x00000131u, 0x00000132u, 0x00050041u, 0x00000134u, 0x00000135u,
|
||||
0x00000037u, 0x0000012eu, 0x0003003eu, 0x00000135u, 0x00000133u, 0x00050041u, 0x000000cbu, 0x00000137u,
|
||||
0x000000c8u, 0x00000124u, 0x0004003du, 0x00000030u, 0x00000138u, 0x00000137u, 0x00050041u, 0x000000d7u,
|
||||
0x00000139u, 0x00000037u, 0x00000136u, 0x0003003eu, 0x00000139u, 0x00000138u, 0x000200f9u, 0x0000012du,
|
||||
0x000200f8u, 0x0000012du, 0x000200f9u, 0x000000b5u, 0x000200f8u, 0x000000b5u, 0x000400e0u, 0x00000025u,
|
||||
0x00000025u, 0x00000024u, 0x0004003du, 0x00000006u, 0x0000013au, 0x00000008u, 0x000500aau, 0x0000000eu,
|
||||
0x0000013bu, 0x0000013au, 0x0000000du, 0x000300f7u, 0x0000013du, 0x00000000u, 0x000400fau, 0x0000013bu,
|
||||
0x0000013cu, 0x0000013du, 0x000200f8u, 0x0000013cu, 0x0004003du, 0x00000006u, 0x0000013eu, 0x00000014u,
|
||||
0x00050041u, 0x0000003bu, 0x0000013fu, 0x00000037u, 0x0000011du, 0x0003003eu, 0x0000013fu, 0x0000013eu,
|
||||
0x00050041u, 0x0000003bu, 0x00000141u, 0x00000037u, 0x00000124u, 0x0003003eu, 0x00000141u, 0x00000140u,
|
||||
0x000200f9u, 0x0000013du, 0x000200f8u, 0x0000013du, 0x000100fdu, 0x00010038u,
|
||||
};
|
||||
inline constexpr std::size_t kDriverPostProgram203WitnessSpvWordCount =
|
||||
sizeof(kDriverPostProgram203WitnessSpv) / sizeof(kDriverPostProgram203WitnessSpv[0]);
|
||||
} // namespace MobileGL::MG_Util::SelfTest
|
||||
Reference in New Issue
Block a user