diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 30e1eece..351cf0d1 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -3445,6 +3445,7 @@ void main() { CollectWireObjects(m_submitCounter, true); ClearAllWireDrawPassCaches(); DestroyWireColorBlitResources(); + DestroyWireDepthMipmapResources(); #endif OnSubmitsCompletedUpTo(m_submitCounter); DestroySubmitFencePool(); @@ -7877,6 +7878,9 @@ void main() { #include "WireFramebuffer.inc" #include "WireTextureReadback.inc" #include "WireColorBlit.inc" + // AFTER WireColorBlit.inc: the depth mip reuses that file's window-Y convention and is + // written to be read beside it. + #include "WireDepthMipmap.inc" #include "WireDraw.inc" void VulkanRenderer::Clear(GLbitfield mask) { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 359fae5c..1f07213b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -500,6 +500,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { struct WireColorBlitResources; WireColorBlitResources* m_wireColorBlitResources = nullptr; void DestroyWireColorBlitResources(); + // P7 wave 2-B, CONTRACT-P7 §5.1 (A): the baked depth-mip program (WireDepthMipmap.inc). + // One level of a depth chain, source and destination being two depth subresources of + // the same image; the caller loops. It owns no frontend object, which is what the + // monolith arm's GenerateDepthMipmapWithShader cannot say. + Bool GenerateWireDepthMipLevel(WireImage source, WireImage destination); + struct WireDepthMipmapResources; + WireDepthMipmapResources* m_wireDepthMipmapResources = nullptr; + void DestroyWireDepthMipmapResources(); void ReadWirePixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); void GenerateWireMipmap(); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h index acf485d8..4101df5e 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h @@ -1,6 +1,11 @@ -// Generated from WireColorBlit.vert / WireColorBlit.frag with: -// glslangValidator -V --target-env vulkan1.0 -o .spv -// Validated with spirv-val --target-env vulkan1.0. Do not edit the words by hand. +// Generated from WireColorBlit.vert / WireColorBlit.frag (Vulkan 1.0 / SPIR-V 1.0) by +// scripts/bake_internal_shaders.py, which runs MG_Test's BakedInternalShadersTest with the +// IN-TREE glslang and splices the words it emits into the arrays below. Do not edit the words +// by hand: MOBILEGL_BAKED_INTERNAL_SHADERS (the same test, run as a gate) recompiles every +// source in its table and reds on the first word that disagrees. +// +// These words were hand-run through glslangValidator before that gate existed, and the gate +// reproduces them exactly - which is the one thing nobody could have known beforehand. #pragma once static constexpr Uint32 kWireColorBlitVertexSpirv[] = { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.frag b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.frag new file mode 100644 index 00000000..27aebfff --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.frag @@ -0,0 +1,28 @@ +#version 450 +// The monolith arm's kDepthMipmapFragmentShaderSource (VulkanRenderer.cpp), ported to the +// baked pipeline: the same 2x2 box of texelFetches, the same clamp, the same average, the +// same gl_FragDepth. It is a PORT and not a rewrite on purpose - CONTRACT-P7 §3.2 retires a +// refusal by making the wire arm observably the monolith's, so the two arms have to agree +// texel for texel, including where they read. +// +// uSrcTexelSize arrives on the push constant rather than in a uniform block: the wire arm +// owns no GL program, so there is no default-block uniform to write and no global UBO to +// bind. That is the whole of OQ-13's narrow half for this program. +layout(push_constant) uniform DepthMipmapRect { + vec4 srcRect; + vec4 dstRect; + int surfaceTransform; + ivec2 srcTexelSize; +} rect; +layout(set = 0, binding = 0) uniform sampler2D sourceImage; +layout(location = 0) in vec2 texCoord; + +void main() { + ivec2 srcBase = ivec2(texCoord * vec2(rect.srcTexelSize)); + ivec2 srcMax = rect.srcTexelSize - ivec2(1); + float depth0 = texelFetch(sourceImage, clamp(srcBase, ivec2(0), srcMax), 0).r; + float depth1 = texelFetch(sourceImage, clamp(srcBase + ivec2(1, 0), ivec2(0), srcMax), 0).r; + float depth2 = texelFetch(sourceImage, clamp(srcBase + ivec2(0, 1), ivec2(0), srcMax), 0).r; + float depth3 = texelFetch(sourceImage, clamp(srcBase + ivec2(1, 1), ivec2(0), srcMax), 0).r; + gl_FragDepth = 0.25 * (depth0 + depth1 + depth2 + depth3); +} diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.inc b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.inc new file mode 100644 index 00000000..2d14a2ae --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.inc @@ -0,0 +1,320 @@ +// Included by VulkanRenderer.cpp inside the backend namespace, after WireColorBlit.inc. +// The native depth mip owns no frontend object and never invokes the GL shader compiler. +// +// WHY THIS FILE EXISTS AT ALL. vkCmdBlitImage is the ordinary way to halve a mip, and for a +// depth format it is often not available: VK_FORMAT_FEATURE_BLIT_DST is optional for depth, +// and the monolith arm has carried a shader fallback for exactly that case since before the +// split (VulkanRenderer.cpp's GenerateDepthMipmapWithShader). The wire arm had no such +// fallback, so every depth mip the device could not blit died as +// `Magma:mipmap-shader-format-or-shape`, and a DEPTH|STENCIL texture died one guard earlier +// as `Magma:depth-stencil-mipmap@P7` whether or not it could be blitted. +// +// The monolith fallback is not reusable here and that is the whole of CONTRACT-P7 §5.1 (A): +// it builds a GL ProgramObject, two GL ShaderObjects and a GL sampler, binds through the +// uniform manager's global UBO, and writes uSrcTexelSize as a default-block uniform - four +// frontend objects and a GL compiler on the server's apply thread. The baked program below is +// the same shader with the same arithmetic, driven by a push constant and its own descriptor +// set, which is what lets the server generate a depth mip while owning nothing of the client. +#if MOBILEGL_BUILD_DISAGGREGATED +#include "WireDepthMipmapSpirv.h" + + struct VulkanRenderer::WireDepthMipmapResources { + struct Target { + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkRenderPass renderPass = VK_NULL_HANDLE; + VkPipeline pipeline = VK_NULL_HANDLE; + }; + VkShaderModule vertex = VK_NULL_HANDLE, fragment = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorLayout = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkSampler nearest = VK_NULL_HANDLE; + Vector targets; + }; + + void VulkanRenderer::DestroyWireDepthMipmapResources() { + if (!m_wireDepthMipmapResources) return; + // Shutdown calls this after vkDeviceWaitIdle and after all per-submit + // descriptor pools/framebuffers/views have been collected. + auto& cache = *m_wireDepthMipmapResources; + for (const auto& target : cache.targets) { + vkDestroyPipeline(m_device, target.pipeline, nullptr); + vkDestroyRenderPass(m_device, target.renderPass, nullptr); + } + vkDestroySampler(m_device, cache.nearest, nullptr); + vkDestroyPipelineLayout(m_device, cache.pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(m_device, cache.descriptorLayout, nullptr); + vkDestroyShaderModule(m_device, cache.vertex, nullptr); + vkDestroyShaderModule(m_device, cache.fragment, nullptr); + delete m_wireDepthMipmapResources; + m_wireDepthMipmapResources = nullptr; + } + + // ONE LEVEL, source -> destination, both depth subresources of the same image. The shape + // mirrors BlitWireColorImage deliberately: the same lazily built module pair, the same + // per-format render pass/pipeline cache, the same per-submit descriptor pool, and the + // same GENERAL-on-both-sides layout rule for a same-image pass, so the two native passes + // cannot disagree about how an image is handed between them. + Bool VulkanRenderer::GenerateWireDepthMipLevel(WireImage source, WireImage destination) { + const Bool sameImage = source.image == destination.image; + if (!source.image || !destination.image) return false; + if (sameImage && source.level == destination.level && source.layer == destination.layer) + return false; + if (source.isDefault || destination.isDefault) return false; + if (source.samples != VK_SAMPLE_COUNT_1_BIT || destination.samples != VK_SAMPLE_COUNT_1_BIT) + return false; + if (source.is3D || destination.is3D) return false; + if (source.format != destination.format) return false; + // DEPTH ONLY. A combined depth/stencil image can be sampled for its depth and + // rendered as a depth attachment, but this pass writes gl_FragDepth and NOTHING + // else - the stencil aspect would come out of the render pass undefined, which is + // not what GL's glGenerateMipmap promises for the level it just produced. The + // caller declines that shape rather than producing half a level. + if (source.aspect != VK_IMAGE_ASPECT_DEPTH_BIT || + destination.aspect != VK_IMAGE_ASPECT_DEPTH_BIT) return false; + if (!source.extent.width || !source.extent.height || + !destination.extent.width || !destination.extent.height) return false; + VkFormatProperties properties{}; + vkGetPhysicalDeviceFormatProperties(m_physicalDevice.handle, source.format, &properties); + const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + if ((properties.optimalTilingFeatures & required) != required) return false; + + // The baked block's layout, and the offsets are not a guess: the generated header + // decorates its members at 0 / 16 / 32 / 40, which is where a vec4, a vec4, an int + // and an 8-byte-aligned ivec2 land. The pad is what makes the C++ agree. + struct Constants { + float srcRect[4]; + float dstRect[4]; + Int32 surfaceTransform; + Int32 reservedForIvec2Alignment; + Int32 srcTexelSize[2]; + }; + static_assert(sizeof(Constants) == 48); + static_assert(offsetof(Constants, srcTexelSize) == 40); + + if (!m_wireDepthMipmapResources) { + m_wireDepthMipmapResources = new WireDepthMipmapResources; + auto& cache = *m_wireDepthMipmapResources; + const auto shader = [&](const Uint32* code, SizeT bytes, VkShaderModule& module) { + VkShaderModuleCreateInfo info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + info.codeSize = bytes; + info.pCode = code; + VK_VERIFY(vkCreateShaderModule(m_device, &info, nullptr, &module)); + }; + shader(kWireDepthMipmapVertexSpirv, sizeof(kWireDepthMipmapVertexSpirv), cache.vertex); + shader(kWireDepthMipmapFragmentSpirv, sizeof(kWireDepthMipmapFragmentSpirv), cache.fragment); + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; + VkDescriptorSetLayoutCreateInfo layout{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + layout.bindingCount = 1; + layout.pBindings = &binding; + VK_VERIFY(vkCreateDescriptorSetLayout(m_device, &layout, nullptr, &cache.descriptorLayout)); + // BOTH STAGES ON ONE RANGE: the block is declared identically in the vertex and + // fragment sources (a push-constant block must be), the vertex stage reads the + // rects and the fragment stage reads srcTexelSize. + const VkPushConstantRange push{VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(Constants)}; + VkPipelineLayoutCreateInfo pipelineLayout{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayout.setLayoutCount = 1; + pipelineLayout.pSetLayouts = &cache.descriptorLayout; + pipelineLayout.pushConstantRangeCount = 1; + pipelineLayout.pPushConstantRanges = &push; + VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayout, nullptr, &cache.pipelineLayout)); + // NEAREST, and it is not a default: the fragment shader does its own 2x2 box with + // texelFetch, so any filtering the sampler added would be applied twice. It also + // keeps the sampler legal on a device that does not advertise linear filtering for + // depth formats, which is most of them. + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + sampler.addressModeU = sampler.addressModeV = sampler.addressModeW = + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler.magFilter = sampler.minFilter = VK_FILTER_NEAREST; + sampler.maxLod = 0.0f; + VK_VERIFY(vkCreateSampler(m_device, &sampler, nullptr, &cache.nearest)); + } + auto& cache = *m_wireDepthMipmapResources; + + const VkImageLayout sourceLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL + : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + const VkImageLayout destinationLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL + : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + WireDepthMipmapResources::Target* target = nullptr; + for (auto& entry : cache.targets) { + if (entry.format == destination.format && entry.layout == destinationLayout) { + target = &entry; + break; + } + } + if (!target) { + cache.targets.emplace_back(); + target = &cache.targets.back(); + target->format = destination.format; + target->layout = destinationLayout; + VkAttachmentDescription attachment{}; + attachment.format = destination.format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + // DONT_CARE, not LOAD: the pass writes gl_FragDepth at every texel of the level + // it is producing, so there is nothing in the destination worth loading, and a + // level that has just been grown has no defined contents to load anyway. + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = attachment.finalLayout = destinationLayout; + const VkAttachmentReference depth{0, destinationLayout}; + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.pDepthStencilAttachment = &depth; + VkRenderPassCreateInfo pass{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; + pass.attachmentCount = 1; + pass.pAttachments = &attachment; + pass.subpassCount = 1; + pass.pSubpasses = &subpass; + VK_VERIFY(vkCreateRenderPass(m_device, &pass, nullptr, &target->renderPass)); + VkPipelineShaderStageCreateInfo stages[2]{}; + for (auto& stage : stages) { + stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage.pName = "main"; + } + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[0].module = cache.vertex; + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[1].module = cache.fragment; + const VkPipelineVertexInputStateCreateInfo vertex{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; + VkPipelineInputAssemblyStateCreateInfo assembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; + assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + VkPipelineViewportStateCreateInfo viewport{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; + viewport.viewportCount = viewport.scissorCount = 1; + VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; + raster.polygonMode = VK_POLYGON_MODE_FILL; + raster.cullMode = VK_CULL_MODE_NONE; + raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + raster.lineWidth = 1.0f; + VkPipelineMultisampleStateCreateInfo samples{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; + samples.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + // ALWAYS + write enabled: the fragment shader's gl_FragDepth is the answer, and a + // comparison against whatever DONT_CARE left behind would discard some of it. + VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_ALWAYS; + depthStencil.minDepthBounds = 0.0f; + depthStencil.maxDepthBounds = 1.0f; + // No colour attachment in this render pass, so no attachment states either. + VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; + const VkDynamicState dynamicStates[]{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; + dynamic.dynamicStateCount = 2; + dynamic.pDynamicStates = dynamicStates; + VkGraphicsPipelineCreateInfo pipeline{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; + pipeline.stageCount = 2; + pipeline.pStages = stages; + pipeline.pVertexInputState = &vertex; + pipeline.pInputAssemblyState = &assembly; + pipeline.pViewportState = &viewport; + pipeline.pRasterizationState = &raster; + pipeline.pMultisampleState = &samples; + pipeline.pDepthStencilState = &depthStencil; + pipeline.pColorBlendState = &blend; + pipeline.pDynamicState = &dynamic; + pipeline.layout = cache.pipelineLayout; + pipeline.renderPass = target->renderPass; + VK_VERIFY(vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &pipeline, nullptr, &target->pipeline)); + } + + m_textureManager->FlushPendingUploads(); + // Distinct mip views of the same image are legal shader input and output at once. + // GENERAL keeps the whole-image layout tracker truthful; the transition also orders + // the previous level's attachment write against this level's sample of it. + TransitionWireImage(source, sourceLayout); + if (sameImage) destination.layout = source.layout; + else TransitionWireImage(destination, destinationLayout); + const auto makeView = [&](const WireImage& image) { + VkImageViewCreateInfo view{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + view.image = image.image; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = image.format; + view.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, image.level, 1, image.layer, 1}; + VkImageView handle = VK_NULL_HANDLE; + VK_VERIFY(vkCreateImageView(m_device, &view, nullptr, &handle)); + return handle; + }; + const VkImageView sourceView = makeView(source), destinationView = makeView(destination); + VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + framebufferInfo.renderPass = target->renderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &destinationView; + framebufferInfo.width = destination.extent.width; + framebufferInfo.height = destination.extent.height; + framebufferInfo.layers = 1; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &framebuffer)); + // Each in-flight pass owns its descriptor set, for the colour blit's reason: updating + // a cached set would rewrite the source view of an older queued pass. + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}; + VkDescriptorPoolCreateInfo pool{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + pool.maxSets = 1; + pool.poolSizeCount = 1; + pool.pPoolSizes = &poolSize; + VK_VERIFY(vkCreateDescriptorPool(m_device, &pool, nullptr, &descriptorPool)); + VkDescriptorSetAllocateInfo alloc{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + alloc.descriptorPool = descriptorPool; + alloc.descriptorSetCount = 1; + alloc.pSetLayouts = &cache.descriptorLayout; + VK_VERIFY(vkAllocateDescriptorSets(m_device, &alloc, &descriptorSet)); + const VkDescriptorImageInfo sampled{cache.nearest, sourceView, sourceLayout}; + VkWriteDescriptorSet write{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + write.dstSet = descriptorSet; + write.dstBinding = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.pImageInfo = &sampled; + vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr); + + // The destination rectangle is flipped exactly as BlitWireColorImage flips it for an + // offscreen target, because it shares that file's vertex shader and therefore its + // window-Y flip. With the flip undone, destination row r samples texCoord.y + // (r + 0.5) / dstHeight, and the fragment's ivec2(texCoord * srcTexelSize) lands on + // the same source texels the monolith arm's fullscreen triangle lands on - which is + // the point: §3.2 retires a refusal by making the wire arm observably the monolith's, + // half-texel offset included. + const Constants constants{ + {0.0f, 0.0f, 1.0f, 1.0f}, + {0.0f, 1.0f, 1.0f, -1.0f}, + 0, 0, + {static_cast(source.extent.width), static_cast(source.extent.height)}}; + auto& frame = m_frameContext.GetCurrent(); + VkRenderPassBeginInfo begin{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + begin.renderPass = target->renderPass; + begin.framebuffer = framebuffer; + begin.renderArea = {{0, 0}, destination.extent}; + vkCmdBeginRenderPass(frame.commandBuffer, &begin, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, target->pipeline); + const VkViewport viewport{0.0f, 0.0f, static_cast(destination.extent.width), + static_cast(destination.extent.height), 0.0f, 1.0f}; + const VkRect2D scissor{{0, 0}, destination.extent}; + vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport); + vkCmdSetScissor(frame.commandBuffer, 0, 1, &scissor); + vkCmdBindDescriptorSets(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cache.pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + vkCmdPushConstants(frame.commandBuffer, cache.pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(constants), &constants); + vkCmdDraw(frame.commandBuffer, 6, 1, 0, 0); + vkCmdEndRenderPass(frame.commandBuffer); + ResetDynamicStateShadow(); + InvalidatePipelineMemo(); + // This native pass binds its own set/layout without going through the application's + // descriptor binder. Its next fast path must rebind. + if (m_uniformManager) m_uniformManager->OnCommandBufferBoundary(); + WireRetiredObjects retired{}; + retired.framebuffers.push_back(framebuffer); + retired.imageViews = {sourceView, destinationView}; + retired.descriptorPools.push_back(descriptorPool); + RetireWireObjects(Move(retired)); + return true; + } +#endif diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.vert b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.vert new file mode 100644 index 00000000..4c5f70ee --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.vert @@ -0,0 +1,33 @@ +#version 450 +// Native Vulkan depth mip generation: no GL program, registry entry, or runtime transpilation. +// +// The geometry is WireColorBlit.vert's, unchanged - the same quad, the same push-constant +// rect, the same GL-bottom-left to native-image mapping - so a depth mip and a colour blit +// place their fragments identically and only the fragment stage differs. The block carries +// one member more than the colour blit's, and the fragment stage is the member's only +// reader: a push-constant block must be declared identically in every stage of one pipeline, +// so it is declared here too rather than split into a second range. +layout(push_constant) uniform DepthMipmapRect { + vec4 srcRect; + vec4 dstRect; + int surfaceTransform; + ivec2 srcTexelSize; +} rect; +layout(location = 0) out vec2 texCoord; + +void main() { + // A quad, rather than an oversized triangle, also clips partial blits to + // their destination rectangle. The Vulkan viewport covers the native image. + const vec2 corners[6] = vec2[]( + vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(0.0, 1.0), + vec2(0.0, 1.0), vec2(1.0, 0.0), vec2(1.0, 1.0)); + vec2 uv = corners[gl_VertexIndex]; + vec2 p = (rect.dstRect.xy + uv * rect.dstRect.zw) * 2.0 - 1.0; + // Same GL-bottom-left to native-image mapping as the monolithic blit. + p.y = -p.y; + if (rect.surfaceTransform == 1) p = vec2(-p.y, p.x); + else if (rect.surfaceTransform == 2) p = -p; + else if (rect.surfaceTransform == 3) p = vec2(p.y, -p.x); + gl_Position = vec4(p, 0.0, 1.0); + texCoord = rect.srcRect.xy + uv * rect.srcRect.zw; +} diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmapSpirv.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmapSpirv.h new file mode 100644 index 00000000..1c43c9c3 --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmapSpirv.h @@ -0,0 +1,174 @@ +// Generated from WireDepthMipmap.vert / WireDepthMipmap.frag by +// scripts/bake_internal_shaders.py, which runs MG_Test's BakedInternalShadersTest with the +// IN-TREE glslang and splices the words it emits into the arrays below. Do not edit the +// words by hand: MOBILEGL_BAKED_INTERNAL_SHADERS (the same test, run as a gate) recompiles +// every source in its table and reds on the first word that disagrees. +#pragma once + +static constexpr Uint32 kWireDepthMipmapVertexSpirv[] = { + 0x07230203u, 0x00010000u, 0x0008000bu, 0x00000071u, 0x00000000u, 0x00020011u, 0x00000001u, 0x0006000bu, + 0x00000001u, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0x00000000u, 0x0003000eu, 0x00000000u, 0x00000001u, + 0x0008000fu, 0x00000000u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x00000016u, 0x0000005eu, 0x00000067u, + 0x00030003u, 0x00000002u, 0x000001c2u, 0x00040005u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x00030005u, + 0x00000009u, 0x00007675u, 0x00060005u, 0x00000016u, 0x565f6c67u, 0x65747265u, 0x646e4978u, 0x00007865u, + 0x00050005u, 0x00000019u, 0x65646e69u, 0x6c626178u, 0x00000065u, 0x00030005u, 0x0000001cu, 0x00000070u, + 0x00060005u, 0x0000001fu, 0x74706544u, 0x70694d68u, 0x5270616du, 0x00746365u, 0x00050006u, 0x0000001fu, + 0x00000000u, 0x52637273u, 0x00746365u, 0x00050006u, 0x0000001fu, 0x00000001u, 0x52747364u, 0x00746365u, + 0x00080006u, 0x0000001fu, 0x00000002u, 0x66727573u, 0x54656361u, 0x736e6172u, 0x6d726f66u, 0x00000000u, + 0x00070006u, 0x0000001fu, 0x00000003u, 0x54637273u, 0x6c657865u, 0x657a6953u, 0x00000000u, 0x00040005u, + 0x00000021u, 0x74636572u, 0x00000000u, 0x00060005u, 0x0000005cu, 0x505f6c67u, 0x65567265u, 0x78657472u, + 0x00000000u, 0x00060006u, 0x0000005cu, 0x00000000u, 0x505f6c67u, 0x7469736fu, 0x006e6f69u, 0x00070006u, + 0x0000005cu, 0x00000001u, 0x505f6c67u, 0x746e696fu, 0x657a6953u, 0x00000000u, 0x00070006u, 0x0000005cu, + 0x00000002u, 0x435f6c67u, 0x4470696cu, 0x61747369u, 0x0065636eu, 0x00070006u, 0x0000005cu, 0x00000003u, + 0x435f6c67u, 0x446c6c75u, 0x61747369u, 0x0065636eu, 0x00030005u, 0x0000005eu, 0x00000000u, 0x00050005u, + 0x00000067u, 0x43786574u, 0x64726f6fu, 0x00000000u, 0x00040047u, 0x00000016u, 0x0000000bu, 0x0000002au, + 0x00030047u, 0x0000001fu, 0x00000002u, 0x00050048u, 0x0000001fu, 0x00000000u, 0x00000023u, 0x00000000u, + 0x00050048u, 0x0000001fu, 0x00000001u, 0x00000023u, 0x00000010u, 0x00050048u, 0x0000001fu, 0x00000002u, + 0x00000023u, 0x00000020u, 0x00050048u, 0x0000001fu, 0x00000003u, 0x00000023u, 0x00000028u, 0x00030047u, + 0x0000005cu, 0x00000002u, 0x00050048u, 0x0000005cu, 0x00000000u, 0x0000000bu, 0x00000000u, 0x00050048u, + 0x0000005cu, 0x00000001u, 0x0000000bu, 0x00000001u, 0x00050048u, 0x0000005cu, 0x00000002u, 0x0000000bu, + 0x00000003u, 0x00050048u, 0x0000005cu, 0x00000003u, 0x0000000bu, 0x00000004u, 0x00040047u, 0x00000067u, + 0x0000001eu, 0x00000000u, 0x00020013u, 0x00000002u, 0x00030021u, 0x00000003u, 0x00000002u, 0x00030016u, + 0x00000006u, 0x00000020u, 0x00040017u, 0x00000007u, 0x00000006u, 0x00000002u, 0x00040020u, 0x00000008u, + 0x00000007u, 0x00000007u, 0x00040015u, 0x0000000au, 0x00000020u, 0x00000000u, 0x0004002bu, 0x0000000au, + 0x0000000bu, 0x00000006u, 0x0004001cu, 0x0000000cu, 0x00000007u, 0x0000000bu, 0x0004002bu, 0x00000006u, + 0x0000000du, 0x00000000u, 0x0005002cu, 0x00000007u, 0x0000000eu, 0x0000000du, 0x0000000du, 0x0004002bu, + 0x00000006u, 0x0000000fu, 0x3f800000u, 0x0005002cu, 0x00000007u, 0x00000010u, 0x0000000fu, 0x0000000du, + 0x0005002cu, 0x00000007u, 0x00000011u, 0x0000000du, 0x0000000fu, 0x0005002cu, 0x00000007u, 0x00000012u, + 0x0000000fu, 0x0000000fu, 0x0009002cu, 0x0000000cu, 0x00000013u, 0x0000000eu, 0x00000010u, 0x00000011u, + 0x00000011u, 0x00000010u, 0x00000012u, 0x00040015u, 0x00000014u, 0x00000020u, 0x00000001u, 0x00040020u, + 0x00000015u, 0x00000001u, 0x00000014u, 0x0004003bu, 0x00000015u, 0x00000016u, 0x00000001u, 0x00040020u, + 0x00000018u, 0x00000007u, 0x0000000cu, 0x00040017u, 0x0000001du, 0x00000006u, 0x00000004u, 0x00040017u, + 0x0000001eu, 0x00000014u, 0x00000002u, 0x0006001eu, 0x0000001fu, 0x0000001du, 0x0000001du, 0x00000014u, + 0x0000001eu, 0x00040020u, 0x00000020u, 0x00000009u, 0x0000001fu, 0x0004003bu, 0x00000020u, 0x00000021u, + 0x00000009u, 0x0004002bu, 0x00000014u, 0x00000022u, 0x00000001u, 0x00040020u, 0x00000023u, 0x00000009u, + 0x0000001du, 0x0004002bu, 0x00000006u, 0x0000002du, 0x40000000u, 0x0004002bu, 0x0000000au, 0x00000031u, + 0x00000001u, 0x00040020u, 0x00000032u, 0x00000007u, 0x00000006u, 0x0004002bu, 0x00000014u, 0x00000037u, + 0x00000002u, 0x00040020u, 0x00000038u, 0x00000009u, 0x00000014u, 0x00020014u, 0x0000003bu, 0x0004002bu, + 0x0000000au, 0x00000042u, 0x00000000u, 0x0004002bu, 0x00000014u, 0x00000051u, 0x00000003u, 0x0004001cu, + 0x0000005bu, 0x00000006u, 0x00000031u, 0x0006001eu, 0x0000005cu, 0x0000001du, 0x00000006u, 0x0000005bu, + 0x0000005bu, 0x00040020u, 0x0000005du, 0x00000003u, 0x0000005cu, 0x0004003bu, 0x0000005du, 0x0000005eu, + 0x00000003u, 0x0004002bu, 0x00000014u, 0x0000005fu, 0x00000000u, 0x00040020u, 0x00000064u, 0x00000003u, + 0x0000001du, 0x00040020u, 0x00000066u, 0x00000003u, 0x00000007u, 0x0004003bu, 0x00000066u, 0x00000067u, + 0x00000003u, 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200f8u, 0x00000005u, + 0x0004003bu, 0x00000008u, 0x00000009u, 0x00000007u, 0x0004003bu, 0x00000018u, 0x00000019u, 0x00000007u, + 0x0004003bu, 0x00000008u, 0x0000001cu, 0x00000007u, 0x0004003du, 0x00000014u, 0x00000017u, 0x00000016u, + 0x0003003eu, 0x00000019u, 0x00000013u, 0x00050041u, 0x00000008u, 0x0000001au, 0x00000019u, 0x00000017u, + 0x0004003du, 0x00000007u, 0x0000001bu, 0x0000001au, 0x0003003eu, 0x00000009u, 0x0000001bu, 0x00050041u, + 0x00000023u, 0x00000024u, 0x00000021u, 0x00000022u, 0x0004003du, 0x0000001du, 0x00000025u, 0x00000024u, + 0x0007004fu, 0x00000007u, 0x00000026u, 0x00000025u, 0x00000025u, 0x00000000u, 0x00000001u, 0x0004003du, + 0x00000007u, 0x00000027u, 0x00000009u, 0x00050041u, 0x00000023u, 0x00000028u, 0x00000021u, 0x00000022u, + 0x0004003du, 0x0000001du, 0x00000029u, 0x00000028u, 0x0007004fu, 0x00000007u, 0x0000002au, 0x00000029u, + 0x00000029u, 0x00000002u, 0x00000003u, 0x00050085u, 0x00000007u, 0x0000002bu, 0x00000027u, 0x0000002au, + 0x00050081u, 0x00000007u, 0x0000002cu, 0x00000026u, 0x0000002bu, 0x0005008eu, 0x00000007u, 0x0000002eu, + 0x0000002cu, 0x0000002du, 0x00050050u, 0x00000007u, 0x0000002fu, 0x0000000fu, 0x0000000fu, 0x00050083u, + 0x00000007u, 0x00000030u, 0x0000002eu, 0x0000002fu, 0x0003003eu, 0x0000001cu, 0x00000030u, 0x00050041u, + 0x00000032u, 0x00000033u, 0x0000001cu, 0x00000031u, 0x0004003du, 0x00000006u, 0x00000034u, 0x00000033u, + 0x0004007fu, 0x00000006u, 0x00000035u, 0x00000034u, 0x00050041u, 0x00000032u, 0x00000036u, 0x0000001cu, + 0x00000031u, 0x0003003eu, 0x00000036u, 0x00000035u, 0x00050041u, 0x00000038u, 0x00000039u, 0x00000021u, + 0x00000037u, 0x0004003du, 0x00000014u, 0x0000003au, 0x00000039u, 0x000500aau, 0x0000003bu, 0x0000003cu, + 0x0000003au, 0x00000022u, 0x000300f7u, 0x0000003eu, 0x00000000u, 0x000400fau, 0x0000003cu, 0x0000003du, + 0x00000046u, 0x000200f8u, 0x0000003du, 0x00050041u, 0x00000032u, 0x0000003fu, 0x0000001cu, 0x00000031u, + 0x0004003du, 0x00000006u, 0x00000040u, 0x0000003fu, 0x0004007fu, 0x00000006u, 0x00000041u, 0x00000040u, + 0x00050041u, 0x00000032u, 0x00000043u, 0x0000001cu, 0x00000042u, 0x0004003du, 0x00000006u, 0x00000044u, + 0x00000043u, 0x00050050u, 0x00000007u, 0x00000045u, 0x00000041u, 0x00000044u, 0x0003003eu, 0x0000001cu, + 0x00000045u, 0x000200f9u, 0x0000003eu, 0x000200f8u, 0x00000046u, 0x00050041u, 0x00000038u, 0x00000047u, + 0x00000021u, 0x00000037u, 0x0004003du, 0x00000014u, 0x00000048u, 0x00000047u, 0x000500aau, 0x0000003bu, + 0x00000049u, 0x00000048u, 0x00000037u, 0x000300f7u, 0x0000004bu, 0x00000000u, 0x000400fau, 0x00000049u, + 0x0000004au, 0x0000004eu, 0x000200f8u, 0x0000004au, 0x0004003du, 0x00000007u, 0x0000004cu, 0x0000001cu, + 0x0004007fu, 0x00000007u, 0x0000004du, 0x0000004cu, 0x0003003eu, 0x0000001cu, 0x0000004du, 0x000200f9u, + 0x0000004bu, 0x000200f8u, 0x0000004eu, 0x00050041u, 0x00000038u, 0x0000004fu, 0x00000021u, 0x00000037u, + 0x0004003du, 0x00000014u, 0x00000050u, 0x0000004fu, 0x000500aau, 0x0000003bu, 0x00000052u, 0x00000050u, + 0x00000051u, 0x000300f7u, 0x00000054u, 0x00000000u, 0x000400fau, 0x00000052u, 0x00000053u, 0x00000054u, + 0x000200f8u, 0x00000053u, 0x00050041u, 0x00000032u, 0x00000055u, 0x0000001cu, 0x00000031u, 0x0004003du, + 0x00000006u, 0x00000056u, 0x00000055u, 0x00050041u, 0x00000032u, 0x00000057u, 0x0000001cu, 0x00000042u, + 0x0004003du, 0x00000006u, 0x00000058u, 0x00000057u, 0x0004007fu, 0x00000006u, 0x00000059u, 0x00000058u, + 0x00050050u, 0x00000007u, 0x0000005au, 0x00000056u, 0x00000059u, 0x0003003eu, 0x0000001cu, 0x0000005au, + 0x000200f9u, 0x00000054u, 0x000200f8u, 0x00000054u, 0x000200f9u, 0x0000004bu, 0x000200f8u, 0x0000004bu, + 0x000200f9u, 0x0000003eu, 0x000200f8u, 0x0000003eu, 0x0004003du, 0x00000007u, 0x00000060u, 0x0000001cu, + 0x00050051u, 0x00000006u, 0x00000061u, 0x00000060u, 0x00000000u, 0x00050051u, 0x00000006u, 0x00000062u, + 0x00000060u, 0x00000001u, 0x00070050u, 0x0000001du, 0x00000063u, 0x00000061u, 0x00000062u, 0x0000000du, + 0x0000000fu, 0x00050041u, 0x00000064u, 0x00000065u, 0x0000005eu, 0x0000005fu, 0x0003003eu, 0x00000065u, + 0x00000063u, 0x00050041u, 0x00000023u, 0x00000068u, 0x00000021u, 0x0000005fu, 0x0004003du, 0x0000001du, + 0x00000069u, 0x00000068u, 0x0007004fu, 0x00000007u, 0x0000006au, 0x00000069u, 0x00000069u, 0x00000000u, + 0x00000001u, 0x0004003du, 0x00000007u, 0x0000006bu, 0x00000009u, 0x00050041u, 0x00000023u, 0x0000006cu, + 0x00000021u, 0x0000005fu, 0x0004003du, 0x0000001du, 0x0000006du, 0x0000006cu, 0x0007004fu, 0x00000007u, + 0x0000006eu, 0x0000006du, 0x0000006du, 0x00000002u, 0x00000003u, 0x00050085u, 0x00000007u, 0x0000006fu, + 0x0000006bu, 0x0000006eu, 0x00050081u, 0x00000007u, 0x00000070u, 0x0000006au, 0x0000006fu, 0x0003003eu, + 0x00000067u, 0x00000070u, 0x000100fdu, 0x00010038u, +}; + +static constexpr Uint32 kWireDepthMipmapFragmentSpirv[] = { + 0x07230203u, 0x00010000u, 0x0008000bu, 0x00000059u, 0x00000000u, 0x00020011u, 0x00000001u, 0x0006000bu, + 0x00000001u, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0x00000000u, 0x0003000eu, 0x00000000u, 0x00000001u, + 0x0007000fu, 0x00000004u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x0000000du, 0x0000004fu, 0x00030010u, + 0x00000004u, 0x00000007u, 0x00030010u, 0x00000004u, 0x0000000cu, 0x00030003u, 0x00000002u, 0x000001c2u, + 0x00040005u, 0x00000004u, 0x6e69616du, 0x00000000u, 0x00040005u, 0x00000009u, 0x42637273u, 0x00657361u, + 0x00050005u, 0x0000000du, 0x43786574u, 0x64726f6fu, 0x00000000u, 0x00060005u, 0x00000010u, 0x74706544u, + 0x70694d68u, 0x5270616du, 0x00746365u, 0x00050006u, 0x00000010u, 0x00000000u, 0x52637273u, 0x00746365u, + 0x00050006u, 0x00000010u, 0x00000001u, 0x52747364u, 0x00746365u, 0x00080006u, 0x00000010u, 0x00000002u, + 0x66727573u, 0x54656361u, 0x736e6172u, 0x6d726f66u, 0x00000000u, 0x00070006u, 0x00000010u, 0x00000003u, + 0x54637273u, 0x6c657865u, 0x657a6953u, 0x00000000u, 0x00040005u, 0x00000012u, 0x74636572u, 0x00000000u, + 0x00040005u, 0x0000001au, 0x4d637273u, 0x00007861u, 0x00040005u, 0x00000021u, 0x74706564u, 0x00003068u, + 0x00050005u, 0x00000025u, 0x72756f73u, 0x6d496563u, 0x00656761u, 0x00040005u, 0x00000031u, 0x74706564u, + 0x00003168u, 0x00040005u, 0x0000003bu, 0x74706564u, 0x00003268u, 0x00040005u, 0x00000045u, 0x74706564u, + 0x00003368u, 0x00060005u, 0x0000004fu, 0x465f6c67u, 0x44676172u, 0x68747065u, 0x00000000u, 0x00040047u, + 0x0000000du, 0x0000001eu, 0x00000000u, 0x00030047u, 0x00000010u, 0x00000002u, 0x00050048u, 0x00000010u, + 0x00000000u, 0x00000023u, 0x00000000u, 0x00050048u, 0x00000010u, 0x00000001u, 0x00000023u, 0x00000010u, + 0x00050048u, 0x00000010u, 0x00000002u, 0x00000023u, 0x00000020u, 0x00050048u, 0x00000010u, 0x00000003u, + 0x00000023u, 0x00000028u, 0x00040047u, 0x00000025u, 0x00000021u, 0x00000000u, 0x00040047u, 0x00000025u, + 0x00000022u, 0x00000000u, 0x00040047u, 0x0000004fu, 0x0000000bu, 0x00000016u, 0x00020013u, 0x00000002u, + 0x00030021u, 0x00000003u, 0x00000002u, 0x00040015u, 0x00000006u, 0x00000020u, 0x00000001u, 0x00040017u, + 0x00000007u, 0x00000006u, 0x00000002u, 0x00040020u, 0x00000008u, 0x00000007u, 0x00000007u, 0x00030016u, + 0x0000000au, 0x00000020u, 0x00040017u, 0x0000000bu, 0x0000000au, 0x00000002u, 0x00040020u, 0x0000000cu, + 0x00000001u, 0x0000000bu, 0x0004003bu, 0x0000000cu, 0x0000000du, 0x00000001u, 0x00040017u, 0x0000000fu, + 0x0000000au, 0x00000004u, 0x0006001eu, 0x00000010u, 0x0000000fu, 0x0000000fu, 0x00000006u, 0x00000007u, + 0x00040020u, 0x00000011u, 0x00000009u, 0x00000010u, 0x0004003bu, 0x00000011u, 0x00000012u, 0x00000009u, + 0x0004002bu, 0x00000006u, 0x00000013u, 0x00000003u, 0x00040020u, 0x00000014u, 0x00000009u, 0x00000007u, + 0x0004002bu, 0x00000006u, 0x0000001du, 0x00000001u, 0x0005002cu, 0x00000007u, 0x0000001eu, 0x0000001du, + 0x0000001du, 0x00040020u, 0x00000020u, 0x00000007u, 0x0000000au, 0x00090019u, 0x00000022u, 0x0000000au, + 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x0003001bu, 0x00000023u, + 0x00000022u, 0x00040020u, 0x00000024u, 0x00000000u, 0x00000023u, 0x0004003bu, 0x00000024u, 0x00000025u, + 0x00000000u, 0x0004002bu, 0x00000006u, 0x00000028u, 0x00000000u, 0x0005002cu, 0x00000007u, 0x00000029u, + 0x00000028u, 0x00000028u, 0x00040015u, 0x0000002eu, 0x00000020u, 0x00000000u, 0x0004002bu, 0x0000002eu, + 0x0000002fu, 0x00000000u, 0x0005002cu, 0x00000007u, 0x00000034u, 0x0000001du, 0x00000028u, 0x0005002cu, + 0x00000007u, 0x0000003eu, 0x00000028u, 0x0000001du, 0x00040020u, 0x0000004eu, 0x00000003u, 0x0000000au, + 0x0004003bu, 0x0000004eu, 0x0000004fu, 0x00000003u, 0x0004002bu, 0x0000000au, 0x00000050u, 0x3e800000u, + 0x00050036u, 0x00000002u, 0x00000004u, 0x00000000u, 0x00000003u, 0x000200f8u, 0x00000005u, 0x0004003bu, + 0x00000008u, 0x00000009u, 0x00000007u, 0x0004003bu, 0x00000008u, 0x0000001au, 0x00000007u, 0x0004003bu, + 0x00000020u, 0x00000021u, 0x00000007u, 0x0004003bu, 0x00000020u, 0x00000031u, 0x00000007u, 0x0004003bu, + 0x00000020u, 0x0000003bu, 0x00000007u, 0x0004003bu, 0x00000020u, 0x00000045u, 0x00000007u, 0x0004003du, + 0x0000000bu, 0x0000000eu, 0x0000000du, 0x00050041u, 0x00000014u, 0x00000015u, 0x00000012u, 0x00000013u, + 0x0004003du, 0x00000007u, 0x00000016u, 0x00000015u, 0x0004006fu, 0x0000000bu, 0x00000017u, 0x00000016u, + 0x00050085u, 0x0000000bu, 0x00000018u, 0x0000000eu, 0x00000017u, 0x0004006eu, 0x00000007u, 0x00000019u, + 0x00000018u, 0x0003003eu, 0x00000009u, 0x00000019u, 0x00050041u, 0x00000014u, 0x0000001bu, 0x00000012u, + 0x00000013u, 0x0004003du, 0x00000007u, 0x0000001cu, 0x0000001bu, 0x00050082u, 0x00000007u, 0x0000001fu, + 0x0000001cu, 0x0000001eu, 0x0003003eu, 0x0000001au, 0x0000001fu, 0x0004003du, 0x00000023u, 0x00000026u, + 0x00000025u, 0x0004003du, 0x00000007u, 0x00000027u, 0x00000009u, 0x0004003du, 0x00000007u, 0x0000002au, + 0x0000001au, 0x0008000cu, 0x00000007u, 0x0000002bu, 0x00000001u, 0x0000002du, 0x00000027u, 0x00000029u, + 0x0000002au, 0x00040064u, 0x00000022u, 0x0000002cu, 0x00000026u, 0x0007005fu, 0x0000000fu, 0x0000002du, + 0x0000002cu, 0x0000002bu, 0x00000002u, 0x00000028u, 0x00050051u, 0x0000000au, 0x00000030u, 0x0000002du, + 0x00000000u, 0x0003003eu, 0x00000021u, 0x00000030u, 0x0004003du, 0x00000023u, 0x00000032u, 0x00000025u, + 0x0004003du, 0x00000007u, 0x00000033u, 0x00000009u, 0x00050080u, 0x00000007u, 0x00000035u, 0x00000033u, + 0x00000034u, 0x0004003du, 0x00000007u, 0x00000036u, 0x0000001au, 0x0008000cu, 0x00000007u, 0x00000037u, + 0x00000001u, 0x0000002du, 0x00000035u, 0x00000029u, 0x00000036u, 0x00040064u, 0x00000022u, 0x00000038u, + 0x00000032u, 0x0007005fu, 0x0000000fu, 0x00000039u, 0x00000038u, 0x00000037u, 0x00000002u, 0x00000028u, + 0x00050051u, 0x0000000au, 0x0000003au, 0x00000039u, 0x00000000u, 0x0003003eu, 0x00000031u, 0x0000003au, + 0x0004003du, 0x00000023u, 0x0000003cu, 0x00000025u, 0x0004003du, 0x00000007u, 0x0000003du, 0x00000009u, + 0x00050080u, 0x00000007u, 0x0000003fu, 0x0000003du, 0x0000003eu, 0x0004003du, 0x00000007u, 0x00000040u, + 0x0000001au, 0x0008000cu, 0x00000007u, 0x00000041u, 0x00000001u, 0x0000002du, 0x0000003fu, 0x00000029u, + 0x00000040u, 0x00040064u, 0x00000022u, 0x00000042u, 0x0000003cu, 0x0007005fu, 0x0000000fu, 0x00000043u, + 0x00000042u, 0x00000041u, 0x00000002u, 0x00000028u, 0x00050051u, 0x0000000au, 0x00000044u, 0x00000043u, + 0x00000000u, 0x0003003eu, 0x0000003bu, 0x00000044u, 0x0004003du, 0x00000023u, 0x00000046u, 0x00000025u, + 0x0004003du, 0x00000007u, 0x00000047u, 0x00000009u, 0x00050080u, 0x00000007u, 0x00000048u, 0x00000047u, + 0x0000001eu, 0x0004003du, 0x00000007u, 0x00000049u, 0x0000001au, 0x0008000cu, 0x00000007u, 0x0000004au, + 0x00000001u, 0x0000002du, 0x00000048u, 0x00000029u, 0x00000049u, 0x00040064u, 0x00000022u, 0x0000004bu, + 0x00000046u, 0x0007005fu, 0x0000000fu, 0x0000004cu, 0x0000004bu, 0x0000004au, 0x00000002u, 0x00000028u, + 0x00050051u, 0x0000000au, 0x0000004du, 0x0000004cu, 0x00000000u, 0x0003003eu, 0x00000045u, 0x0000004du, + 0x0004003du, 0x0000000au, 0x00000051u, 0x00000021u, 0x0004003du, 0x0000000au, 0x00000052u, 0x00000031u, + 0x00050081u, 0x0000000au, 0x00000053u, 0x00000051u, 0x00000052u, 0x0004003du, 0x0000000au, 0x00000054u, + 0x0000003bu, 0x00050081u, 0x0000000au, 0x00000055u, 0x00000053u, 0x00000054u, 0x0004003du, 0x0000000au, + 0x00000056u, 0x00000045u, 0x00050081u, 0x0000000au, 0x00000057u, 0x00000055u, 0x00000056u, 0x00050085u, + 0x0000000au, 0x00000058u, 0x00000050u, 0x00000057u, 0x0003003eu, 0x0000004fu, 0x00000058u, 0x000100fdu, + 0x00010038u, +}; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc index 218bbdaf..0ac2d8c3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/WireFramebuffer.inc @@ -828,10 +828,26 @@ if (base >= fullLevelCount) MagmaWireFatal("mipmap-base-extent"); const Uint32 count = std::min(logicalEnd - logicalBase, fullLevelCount - base); if (count <= 1) return; + // P7 wave 2-B, CONTRACT-P7 §3.2: `depth-stencil-mipmap@P7` RETIRES FOR DEPTH AND + // DECLINES FOR DEPTH|STENCIL - and the decline comes BEFORE the chain is grown, so a + // level this verb is not going to fill is not created and then recorded as defined. + // + // The combined case is a decline rather than a Fatal because the monolith arm does no + // better: its shader fallback asserts depth-only (VulkanRenderer.cpp's GenerateMipmap, + // "shader fallback only supports depth-only textures") and an assert is nothing in the + // release build both arms ship as. Nothing in GL promises a stencil mip either - the + // pass writes gl_FragDepth and would leave the stencil aspect of the level it produced + // undefined, which is worse than leaving the whole level alone and saying so. + if (resource->aspect != VK_IMAGE_ASPECT_COLOR_BIT && resource->aspect != VK_IMAGE_ASPECT_DEPTH_BIT) { + MGLOG_E_ONCE("DirectVulkan::GenerateWireMipmap: aspect 0x%x (a combined depth/stencil or " + "stencil-only texture, format %d) has no mip generation on either arm; " + "declining and leaving levels %u..%u as they are", + static_cast(resource->aspect), static_cast(resource->format), + base + 1, base + count - 1); + return; + } if (!m_textureManager->GrowWireTextureMipChain(handle,base+count,frame.commandBuffer)) MagmaWireFatal("mipmap-growth"); - if (resource->aspect != VK_IMAGE_ASPECT_COLOR_BIT && resource->aspect != VK_IMAGE_ASPECT_DEPTH_BIT) - MagmaWireFatal("depth-stencil-mipmap@P7"); VkFormatProperties props{}; const VkFormat format = viewFormat == VK_FORMAT_UNDEFINED ? resource->format : viewFormat; vkGetPhysicalDeviceFormatProperties(m_physicalDevice.handle,format,&props); @@ -841,7 +857,52 @@ (props.optimalTilingFeatures & required) == required; const VkFilter filter = props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; - if (!nativeBlit) { + if (!nativeBlit && resource->aspect == VK_IMAGE_ASPECT_DEPTH_BIT) { + // P7 wave 2-B, CONTRACT-P7 §5.1 (A): THE DEPTH ARM, and it is first because a + // depth format without BLIT_DST is the ordinary case, not the exotic one - + // VK_FORMAT_FEATURE_BLIT_DST is optional for depth and plenty of devices decline + // it. Before this package the whole branch below was colour-only, so such a + // texture reached `mipmap-shader-format-or-shape` on its very first disjunction + // while the monolith arm quietly generated the chain with a shader. + // + // The per-level pass is WireDepthMipmap.inc's, which is the monolith's fragment + // shader with the monolith's arithmetic on a baked pipeline that owns no frontend + // object - §3.2's "observably the monolith's" without the GL program the monolith + // needs to get there. + if (baseLayer >= resource->arrayLayers || layerCount > resource->arrayLayers - baseLayer) + MagmaWireFatal(MagmaWireShapeDetail("mipmap-shader-format-or-shape", format, + resource->format, props, resource->aspect, resource->viewType, + resource->usageFlags, resource->extent, resource->depth, resource->mipLevels, + baseLayer, layerCount, resource->arrayLayers).c_str()); + for (Uint32 level = base + 1; level < base + count; ++level) { + for (Uint32 layer = baseLayer; layer < baseLayer + layerCount; ++layer) { + WireImage source{}; + source.image = resource->image; + source.format = format; + source.aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + source.layout = resource->layout; + source.trackedLayout = &resource->layout; + source.levels = resource->mipLevels; + source.level = level - 1; + source.layer = layer; + source.extent = {std::max(resource->extent.width >> (level - 1), 1u), + std::max(resource->extent.height >> (level - 1), 1u)}; + WireImage destination = source; + destination.level = level; + destination.extent = {std::max(resource->extent.width >> level, 1u), + std::max(resource->extent.height >> level, 1u)}; + // The pass reports the SHAPE it cannot take (1D, 3D, multisample, a + // format without sampled or depth-attachment support), so the refusal + // keeps its name and gains the reason. + if (!GenerateWireDepthMipLevel(source, destination)) + MagmaWireFatal(MagmaWireShapeDetail("mipmap-shader-format-or-shape", format, + resource->format, props, resource->aspect, resource->viewType, + resource->usageFlags, resource->extent, resource->depth, + resource->mipLevels, baseLayer, layerCount, + resource->arrayLayers).c_str()); + } + } + } else if (!nativeBlit) { // Packed floating-point color formats may support sampling and // rendering without BLIT_DST. Generate from actual GPU mip contents // through the native shader pass; no client or staged texels enter. diff --git a/MobileGL/MG_IntegrationTest/CMakeLists.txt b/MobileGL/MG_IntegrationTest/CMakeLists.txt index 2718a803..51163f64 100644 --- a/MobileGL/MG_IntegrationTest/CMakeLists.txt +++ b/MobileGL/MG_IntegrationTest/CMakeLists.txt @@ -2710,6 +2710,26 @@ if (MOBILEGL_BUILD_DISAGGREGATED) ${mglItestArmProperties} ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_MIPMAP=${shaderMipTier}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-shadermip${mglItestArmLogTag}-tier${shaderMipTier}.log") endforeach() + # The DEPTH half of the same knob (CONTRACT-P7 §5.1 (A)). ONE TIER, not two: the depth + # pass renders into a depth ATTACHMENT view of the destination level, which a depth + # image always has usage for - there is no "cannot be attached" shape to force, so + # tier 2 would register a second copy of tier 1's run. + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectVulkan.${mglItestArm}.DepthMip." + TEST_FILTER "F1WireScenario.GenerateMipmapDepthWithoutNativeBlitPixels" + DISCOVERY_TIMEOUT 30 + PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT} + ${mglItestArmProperties} + ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MGITEST_MAGMA_FORCE_SHADER_MIPMAP=1\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-depthmip${mglItestArmLogTag}.log") + # NO KNOB on the decline: it is decided on the aspect before the blit-support question + # is asked, so the plain Fm environment reaches it on every driver. + gtest_discover_tests(MobileGLIntegrationTest + TEST_PREFIX "DirectVulkan.${mglItestArm}.Fm." + TEST_FILTER "F1WireScenario.GenerateMipmapDepthStencilDeclinesAndKeepsTheSession" + DISCOVERY_TIMEOUT 30 + PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT} + ${mglItestArmProperties} + ENVIRONMENT "${mglItestMagmaWireEnvironment}\;MOBILEGL_LOG_FILE_PATH=${CMAKE_CURRENT_BINARY_DIR}/p7-dsmipdecline${mglItestArmLogTag}.log") endforeach() endif() diff --git a/MobileGL/MG_IntegrationTest/Scenarios/F1WireScenario.cpp b/MobileGL/MG_IntegrationTest/Scenarios/F1WireScenario.cpp index ba3d2b6e..97f400e6 100644 --- a/MobileGL/MG_IntegrationTest/Scenarios/F1WireScenario.cpp +++ b/MobileGL/MG_IntegrationTest/Scenarios/F1WireScenario.cpp @@ -560,6 +560,109 @@ TEST_F(F1WireScenario, GenerateMipmapDepthPixels) { EXPECT_NEAR(pixel, 0.375f, 0.00001f); } +// P7 wave 2-B, CONTRACT-P7 §5.1 (A): the baked depth mip program, on the two GL depth formats +// that reach it as a depth-only Vulkan aspect (DEPTH_COMPONENT24 -> X8_D24_UNORM_PACK32, +// DEPTH_COMPONENT32F -> D32_SFLOAT). GenerateMipmapDepthPixels above passes on this host +// because lavapipe blits depth natively; the knob removes that arm, which is what an Adreno +// does by itself - VK_FORMAT_FEATURE_BLIT_DST is OPTIONAL for depth formats, so a depth chain +// through a shader is the ordinary case and not the exotic one. +// +// TWO HALVES AND A BAND THAT IS NOT ASSERTED. The generated level is read back through a real +// sampled attachment, so a flat fill would prove nothing: the source is split at its middle +// row instead. The ported filter takes a 2x2 box at ivec2(texCoord * srcTexelSize), which +// lands half a texel off the destination centre - the monolith's own arithmetic, kept +// deliberately (§3.2 retires a refusal by matching that arm, defects included). Under either +// reading of that half texel, destination rows 0..2 come only from the lower half and rows +// 4..7 only from the upper half; row 3 is the straddle and is the one row this case does not +// pin, because pinning it would assert the half-texel offset rather than the mip. +TEST_F(F1WireScenario, GenerateMipmapDepthWithoutNativeBlitPixels) { + if (!Ready()) return; + const std::string tier = SplitLane::MarkerValue("MGITEST_MAGMA_FORCE_SHADER_MIPMAP"); + if (tier.empty()) + GTEST_SKIP() << "MGITEST_MAGMA_FORCE_SHADER_MIPMAP is unset: this driver blits depth " + "natively, so the baked depth mip program under test is not entered"; + for (const GLenum internalFormat : {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F}) { + GLuint depth = 0; + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexStorage2D(GL_TEXTURE_2D, 5, internalFormat, 16, 16); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE)) + << "format 0x" << std::hex << internalFormat; + glDepthMask(GL_TRUE); + glDisable(GL_SCISSOR_TEST); + glClearDepth(0.75); + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, 16, 8); + glClearDepth(0.25); + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + const auto before = PeekSplitRuntime().emitSeq; + glGenerateMipmap(GL_TEXTURE_2D); + ASSERT_GT(PeekSplitRuntime().emitSeq, before) << "F1.DepthMip.wire"; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 1); + ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE)); + GLfloat rows[8]{}; + glReadPixels(2, 0, 1, 8, GL_DEPTH_COMPONENT, GL_FLOAT, rows); + ASSERT_EQ(FirstGLError(), GLenum(GL_NO_ERROR)) << "F1.DepthMip.error"; + for (int row = 0; row < 8; ++row) { + if (row == 3) continue; + const GLfloat expected = row < 3 ? 0.25f : 0.75f; + EXPECT_NEAR(rows[row], expected, 0.002f) + << "F1.DepthMip.pixels tier=" << tier << " format=0x" << std::hex << internalFormat + << std::dec << " row=" << row; + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + glDeleteTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, texture); + } + glClearDepth(1.0); +} + +// The OTHER half of `depth-stencil-mipmap@P7`, and it is a decline rather than a retirement +// (CONTRACT-P7 §3.2): a combined depth/stencil texture has no mip generation on EITHER arm - +// the monolith's shader fallback asserts depth-only, and an assert is nothing in the release +// build both arms ship as. What this case pins is that the wire arm now says so and carries +// on, rather than taking the session down: no GL error, the session still alive afterwards, +// and level zero still holding what was cleared into it. +// +// No knob: the decline is decided on the ASPECT, before the blit-support question is asked, +// so it fires on every driver. +// Red once (executed, reverted): restore the MagmaWireFatal and this case dies with +// Fatal{UnmigratedVerb, "Magma:depth-stencil-mipmap@P7"}. +TEST_F(F1WireScenario, GenerateMipmapDepthStencilDeclinesAndKeepsTheSession) { + if (!Ready()) return; + GLuint depthStencil = 0; + glGenTextures(1, &depthStencil); + glBindTexture(GL_TEXTURE_2D, depthStencil); + glTexStorage2D(GL_TEXTURE_2D, 4, GL_DEPTH24_STENCIL8, 8, 8); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE)); + glDepthMask(GL_TRUE); + glDisable(GL_SCISSOR_TEST); + glClearDepth(0.5); + glClear(GL_DEPTH_BUFFER_BIT); + glGenerateMipmap(GL_TEXTURE_2D); + EXPECT_EQ(FirstGLError(), GLenum(GL_NO_ERROR)) << "F1.DepthStencilMip.error"; + // The session is what the retired Fatal used to take with it. A readback is a round trip + // through the server, so it answers that question and the level-zero one at once. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); + ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GLenum(GL_FRAMEBUFFER_COMPLETE)); + GLfloat level0 = 0; + glReadPixels(1, 1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &level0); + EXPECT_EQ(FirstGLError(), GLenum(GL_NO_ERROR)) << "F1.DepthStencilMip.readback"; + EXPECT_NEAR(level0, 0.5f, 0.002f) << "F1.DepthStencilMip.level0"; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + glDeleteTextures(1, &depthStencil); + glBindTexture(GL_TEXTURE_2D, texture); + glClearDepth(1.0); +} + TEST_F(F1WireScenario, GenerateMipmapHonorsMutableBaseAndMaxWithoutChangingOtherLevels) { if (!Ready()) return; const std::array colors[5] = { diff --git a/MobileGL/MG_Test/SelfTest/BakedInternalShadersTest.cpp b/MobileGL/MG_Test/SelfTest/BakedInternalShadersTest.cpp new file mode 100644 index 00000000..469a39db --- /dev/null +++ b/MobileGL/MG_Test/SelfTest/BakedInternalShadersTest.cpp @@ -0,0 +1,226 @@ +// MobileGL - MobileGL/MG_Test/SelfTest/BakedInternalShadersTest.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 +// +// MOBILEGL_BAKED_INTERNAL_SHADERS - the freshness gate (CONTRACT-P7 §5.1 (D)). +// +// WHAT A BAKED SPIR-V HEADER ACTUALLY IS: a compiler output committed to the tree, with its +// input committed beside it and NOTHING connecting the two. Edit WireColorBlit.frag and the +// build stays green, the lane stays green, and the shader that runs is the one from before +// the edit - silently, on every device, until somebody reads the words. The tree already had +// three such pairs before this package added a fourth, and one of them (the iterationRP +// witness) was measurably stale: its own header said so in prose, which is exactly as much +// enforcement as prose provides. +// +// So every baked header is recompiled here, from its committed source, with the IN-TREE +// glslang, and compared word for word. +// +// THIS TEST IS THE BAKER, NOT A SECOND OPINION. scripts/bake_internal_shaders.py does not +// compile anything: it runs this binary with MOBILEGL_BAKE_INTERNAL_SHADERS set, takes the +// words it emits, and splices them into the headers. That direction is deliberate. A gate +// that compiles through the glslang LIBRARY while the baker shells out to a glslangValidator +// BINARY has two compilers and no rule about which one is right, and the day their defaults +// diverge - an option the CLI passes by default, a version skew between a system tool and +// the submodule - the gate reds on a header nobody can regenerate. One compiler, one truth, +// and the gate's own output is what the tree stores. +// +// SOURCE PATH: the sources live in the source tree, not next to the binary, so the build +// hands their root in as MOBILEGL_BAKED_SHADER_ROOT. A test that cannot find them FAILS +// rather than skipping: a freshness gate that silently disarms is the thing it exists +// against. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + +// The two Renderer headers are written to be included inside the backend namespace, after +// the project's own type aliases; they name Uint32 and declare nothing else. Including them +// here with a local alias keeps them byte-identical to what VulkanRenderer.cpp compiles - +// the alternative, a copy of the words in this file, is precisely the drift this gate is for. +using Uint32 = std::uint32_t; +#include +#include + +struct BakedShader { + const char* name; // ctest entry name, and the bake file's stem + const char* source; // repository-relative GLSL source + const char* header; // repository-relative header the words live in + const char* symbol; // the array identifier inside that header + EShLanguage stage; + glslang::EShTargetClientVersion client; + glslang::EShTargetLanguageVersion spv; + const std::uint32_t* words; + std::size_t wordCount; +}; + +#define MGL_BAKED_ROW(name, source, header, symbol, stage, client, spv, array) \ + BakedShader{name, source, header, symbol, stage, client, spv, (array), \ + sizeof(array) / sizeof((array)[0])} + +const BakedShader kBakedShaders[] = { + // The Magma wire arms' own programs: no GL program object, no registry entry, no runtime + // transpilation, so the words in the header are the only copy that exists. + MGL_BAKED_ROW("WireColorBlitVertex", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.vert", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h", + "kWireColorBlitVertexSpirv", EShLangVertex, + glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, + kWireColorBlitVertexSpirv), + MGL_BAKED_ROW("WireColorBlitFragment", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlit.frag", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireColorBlitSpirv.h", + "kWireColorBlitFragmentSpirv", EShLangFragment, + glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, + kWireColorBlitFragmentSpirv), + MGL_BAKED_ROW("WireDepthMipmapVertex", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.vert", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmapSpirv.h", + "kWireDepthMipmapVertexSpirv", EShLangVertex, + glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, + kWireDepthMipmapVertexSpirv), + MGL_BAKED_ROW("WireDepthMipmapFragment", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmap.frag", + "MobileGL/MG_Backend/DirectVulkan/Renderer/WireDepthMipmapSpirv.h", + "kWireDepthMipmapFragmentSpirv", EShLangFragment, + glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, + kWireDepthMipmapFragmentSpirv), + // The two driver self-test probes. They are not Magma's, and they are in this table for + // the reason the contract names them: they are baked, so they can be stale, and one of + // them was. + MGL_BAKED_ROW("DriverPostIterationRPWitness", + "MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitness.comp", + "MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitnessSpv.h", + "kDriverPostIterationRPWitnessSpv", EShLangCompute, + glslang::EShTargetVulkan_1_1, glslang::EShTargetSpv_1_3, + MobileGL::MG_Util::SelfTest::kDriverPostIterationRPWitnessSpv), + MGL_BAKED_ROW("PrimitivesGeneratedNoXfbProbeVert", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbe.vert", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h", + "kPrimitivesGeneratedNoXfbProbeVertSpv", EShLangVertex, + glslang::EShTargetVulkan_1_1, glslang::EShTargetSpv_1_3, + MobileGL::MG_Util::SelfTest::kPrimitivesGeneratedNoXfbProbeVertSpv), + MGL_BAKED_ROW("PrimitivesGeneratedNoXfbProbeTesc", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbe.tesc", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h", + "kPrimitivesGeneratedNoXfbProbeTescSpv", EShLangTessControl, + glslang::EShTargetVulkan_1_1, glslang::EShTargetSpv_1_3, + MobileGL::MG_Util::SelfTest::kPrimitivesGeneratedNoXfbProbeTescSpv), + MGL_BAKED_ROW("PrimitivesGeneratedNoXfbProbeTese", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbe.tese", + "MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h", + "kPrimitivesGeneratedNoXfbProbeTeseSpv", EShLangTessEvaluation, + glslang::EShTargetVulkan_1_1, glslang::EShTargetSpv_1_3, + MobileGL::MG_Util::SelfTest::kPrimitivesGeneratedNoXfbProbeTeseSpv), +}; + +#undef MGL_BAKED_ROW + +std::string RepositoryRoot() { +#ifdef MOBILEGL_BAKED_SHADER_ROOT + return std::string(MOBILEGL_BAKED_SHADER_ROOT); +#else + return std::string(); +#endif +} + +// glslang::InitializeProcess is process-wide and refcounted. One call for the whole binary: +// this test never runs MobileGL::Initialize, which is the other caller. +void EnsureGlslangProcess() { + static const bool ready = glslang::InitializeProcess(); + ASSERT_TRUE(ready) << "glslang::InitializeProcess failed"; +} + +class BakedInternalShaders : public ::testing::TestWithParam {}; + +TEST_P(BakedInternalShaders, HeaderMatchesItsSource) { + const BakedShader& row = GetParam(); + ASSERT_NO_FATAL_FAILURE(EnsureGlslangProcess()); + + const std::string root = RepositoryRoot(); + ASSERT_FALSE(root.empty()) + << "MOBILEGL_BAKED_SHADER_ROOT was not defined for this target: the gate cannot find " + "the GLSL sources and must not pass by default"; + const std::string sourcePath = root + "/" + row.source; + std::ifstream in(sourcePath, std::ios::binary); + ASSERT_TRUE(in.good()) << "cannot open " << sourcePath; + std::ostringstream buffer; + buffer << in.rdbuf(); + const std::string source = buffer.str(); + ASSERT_FALSE(source.empty()) << sourcePath << " is empty"; + + glslang::TShader shader(row.stage); + const char* strings[] = {source.c_str()}; + shader.setStrings(strings, 1); + shader.setEnvInput(glslang::EShSourceGlsl, row.stage, glslang::EShClientVulkan, 100); + shader.setEnvClient(glslang::EShClientVulkan, row.client); + shader.setEnvTarget(glslang::EShTargetSpv, row.spv); + const EShMessages messages = static_cast(EShMsgSpvRules | EShMsgVulkanRules); + ASSERT_TRUE(shader.parse(GetDefaultResources(), 100, false, messages)) + << row.source << " does not compile:\n" << shader.getInfoLog(); + + glslang::TProgram program; + program.addShader(&shader); + ASSERT_TRUE(program.link(messages)) << row.source << " does not link:\n" << program.getInfoLog(); + glslang::TIntermediate* intermediate = program.getIntermediate(row.stage); + ASSERT_NE(intermediate, nullptr); + + std::vector spirv; + spv::SpvBuildLogger logger; + glslang::SpvOptions options; + options.disableOptimizer = true; + glslang::GlslangToSpv(*intermediate, spirv, &logger, &options); + ASSERT_FALSE(spirv.empty()) << "GlslangToSpv produced nothing for " << row.source; + + // Bake mode writes what it computed and asserts nothing else: the script that sets this + // variable is about to overwrite the header, so a red here would only stop it doing so. + if (const char* bakeDir = std::getenv("MOBILEGL_BAKE_INTERNAL_SHADERS")) { + const std::string out = std::string(bakeDir) + "/" + row.symbol + ".words"; + std::ofstream sink(out, std::ios::binary); + ASSERT_TRUE(sink.good()) << "cannot write " << out; + sink << row.header << "\n"; + for (unsigned int word : spirv) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x\n", word); + sink << text; + } + ASSERT_TRUE(sink.good()) << "failed writing " << out; + return; + } + + ASSERT_EQ(spirv.size(), row.wordCount) + << row.header << ": " << row.symbol << " has " << row.wordCount << " words, recompiling " + << row.source << " with the in-tree glslang produces " << spirv.size() + << ". Regenerate with scripts/bake_internal_shaders.py."; + for (std::size_t at = 0; at < spirv.size(); ++at) { + ASSERT_EQ(spirv[at], row.words[at]) + << row.header << ": " << row.symbol << " word " << at << " is stale against " + << row.source << ". Regenerate with scripts/bake_internal_shaders.py."; + } +} + +INSTANTIATE_TEST_SUITE_P(BakedShaders, BakedInternalShaders, + ::testing::ValuesIn(kBakedShaders), + [](const ::testing::TestParamInfo& info) { + return std::string(info.param.name); + }); + +} // namespace diff --git a/MobileGL/MG_Test/SelfTest/CMakeLists.txt b/MobileGL/MG_Test/SelfTest/CMakeLists.txt index 768e9179..af0cbedd 100644 --- a/MobileGL/MG_Test/SelfTest/CMakeLists.txt +++ b/MobileGL/MG_Test/SelfTest/CMakeLists.txt @@ -46,7 +46,38 @@ target_link_libraries(PrimitivesGeneratedNoXfbProbeTest PRIVATE ${LINK_LIBRARIES} ) +# MOBILEGL_BAKED_INTERNAL_SHADERS (CONTRACT-P7 §5.1 (D)): recompiles every baked SPIR-V header +# in the tree from its committed GLSL with the IN-TREE glslang and byte-compares. It is also the +# BAKER - scripts/bake_internal_shaders.py runs this binary rather than a glslangValidator of its +# own, so the gate and the generator cannot be two compilers with two answers. +# +# glslang-default-resource-limits is the standalone limits table glslangValidator itself parses +# with; MobileGL_s links glslang but builds its own limits from the live GL context, which a test +# with no context cannot do. MOBILEGL_BAKED_SHADER_ROOT is the SOURCE tree: the .vert/.frag/.comp +# inputs are not installed next to the binary and the gate fails rather than skips without them. +add_executable( + BakedInternalShadersTest + BakedInternalShadersTest.cpp +) + +target_include_directories(BakedInternalShadersTest PRIVATE + ${MGL_ROOT}/include + ${MGL_ROOT}/MobileGL +) + +target_compile_definitions(BakedInternalShadersTest PRIVATE + MOBILEGL_BAKED_SHADER_ROOT="${MGL_ROOT}" +) + +target_link_libraries(BakedInternalShadersTest PRIVATE + GTest::gtest_main + glslang + glslang-default-resource-limits + ${LINK_LIBRARIES} +) + include(GoogleTest) gtest_discover_tests(DriverPostIterationRPWitnessTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit) +gtest_discover_tests(BakedInternalShadersTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit) gtest_discover_tests(DriverBugProbesTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit) gtest_discover_tests(PrimitivesGeneratedNoXfbProbeTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit) diff --git a/MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitnessSpv.h b/MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitnessSpv.h index 556fdcf8..a2b91804 100644 --- a/MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitnessSpv.h +++ b/MobileGL/MG_Util/SelfTest/DriverPostIterationRPWitnessSpv.h @@ -6,15 +6,18 @@ // SPDX-License-Identifier: LGPL-3.0-only // End of Source File Header // -// Generated from DriverPostIterationRPWitness.comp with: -// glslangValidator --target-env vulkan1.1 -V DriverPostIterationRPWitness.comp -// Validated with spirv-val --target-env vulkan1.1. Do not edit words by hand. +// Generated from DriverPostIterationRPWitness.comp (Vulkan 1.1 / SPIR-V 1.3) by +// scripts/bake_internal_shaders.py, which runs MG_Test's BakedInternalShadersTest with the +// IN-TREE glslang and splices the words it emits into the array below. Do not edit the words +// by hand: MOBILEGL_BAKED_INTERNAL_SHADERS (the same test, run as a gate) recompiles this +// source and reds on the first word that disagrees. // -// The stored words predate the Program203 -> IterationRP source rename, so their -// embedded OpName debug strings still spell the old identifiers; regeneration from -// the renamed source produces semantically identical code differing only in those -// strings. The witness magic stays 0x50323033 ("P203" - the trace's program id) so -// these words remain valid without regeneration. +// P7 wave 2-B regenerated these words. They had predated the Program203 -> IterationRP source +// rename, so their OpName debug strings still spelled the old identifiers, and the header said +// so in prose - which is exactly as much enforcement as prose provides: nothing recompiled the +// source, so nothing could tell that difference from a real one. The witness magic is still +// 0x50323033 ("P203" - the trace's program id), because it is a constant in the .comp and not +// a property of the words. #pragma once @@ -38,259 +41,259 @@ namespace MobileGL::MG_Util::SelfTest { 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, + 0x4e5f6c67u, 0x75536d75u, 0x6f726762u, 0x00737075u, 0x00090005u, 0x00000035u, 0x72657449u, 0x6f697461u, + 0x5750526eu, 0x656e7469u, 0x754f7373u, 0x74757074u, 0x00000000u, 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 kDriverPostIterationRPWitnessSpvWordCount = sizeof(kDriverPostIterationRPWitnessSpv) / sizeof(kDriverPostIterationRPWitnessSpv[0]); diff --git a/MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h b/MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h index b3a2b522..a5cb1500 100644 --- a/MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h +++ b/MobileGL/MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbeSpv.h @@ -6,13 +6,15 @@ // SPDX-License-Identifier: LGPL-3.0-only // End of Source File Header -// Generated from PrimitivesGeneratedNoXfbProbe.{vert,tesc,tese} with: -// glslangValidator --target-env vulkan1.1 -V PrimitivesGeneratedNoXfbProbe. -// (SPIR-V words dumped little-endian, six per line.) +// Generated from PrimitivesGeneratedNoXfbProbe.{vert,tesc,tese} (Vulkan 1.1 / SPIR-V 1.3) by +// scripts/bake_internal_shaders.py, which runs MG_Test's BakedInternalShadersTest with the +// IN-TREE glslang and splices the words it emits into the arrays below. Do not edit the words +// by hand, and do not rely on remembering to regenerate: MOBILEGL_BAKED_INTERNAL_SHADERS (the +// same test, run as a gate) recompiles all three sources and reds on the first word that +// disagrees. Measured when that gate landed: these three arrays were already fresh. // -// Regenerate whenever a probe shader changes; nothing else in the probe depends on -// the exact binary. None of the modules carries an Xfb execution mode - that is the -// probe's subject, see PrimitivesGeneratedNoXfbProbe.cpp. +// None of the modules carries an Xfb execution mode - that is the probe's subject, see +// PrimitivesGeneratedNoXfbProbe.cpp. #pragma once #include diff --git a/docs/Disaggregated/notes/p7/magma-b.md b/docs/Disaggregated/notes/p7/magma-b.md index e9dd401a..2ac517c4 100644 --- a/docs/Disaggregated/notes/p7/magma-b.md +++ b/docs/Disaggregated/notes/p7/magma-b.md @@ -18,6 +18,7 @@ | 片 | 名 | 退役 / decline | 提交 | |---|---|---|---| | 1 | `mipmap-shader-format-or-shape` | 诊断 + 颜色 shader mip 回落(**退役**一半:可渲染格式的不可附着图像) | 见 §1 | +| 2 | `depth-stencil-mipmap@P7` + 烘焙 (A)(D) | DEPTH-only **退役**(烘焙深度 mip 程序);D\|S **decline** | 见 §2 | --- @@ -102,3 +103,103 @@ MGPipe: Fatal{UnmigratedVerb, "Magma:mipmap-shader-format-or-shape format=37 ext ### 1.5 门 `integration-magma-split` **75**(+2)、`-spawn` **54**(+2)、`-tcp` **56**(+2),三臂 0 红。 + +--- + +## 2. 片 2:深度 mip 烘焙 (A) + 新鲜度门 (D) + +### 2.1 为什么 monolith 的回落不能直接用 + +monolith 臂从拆分之前就带着一条深度 mip 的 shader 回落(`GenerateDepthMipmapWithShader`),因为 +`VK_FORMAT_FEATURE_BLIT_DST` 对深度格式**是可选的**,相当多的设备不给。wire 臂没有这条回落:深度纹理 +一旦不能原生 blit,第一个析取项 `resource->aspect != COLOR` 就把它送进 +`mipmap-shader-format-or-shape`(片 1 的诊断现在会把它指名为 `aspect=0x2 missing=COLOR_ATTACHMENT`)。 + +monolith 那条回落**不可复用**,这正是 CONTRACT-P7 §5.1 (A) 的全部内容:它要造一个 GL `ProgramObject`、 +两个 `ShaderObject` 和一个 GL sampler,经 uniform manager 的 global UBO 绑定,把 `uSrcTexelSize` 当默认块 +uniform 写——四个前端对象加一次 GL 编译器调用,落在 server 的 apply 线程上。 + +### 2.2 烘焙 (A) + +- `WireDepthMipmap.vert`:几何与 `WireColorBlit.vert` **逐字相同**(同一个 quad、同一个 push-constant + rect、同一个 GL-bottom-left → native-image 映射),只多一个成员 `ivec2 srcTexelSize`。push-constant 块 + 必须在同一管线的每个 stage 里声明一致,所以顶点阶段也声明它,而不是拆出第二个 range。 +- `WireDepthMipmap.frag`:`kDepthMipmapFragmentShaderSource` 的**移植**而非重写——同样的 2×2 + `texelFetch` 盒、同样的 clamp、同样的平均、同样的 `gl_FragDepth`。§3.2 的「退役」= 与 monolith 臂同 + 可观测,所以连它那半个 texel 的偏移(`ivec2(texCoord * srcTexelSize)` 落在目标中心偏半 texel)也照搬。 +- `WireDepthMipmap.inc`:深度附件 render pass(`loadOp = DONT_CARE`,pass 写满整级)+ 管线 + (`depthTest/Write = TRUE`、`compareOp = ALWAYS`、无颜色附件)+ 按格式/布局缓存的 target 表,形状与 + `WireColorBlit.inc` 逐条对齐(同样的懒建模块、同样的每提交描述符池、同 image 时两侧都 GENERAL)。 + sampler 用 NEAREST:frag 自己做 2×2 盒,任何采样器过滤都会被算两遍,而且多数设备不给深度格式 + linear。 +- `GenerateWireMipmap` 深度分支接入;`WireDepthMipmapSpirv.h` 由下面的门自己烘。 + +### 2.3 `depth-stencil-mipmap@P7` 拆成退役 + decline + +DEPTH-only 走上面的烘焙程序(**退役**)。D|S 合并与 stencil-only 改为 **decline**(`MGLOG_E_ONCE` + +return,§3.2),并且**在 `GrowWireTextureMipChain` 之前**就 return——否则会先长出一条这个动词不会填的 +链,随后又把它记成 defined。 + +decline 而非 Fatal 的理由:**monolith 也做不到**。它的 shader 回落自己断言 depth-only +("shader fallback only supports depth-only textures"),而断言在两条臂都发的 release 构建里等于零。GL +也没承诺 stencil mip;这条 pass 写 `gl_FragDepth`,会把它刚产出的那一级的 stencil aspect 留成未定义—— +比整级不动还糟。 + +### 2.4 新鲜度门 (D):`MOBILEGL_BAKED_INTERNAL_SHADERS` + +`MG_Test/SelfTest/BakedInternalShadersTest`,表驱动,8 行(`WireColorBlit.{vert,frag}`、 +`WireDepthMipmap.{vert,frag}`、`DriverPostIterationRPWitness.comp`、 +`PrimitivesGeneratedNoXfbProbe.{vert,tesc,tese}`),用**树内 glslang** 重编每一行并逐字比较。 + +**这个门就是烘焙器。** `scripts/bake_internal_shaders.py` 自己不编译任何东西:它用 +`MOBILEGL_BAKE_INTERNAL_SHADERS` 跑这个二进制,拿它吐出的字,splice 进头文件。方向是刻意的——门走 +glslang **库**、烘焙器 shell 出一个 glslangValidator **二进制**,就是两个编译器、没有哪个说了算;等它们 +的默认值哪天分叉,门会在一个没人能重新生成的头上变红。格式**按头保留**而不是统一:树里的头对每行几个字 +和 `u` 后缀意见不一,统一会把一个字的改动埋进整文件 diff。 + +**首轮实测(这是事先没人能知道的一件事):** + +| 头 | 结论 | +|---|---| +| `WireColorBlitSpirv.h` | **已新鲜**——手跑 glslangValidator 的字与树内 glslang 逐字相同 | +| `PrimitivesGeneratedNoXfbProbeSpv.h` | **已新鲜**(三个数组全部) | +| `DriverPostIterationRPWitnessSpv.h` | **过期**,按其自己的散文所说;本片重烘(2142 → 2143 字),witness magic `0x50323033` 仍在(它是 `.comp` 里的常量,不是字的属性) | + +三处 provenance 注释改为指向脚本与门。 + +### 2.5 场景 + +- `F1WireScenario.GenerateMipmapDepthWithoutNativeBlitPixels`(旋钮 tier 1,三臂): + `GL_DEPTH_COMPONENT24`(→ `X8_D24_UNORM_PACK32`)与 `GL_DEPTH_COMPONENT32F`(→ `D32_SFLOAT`)各一遍, + 16×16、上下两半 0.75 / 0.25,`glGenerateMipmap` 后按**采样附件**读回 level 1 的 8 行。**第 3 行不断言**: + 移植来的滤波器带半个 texel 偏移,两种读法下第 0..2 行只来自下半、第 4..7 行只来自上半,第 3 行是跨界 + 带——钉它等于钉那半个 texel 而不是钉 mip。 +- `F1WireScenario.GenerateMipmapDepthStencilDeclinesAndKeepsTheSession`(**无旋钮**,三臂): + `GL_DEPTH24_STENCIL8` 上 `glGenerateMipmap` 不报 GL 错、不带走会话(回读是一次穿到 server 的往返, + 一并回答会话还活着与 level 0 还在)。 + +### 2.6 red-once(R-16,三条,均已执行并还原) + +1. **新鲜度门**:把 `WireDepthMipmap.frag` 的 `0.25` 改成 `0.2500001`(**不需要重建**——门在运行时读源), + `WireDepthMipmapFragment` 行在**第 279 个字**变红并指名重新生成的办法;还原后 8/8 绿。 +2. **深度退役**:关掉深度分支 → `DirectVulkan.Split.DepthMip.*` 死于 + `Fatal{UnmigratedVerb, "Magma:mipmap-shader-format-or-shape format=125 extent=16x16x1 levels=5 + aspect=0x2 view=1 usage=0x27 layers=0+1/1 missing=COLOR_ATTACHMENT"}`(格式 125 = + `X8_D24_UNORM_PACK32`,诊断把它指名了)。 +3. **D|S decline**:把 `MagmaWireFatal` 放回去 → 该用例死于 + `Fatal{UnmigratedVerb, "Magma:depth-stencil-mipmap@P7"}`。 + +还原后两条 2/2 绿。 + +### 2.7 门 + +`integration-magma-split` **77**(+2)、`-spawn` **56**(+2)、`-tcp` **58**(+2),三臂 0 红; +`ctest -L unit` **2410**(+8 = 新鲜度门的八行)全绿;信息档 `integration-magma-full-split` **513**, +0 红 / 59 skip(基线 510,0 红 / 57 skip——两条新增用例在无旋钮的全量档自 skip)。 + +**G1 实测过了,而且这一条事先不是显然的**:`DriverPostIterationRPWitnessSpv.h` 是 +`MG_Util/SelfTest` 的头,pull 构建也编它,重烘改了 2142 → 2143 个字。pull `.text` 仍是 **`0xa52203`**, +`nm --defined-only` 的名字表与 `~/w7/p7-before/pull-syms.txt` 逐行相同(30570 行)——字长的变化落在 +`.rodata`,没有改动任何一条指令的编码宽度。`fatal_census` 绿(79 abort 站点 / 43 家族词 / 0 无标记, +本片**退掉一处** `Fatal{}` 用法但不动 abort 站点数);`link_ratchet --assert-monotone` 186 不变, +`p7-magma` 桶 101。 diff --git a/scripts/bake_internal_shaders.py b/scripts/bake_internal_shaders.py new file mode 100644 index 00000000..77474037 --- /dev/null +++ b/scripts/bake_internal_shaders.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +# MobileGL - scripts/bake_internal_shaders.py +# 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 +"""Regenerate the tree's baked SPIR-V headers from their committed GLSL. + + python3 scripts/bake_internal_shaders.py --build-dir build-split + python3 scripts/bake_internal_shaders.py --build-dir build-split --check + +THIS SCRIPT DOES NOT COMPILE ANYTHING. It runs MG_Test's BakedInternalShadersTest with +MOBILEGL_BAKE_INTERNAL_SHADERS set, takes the words that binary emits, and splices them into +the headers. The compiler is therefore the IN-TREE glslang the gate itself uses - one compiler +and one answer. + +The alternative, which is what the four headers in the tree were made with before this script +existed, is a glslangValidator somebody happened to have on their PATH. That is how the +iterationRP witness ended up carrying words its own source no longer produces: nothing named +the compiler, nothing re-ran it, and the header's prose was the only record that it was stale. +A gate whose baker is a different program from the gate has the same failure one level up - the +day the CLI's defaults and the library's diverge, the gate reds on a header nobody can +regenerate, and the fix is to edit the words by hand. + +FORMATTING IS PRESERVED PER HEADER, not normalised: the headers in the tree disagree about +words per line and about the `u` suffix, and reformatting one of them would bury a one-word +change in a whole-file diff. The style is read back out of the array being replaced. + +--check exits non-zero and names the headers that would change, without writing. It is the +same verdict the ctest entry gives; this mode exists so the regeneration path can be checked +from a shell without reading gtest output. +""" + +import argparse +import os +import re +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +TEST_TARGET = "BakedInternalShadersTest" +BAKE_ENV = "MOBILEGL_BAKE_INTERNAL_SHADERS" + +# ` 0x07230203u, 0x00010000u, ...` - the body of one baked array. +WORD_RE = re.compile(r"0x([0-9a-fA-F]{1,8})u?") + + +def find_test_binary(build_dir: Path) -> Path: + """The test executable, wherever this generator put it.""" + candidates = sorted(build_dir.rglob(TEST_TARGET)) + candidates = [c for c in candidates if c.is_file() and os.access(c, os.X_OK)] + if not candidates: + raise SystemExit( + f"{TEST_TARGET} not found under {build_dir}. Build it first:\n" + f" cmake --build {build_dir} --target {TEST_TARGET}" + ) + return candidates[0] + + +def emit_words(binary: Path, out_dir: Path) -> dict: + """Run the gate in bake mode; return {symbol: (header, [words])}.""" + env = dict(os.environ) + env[BAKE_ENV] = str(out_dir) + result = subprocess.run([str(binary)], env=env, capture_output=True, text=True) + if result.returncode != 0: + sys.stderr.write(result.stdout) + sys.stderr.write(result.stderr) + raise SystemExit(f"{TEST_TARGET} failed in bake mode (rc={result.returncode})") + baked = {} + for path in sorted(out_dir.glob("*.words")): + lines = path.read_text().splitlines() + if not lines: + raise SystemExit(f"{path} is empty") + header = lines[0].strip() + words = [int(line, 16) for line in lines[1:] if line.strip()] + baked[path.stem] = (header, words) + if not baked: + raise SystemExit(f"{TEST_TARGET} emitted nothing into {out_dir}") + return baked + + +def locate_array(text: str, symbol: str): + """(body_start, body_end, style) for `symbol`'s array body.""" + opener = re.search(re.escape(symbol) + r"\s*\[\s*\]\s*=\s*\{", text) + if not opener: + raise SystemExit(f"cannot find the array `{symbol}` to replace") + body_start = opener.end() + closer = text.find("};", body_start) + if closer < 0: + raise SystemExit("the array `" + symbol + "` has no closing `};`") + body = text[body_start:closer] + rows = [row for row in body.split("\n") if WORD_RE.search(row)] + if not rows: + raise SystemExit(f"the array `{symbol}` holds no words to learn its style from") + style = { + "indent": re.match(r"[ \t]*", rows[0]).group(0), + # The LONGEST row, not the first: a one-row array and a ragged last row would both + # teach the wrong width. + "per_line": max(len(WORD_RE.findall(row)) for row in rows), + "suffix": "u" if re.search(r"0x[0-9a-fA-F]+u", body) else "", + # The whitespace the closing brace sits behind. It is part of the SPAN being + # replaced, so a body written without it silently outdents every array it + # touches - a diff on three headers that changed no word at all. + "close_indent": re.search(r"[ \t]*$", text[:closer]).group(0), + } + return body_start, closer, style + + +def format_body(words, style) -> str: + per_line = style["per_line"] + out = ["\n"] + for at in range(0, len(words), per_line): + chunk = words[at:at + per_line] + out.append(style["indent"] + + ", ".join(f"0x{word:08x}{style['suffix']}" for word in chunk) + ",\n") + out.append(style["close_indent"]) + return "".join(out) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--build-dir", default="build-split", + help="a configured build tree that has BakedInternalShadersTest") + parser.add_argument("--build", action="store_true", + help="build the test target first") + parser.add_argument("--check", action="store_true", + help="report headers that would change and exit non-zero; write nothing") + args = parser.parse_args() + + build_dir = Path(args.build_dir) + if not build_dir.is_absolute(): + build_dir = ROOT / build_dir + if args.build: + subprocess.run(["cmake", "--build", str(build_dir), "--target", TEST_TARGET], + check=True) + + binary = find_test_binary(build_dir) + scratch = Path(tempfile.mkdtemp(prefix="mgl-bake-")) + try: + baked = emit_words(binary, scratch) + finally: + shutil.rmtree(scratch, ignore_errors=True) + + # One read/write per HEADER, not per symbol: two arrays share + # WireColorBlitSpirv.h and three share PrimitivesGeneratedNoXfbProbeSpv.h, and + # rewriting the file once per array would splice into a stale copy. + by_header = {} + for symbol, (header, words) in baked.items(): + by_header.setdefault(header, []).append((symbol, words)) + + changed = [] + for header, entries in sorted(by_header.items()): + path = ROOT / header + if not path.exists(): + raise SystemExit(f"{header} does not exist") + original = path.read_text() + text = original + for symbol, words in sorted(entries): + start, end, style = locate_array(text, symbol) + text = text[:start] + format_body(words, style) + text[end:] + if text == original: + print(f"bake: {header} is already fresh ({len(entries)} array(s))") + continue + changed.append(header) + if args.check: + print(f"bake: {header} WOULD CHANGE ({', '.join(s for s, _ in sorted(entries))})") + else: + path.write_text(text) + print(f"bake: {header} rewritten ({', '.join(s for s, _ in sorted(entries))})") + + if args.check and changed: + print(f"bake: {len(changed)} header(s) are stale against their sources", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main())