a4e7d8ab90
panvk-bifrost campaigns (r1..r4 Vulkan compositor + r5.video1 Vulkan
video decode) shipped before this repo existed; the deliverable
patches live in marfrit-packages, but the reasoning chain, phase docs,
and source-state evidence lived only in local working trees on the
development host.
This retrofit imports:
- mesa-panvk-bifrost/ — r1..r4 era phase docs (iter1..iter18)
(libmali stub blobs at iter18/blob/ excluded
— 109MB of RE artifacts replaced with a README
pointer)
- mesa-panvk-bifrost-video/ — sibling campaign phase docs + probe
- evidence/ — frozen .tgz source snapshots at each milestone
(basis for the 0005 patch diff generation)
Future iterations should branch off here from day one, so each iter is
a commit rather than a snapshot. See [[feedback-session-local-process-pins]]
for the process drift this retrofit closes.
Total: 1.9 MB across 124 files.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
267 lines
10 KiB
C
267 lines
10 KiB
C
/*
|
|
* iter13 Janet-CRITICAL regression: XFB-capable pipeline used WITHOUT
|
|
* vkCmdBeginTransformFeedback must NOT fault the GPU.
|
|
*
|
|
* Same pipeline shape as probe_xfb.c, but the draw is not wrapped in
|
|
* Begin/End XFB and no XFB buffer is bound. The vertex shader still
|
|
* emits a store_global instruction (xfb_address[0] is read from sysval).
|
|
*
|
|
* With the memory-sink fix (xfb_address defaults to PAN_SHADER_OOB_ADDRESS
|
|
* = 0x8000_0000_0000_0000), the store is silently discarded by the MMU.
|
|
* Without that fix, the store goes to address 0 → page fault → GPU job
|
|
* failure.
|
|
*
|
|
* Pass criterion: vkQueueSubmit + vkWaitForFences returns VK_SUCCESS
|
|
* (no DEVICE_LOST). No buffer to read back — we only care that the GPU
|
|
* survives the draw.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#define VSPV_PATH "probe_xfb.vert.spv"
|
|
|
|
#define STEP(name) do { fprintf(stderr, "[step] " name "\n"); fflush(stderr); } while (0)
|
|
|
|
#define VK_CHECK(call) do { \
|
|
VkResult _r = (call); \
|
|
if (_r != VK_SUCCESS) { \
|
|
fprintf(stderr, "[fail] " #call " => %d at %s:%d\n", \
|
|
(int)_r, __FILE__, __LINE__); \
|
|
exit(2); \
|
|
} \
|
|
} while (0)
|
|
|
|
static uint32_t *read_spv(const char *path, size_t *out_bytes)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
if (!f) { fprintf(stderr, "[fail] open %s: %s\n", path, strerror(errno)); exit(3); }
|
|
fseek(f, 0, SEEK_END);
|
|
long n = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
uint32_t *buf = malloc((size_t)n);
|
|
fread(buf, 1, (size_t)n, f);
|
|
fclose(f);
|
|
*out_bytes = (size_t)n;
|
|
return buf;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
STEP("vkCreateInstance");
|
|
VkApplicationInfo app = {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pApplicationName = "panvk-bifrost iter13 XFB no-draw probe",
|
|
.apiVersion = VK_API_VERSION_1_0,
|
|
};
|
|
const char *inst_exts[] = { "VK_KHR_get_physical_device_properties2" };
|
|
VkInstanceCreateInfo ici = {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pApplicationInfo = &app,
|
|
.enabledExtensionCount = 1,
|
|
.ppEnabledExtensionNames = inst_exts,
|
|
};
|
|
VkInstance inst;
|
|
VK_CHECK(vkCreateInstance(&ici, NULL, &inst));
|
|
|
|
uint32_t n_phys = 0;
|
|
VK_CHECK(vkEnumeratePhysicalDevices(inst, &n_phys, NULL));
|
|
VkPhysicalDevice *phys = calloc(n_phys, sizeof(*phys));
|
|
VK_CHECK(vkEnumeratePhysicalDevices(inst, &n_phys, phys));
|
|
VkPhysicalDevice gpu = phys[0];
|
|
|
|
uint32_t n_qf = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &n_qf, NULL);
|
|
VkQueueFamilyProperties *qfp = calloc(n_qf, sizeof(*qfp));
|
|
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &n_qf, qfp);
|
|
uint32_t qfam = UINT32_MAX;
|
|
for (uint32_t i = 0; i < n_qf; i++) {
|
|
if (qfp[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { qfam = i; break; }
|
|
}
|
|
|
|
STEP("vkCreateDevice (+XFB feature enabled + dynamic_rendering)");
|
|
const char *dev_exts[] = {
|
|
"VK_KHR_multiview", "VK_KHR_maintenance2",
|
|
"VK_KHR_create_renderpass2", "VK_KHR_depth_stencil_resolve",
|
|
"VK_KHR_dynamic_rendering",
|
|
"VK_EXT_transform_feedback",
|
|
};
|
|
VkPhysicalDeviceTransformFeedbackFeaturesEXT enable_xfb = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
|
|
.transformFeedback = VK_TRUE,
|
|
.geometryStreams = VK_FALSE,
|
|
};
|
|
VkPhysicalDeviceDynamicRenderingFeaturesKHR dyn_feat = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR,
|
|
.pNext = &enable_xfb,
|
|
.dynamicRendering = VK_TRUE,
|
|
};
|
|
float qprio = 1.0f;
|
|
VkDeviceQueueCreateInfo qci = {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
.queueFamilyIndex = qfam, .queueCount = 1, .pQueuePriorities = &qprio,
|
|
};
|
|
VkDeviceCreateInfo dci = {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
.pNext = &dyn_feat,
|
|
.queueCreateInfoCount = 1, .pQueueCreateInfos = &qci,
|
|
.enabledExtensionCount = sizeof(dev_exts)/sizeof(dev_exts[0]),
|
|
.ppEnabledExtensionNames = dev_exts,
|
|
};
|
|
VkDevice dev;
|
|
VK_CHECK(vkCreateDevice(gpu, &dci, NULL, &dev));
|
|
|
|
VkQueue queue;
|
|
vkGetDeviceQueue(dev, qfam, 0, &queue);
|
|
|
|
PFN_vkCmdBeginRenderingKHR pBeginRendering =
|
|
(PFN_vkCmdBeginRenderingKHR)vkGetDeviceProcAddr(dev, "vkCmdBeginRenderingKHR");
|
|
PFN_vkCmdEndRenderingKHR pEndRendering =
|
|
(PFN_vkCmdEndRenderingKHR)vkGetDeviceProcAddr(dev, "vkCmdEndRenderingKHR");
|
|
|
|
/* Same XFB-bearing vertex shader as probe_xfb — its SPIR-V has the
|
|
* xfb_buffer / xfb_offset decorations on `captured`. PanVk's driver
|
|
* will run pan_nir_lower_xfb on it, producing nir_store_global to
|
|
* vs.xfb_address[0]. We rely on the driver setting that sysval to
|
|
* PAN_SHADER_OOB_ADDRESS when xfb is inactive. */
|
|
STEP("vkCreateGraphicsPipelines (XFB-capable VS, no XFB buffer bound)");
|
|
VkPipelineLayoutCreateInfo plci = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
};
|
|
VkPipelineLayout pl;
|
|
VK_CHECK(vkCreatePipelineLayout(dev, &plci, NULL, &pl));
|
|
|
|
size_t spv_bytes = 0;
|
|
uint32_t *spv = read_spv(VSPV_PATH, &spv_bytes);
|
|
VkShaderModuleCreateInfo smci = {
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
.codeSize = spv_bytes, .pCode = spv,
|
|
};
|
|
VkShaderModule vsm;
|
|
VK_CHECK(vkCreateShaderModule(dev, &smci, NULL, &vsm));
|
|
free(spv);
|
|
|
|
VkPipelineShaderStageCreateInfo stages[1] = {
|
|
{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT, .module = vsm, .pName = "main" },
|
|
};
|
|
VkPipelineVertexInputStateCreateInfo vi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
};
|
|
VkPipelineInputAssemblyStateCreateInfo ia = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
};
|
|
VkViewport vp_dummy = { 0, 0, 1, 1, 0.0f, 1.0f };
|
|
VkRect2D sc_dummy = {{0,0}, {1,1}};
|
|
VkPipelineViewportStateCreateInfo vp = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
.viewportCount = 1, .pViewports = &vp_dummy,
|
|
.scissorCount = 1, .pScissors = &sc_dummy,
|
|
};
|
|
VkPipelineRasterizationStateCreateInfo rs = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
.rasterizerDiscardEnable = VK_TRUE,
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
.lineWidth = 1.0f,
|
|
};
|
|
VkPipelineMultisampleStateCreateInfo ms = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
};
|
|
VkPipelineRenderingCreateInfoKHR pri = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
|
|
.colorAttachmentCount = 0,
|
|
};
|
|
VkGraphicsPipelineCreateInfo gpci = {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.pNext = &pri,
|
|
.stageCount = 1, .pStages = stages,
|
|
.pVertexInputState = &vi,
|
|
.pInputAssemblyState = &ia,
|
|
.pViewportState = &vp,
|
|
.pRasterizationState = &rs,
|
|
.pMultisampleState = &ms,
|
|
.layout = pl,
|
|
};
|
|
VkPipeline pipe;
|
|
VK_CHECK(vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &gpci, NULL, &pipe));
|
|
|
|
VkCommandPoolCreateInfo cpoolci = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.queueFamilyIndex = qfam,
|
|
};
|
|
VkCommandPool cpool;
|
|
VK_CHECK(vkCreateCommandPool(dev, &cpoolci, NULL, &cpool));
|
|
VkCommandBufferAllocateInfo cbai = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
.commandPool = cpool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
.commandBufferCount = 1,
|
|
};
|
|
VkCommandBuffer cb;
|
|
VK_CHECK(vkAllocateCommandBuffers(dev, &cbai, &cb));
|
|
|
|
STEP("record (draw WITHOUT XFB Begin/End; no buffer bound)");
|
|
VkCommandBufferBeginInfo cbbi = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
};
|
|
VK_CHECK(vkBeginCommandBuffer(cb, &cbbi));
|
|
|
|
VkRenderingInfoKHR ri = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
|
|
.renderArea = {{0,0}, {1,1}},
|
|
.layerCount = 1,
|
|
.colorAttachmentCount = 0,
|
|
};
|
|
pBeginRendering(cb, &ri);
|
|
|
|
vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
|
|
/* No vkCmdBindTransformFeedbackBuffersEXT.
|
|
* No vkCmdBeginTransformFeedbackEXT.
|
|
* Just draw — the XFB store in the shader must be silently discarded. */
|
|
vkCmdDraw(cb, 3, 1, 0, 0);
|
|
|
|
pEndRendering(cb);
|
|
|
|
VK_CHECK(vkEndCommandBuffer(cb));
|
|
|
|
VkFenceCreateInfo fci = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
|
VkFence fence;
|
|
VK_CHECK(vkCreateFence(dev, &fci, NULL, &fence));
|
|
VkSubmitInfo si = {
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
.commandBufferCount = 1, .pCommandBuffers = &cb,
|
|
};
|
|
STEP("submit + wait (10s) — expect VK_SUCCESS, not DEVICE_LOST");
|
|
VK_CHECK(vkQueueSubmit(queue, 1, &si, fence));
|
|
VkResult wr = vkWaitForFences(dev, 1, &fence, VK_TRUE, 10ULL * 1000 * 1000 * 1000);
|
|
if (wr == VK_ERROR_DEVICE_LOST) {
|
|
fprintf(stderr, "[FAIL] DEVICE_LOST — the XFB store-global probably faulted "
|
|
"(memory-sink sentinel not applied).\n");
|
|
return 1;
|
|
}
|
|
if (wr != VK_SUCCESS) {
|
|
fprintf(stderr, "[FAIL] vkWaitForFences => %d\n", wr);
|
|
return 2;
|
|
}
|
|
|
|
vkDestroyFence(dev, fence, NULL);
|
|
vkDestroyCommandPool(dev, cpool, NULL);
|
|
vkDestroyPipeline(dev, pipe, NULL);
|
|
vkDestroyShaderModule(dev, vsm, NULL);
|
|
vkDestroyPipelineLayout(dev, pl, NULL);
|
|
vkDestroyDevice(dev, NULL);
|
|
vkDestroyInstance(inst, NULL);
|
|
free(phys); free(qfp);
|
|
|
|
fprintf(stderr, "[PASS] XFB-capable pipeline survives non-XFB draw — memory-sink active.\n");
|
|
return 0;
|
|
}
|