Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 200 additions & 13 deletions src/vulkan/wrapper/wrapper_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,143 @@
#include "vk_util.h"
#include "util/list.h"
#include "util/simple_mtx.h"
#include "util/u_atomic.h"

/* Bounded startup breadcrumbs: unlike API-dump these need no external layer.
* Keep this diagnostic local to the reported application and flush before
* entering the base driver, so a native fault cannot hide the last boundary. */
static void
wrapper_startup_diag(struct wrapper_device *device, const char *fmt, ...)
{
const char *app = device->physical->instance->vk.app_info.app_name;
static int lines;
if (!app || strcmp(app, "Dishonored.exe") ||
p_atomic_inc_return(&lines) > 256)
return;

char message[768];
va_list args;
va_start(args, fmt);
vsnprintf(message, sizeof(message), fmt, args);
va_end(args);
fprintf(stderr, "[WRAPPER_STARTUP] device=%p %s\n",
(void *)device, message);
fflush(stderr);
}

#define STARTUP_RESULT(call) ({ \
wrapper_startup_diag(device, "enter %s", #call); \
VkResult startup_result = (call); \
wrapper_startup_diag(device, "leave %s result=%d", #call, startup_result); \
startup_result; \
})

#define STARTUP_VOID(call) do { \
wrapper_startup_diag(device, "enter %s", #call); \
call; \
wrapper_startup_diag(device, "leave %s", #call); \
} while (0)

/* Second diagnostic: compare the actual application and driver inputs.
* The first breadcrumb's inline/divisor bits only meant storage was allocated,
* not that an inline module or a divisor was present. Never alter the chains. */
static void
wrapper_pipeline_diag_chain(struct wrapper_device *device, const char *where,
const void *pNext)
{
const VkBaseInStructure *node = pNext;
for (unsigned i = 0; node && i < 16; i++, node = node->pNext) {
wrapper_startup_diag(device, "%s chain[%u] sType=%d", where, i, node->sType);
switch (node->sType) {
case VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO: {
const VkPipelineRenderingCreateInfo *r = (const void *)node;
wrapper_startup_diag(device, "%s rendering viewMask=%x colors=%u depth=%d stencil=%d",
where, r->viewMask, r->colorAttachmentCount,
r->depthAttachmentFormat, r->stencilAttachmentFormat);
for (unsigned c = 0; r->pColorAttachmentFormats &&
c < MIN2(r->colorAttachmentCount, 8); c++)
wrapper_startup_diag(device, "%s color[%u]=%d", where, c,
r->pColorAttachmentFormats[c]);
break;
}
case VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO: {
const VkPipelineCreateFlags2CreateInfo *f = (const void *)node;
wrapper_startup_diag(device, "%s flags2=%llx", where,
(unsigned long long)f->flags);
break;
}
case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO: {
const VkShaderModuleCreateInfo *m = (const void *)node;
wrapper_startup_diag(device, "%s inline codeSize=%zu code=%p", where,
m->codeSize, (const void *)m->pCode);
break;
}
default:
break;
}
}
if (node)
wrapper_startup_diag(device, "%s chain truncated", where);
}

static void
wrapper_pipeline_diag(struct wrapper_device *device, const char *where,
const VkGraphicsPipelineCreateInfo *info)
{
wrapper_startup_diag(device,
"%s pipeline flags=%x stages=%u layout=%p renderPass=%p subpass=%u base=%p baseIndex=%d",
where, info->flags, info->stageCount, (void *)(uintptr_t)info->layout,
(void *)(uintptr_t)info->renderPass, info->subpass,
(void *)(uintptr_t)info->basePipelineHandle, info->basePipelineIndex);
wrapper_pipeline_diag_chain(device, where, info->pNext);
for (unsigned s = 0; info->pStages && s < MIN2(info->stageCount, 8); s++) {
const VkPipelineShaderStageCreateInfo *stage = &info->pStages[s];
size_t size = 0;
uint32_t *code = stage->module
? wrapper_stride_module_code(device, stage->module, &size) : NULL;
uint64_t hash = 0xcbf29ce484222325ull;
for (size_t b = 0; code && b < size; b++)
hash = (hash ^ ((const uint8_t *)code)[b]) * 0x100000001b3ull;
wrapper_startup_diag(device,
"%s stage[%u] kind=%x flags=%x module=%p entry=%.64s trackedBytes=%zu hash=%016llx spec=%d",
where, s, stage->stage, stage->flags, (void *)(uintptr_t)stage->module,
stage->pName ? stage->pName : "(null)", size,
(unsigned long long)(code ? hash : 0), stage->pSpecializationInfo != NULL);
free(code);
wrapper_pipeline_diag_chain(device, "stage", stage->pNext);
}
if (info->pVertexInputState) {
const VkPipelineVertexInputStateCreateInfo *vi = info->pVertexInputState;
wrapper_startup_diag(device, "%s vertex bindings=%u attributes=%u", where,
vi->vertexBindingDescriptionCount, vi->vertexAttributeDescriptionCount);
wrapper_pipeline_diag_chain(device, "vertex", vi->pNext);
const VkPipelineVertexInputDivisorStateCreateInfoKHR *ds =
vk_find_struct_const(vi->pNext, PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR);
for (unsigned d = 0; ds && ds->pVertexBindingDivisors &&
d < MIN2(ds->vertexBindingDivisorCount, 32); d++)
wrapper_startup_diag(device, "%s divisor binding=%u value=%u", where,
ds->pVertexBindingDivisors[d].binding,
ds->pVertexBindingDivisors[d].divisor);
}
if (info->pDynamicState) {
const VkPipelineDynamicStateCreateInfo *dyn = info->pDynamicState;
for (unsigned d = 0; dyn->pDynamicStates && d < MIN2(dyn->dynamicStateCount, 32); d++)
wrapper_startup_diag(device, "%s dynamic[%u]=%d", where, d, dyn->pDynamicStates[d]);
}
#define DIAG_STATE(member) do { \
wrapper_startup_diag(device, "%s " #member " present=%d", where, info->member != NULL); \
if (info->member) \
wrapper_pipeline_diag_chain(device, #member, info->member->pNext); \
} while (0)
DIAG_STATE(pInputAssemblyState);
DIAG_STATE(pTessellationState);
DIAG_STATE(pViewportState);
DIAG_STATE(pRasterizationState);
DIAG_STATE(pMultisampleState);
DIAG_STATE(pDepthStencilState);
DIAG_STATE(pColorBlendState);
#undef DIAG_STATE
}

const struct vk_device_extension_table wrapper_device_extensions =
{
Expand Down Expand Up @@ -610,10 +747,10 @@ wrapper_create_null_resources(struct wrapper_device *device)
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
if (dt->CreateBuffer(dev, &bci, NULL, &device->null_buffer) != VK_SUCCESS)
if (STARTUP_RESULT(dt->CreateBuffer(dev, &bci, NULL, &device->null_buffer)) != VK_SUCCESS)
return;
VkMemoryRequirements mr;
dt->GetBufferMemoryRequirements(dev, device->null_buffer, &mr);
STARTUP_VOID(dt->GetBufferMemoryRequirements(dev, device->null_buffer, &mr));
uint32_t mt = UINT32_MAX;
for (uint32_t i = 0; i < mp->memoryTypeCount; i++)
if ((mr.memoryTypeBits & (1u << i)) &&
Expand All @@ -623,13 +760,13 @@ wrapper_create_null_resources(struct wrapper_device *device)
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = mr.size, .memoryTypeIndex = mt,
};
if (dt->AllocateMemory(dev, &mai, NULL, &device->null_buffer_memory) != VK_SUCCESS)
if (STARTUP_RESULT(dt->AllocateMemory(dev, &mai, NULL, &device->null_buffer_memory)) != VK_SUCCESS)
return;
dt->BindBufferMemory(dev, device->null_buffer, device->null_buffer_memory, 0);
STARTUP_RESULT(dt->BindBufferMemory(dev, device->null_buffer, device->null_buffer_memory, 0));
void *ptr = NULL;
if (dt->MapMemory(dev, device->null_buffer_memory, 0, VK_WHOLE_SIZE, 0, &ptr) == VK_SUCCESS) {
memset(ptr, 0, mr.size);
dt->UnmapMemory(dev, device->null_buffer_memory);
if (STARTUP_RESULT(dt->MapMemory(dev, device->null_buffer_memory, 0, VK_WHOLE_SIZE, 0, &ptr)) == VK_SUCCESS) {
STARTUP_VOID(memset(ptr, 0, mr.size));
STARTUP_VOID(dt->UnmapMemory(dev, device->null_buffer_memory));
}

VkImageCreateInfo ici = {
Expand All @@ -640,9 +777,9 @@ wrapper_create_null_resources(struct wrapper_device *device)
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
if (dt->CreateImage(dev, &ici, NULL, &device->null_image) == VK_SUCCESS) {
if (STARTUP_RESULT(dt->CreateImage(dev, &ici, NULL, &device->null_image)) == VK_SUCCESS) {
VkMemoryRequirements imr;
dt->GetImageMemoryRequirements(dev, device->null_image, &imr);
STARTUP_VOID(dt->GetImageMemoryRequirements(dev, device->null_image, &imr));
uint32_t imt = UINT32_MAX;
for (uint32_t i = 0; i < mp->memoryTypeCount; i++)
if (imr.memoryTypeBits & (1u << i)) { imt = i; break; }
Expand All @@ -651,19 +788,19 @@ wrapper_create_null_resources(struct wrapper_device *device)
.allocationSize = imr.size, .memoryTypeIndex = imt,
};
if (imt != UINT32_MAX &&
dt->AllocateMemory(dev, &imai, NULL, &device->null_image_memory) == VK_SUCCESS) {
dt->BindImageMemory(dev, device->null_image, device->null_image_memory, 0);
STARTUP_RESULT(dt->AllocateMemory(dev, &imai, NULL, &device->null_image_memory)) == VK_SUCCESS) {
STARTUP_RESULT(dt->BindImageMemory(dev, device->null_image, device->null_image_memory, 0));
VkImageViewCreateInfo vci = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = device->null_image, .viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 },
};
dt->CreateImageView(dev, &vci, NULL, &device->null_image_view);
STARTUP_RESULT(dt->CreateImageView(dev, &vci, NULL, &device->null_image_view));
}
}
VkSamplerCreateInfo sci = { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
dt->CreateSampler(dev, &sci, NULL, &device->null_sampler);
STARTUP_RESULT(dt->CreateSampler(dev, &sci, NULL, &device->null_sampler));
}

VKAPI_ATTR void VKAPI_CALL
Expand Down Expand Up @@ -1562,9 +1699,12 @@ if (pdf2 && pdf2->features.f) { \
!(emulate_query_reset && !device->query_reset_shared_queue))
wrapper_bcn_reserve_queue(device, &wrapper_create_info, &bcn_queues, &bcn_priorities);

wrapper_startup_diag(device, "enter base CreateDevice feature-chain=%d",
wrapper_create_info.pNext != NULL);
result = physical_device->dispatch_table.CreateDevice(
physical_device->dispatch_handle, &wrapper_create_info,
pAllocator, &device->dispatch_handle);
wrapper_startup_diag(device, "leave base CreateDevice result=%d", result);
wrapper_core13_free_device_create(core13_storage);

if (result != VK_SUCCESS) {
Expand All @@ -1577,9 +1717,11 @@ if (pdf2 && pdf2->features.f) { \
"feature chain\n", result);
wrapper_create_info.pNext = NULL;
used_fallback_create = true;
wrapper_startup_diag(device, "enter fallback CreateDevice");
result = physical_device->dispatch_table.CreateDevice(
physical_device->dispatch_handle, &wrapper_create_info,
pAllocator, &device->dispatch_handle);
wrapper_startup_diag(device, "leave fallback CreateDevice result=%d", result);
}

if (result != VK_SUCCESS) {
Expand Down Expand Up @@ -1624,7 +1766,9 @@ if (pdf2 && pdf2->features.f) { \
!physical_device->base_supported_features.nullDescriptor;
if (device->emulate_null_descriptor) {
WRAPPER_LOG(info, "Emulating nullDescriptor with canonical zero resources");
wrapper_startup_diag(device, "enter null resources");
wrapper_create_null_resources(device);
wrapper_startup_diag(device, "leave null resources");
}

device->emulate_imageless_framebuffer =
Expand Down Expand Up @@ -4086,6 +4230,25 @@ wrapper_CreateGraphicsPipelines(VkDevice _device, VkPipelineCache pipelineCache,
VkPipeline *pPipelines)
{
VK_FROM_HANDLE(wrapper_device, device, _device);
const char *app = device->physical->instance->vk.app_info.app_name;
static int diagnostic_calls;
const bool diagnostic = app && !strcmp(app, "Dishonored.exe") &&
p_atomic_inc_return(&diagnostic_calls) <= 2;
if (diagnostic) {
wrapper_startup_diag(device,
"pipeline capabilities driver=%d api=%x baseRendering=%d requestedRendering=%d baseM5=%d requestedM5=%d allocator=%d cache=%p",
device->physical->driver_properties.driverID,
device->physical->properties2.properties.apiVersion,
device->physical->base_supported_features.dynamicRendering,
device->vk.enabled_features.dynamicRendering,
device->physical->base_supported_extensions.KHR_maintenance5,
device->vk.enabled_extensions.KHR_maintenance5, pAllocator != NULL,
(void *)(uintptr_t)pipelineCache);
for (unsigned i = 0; i < MIN2(createInfoCount, 2); i++)
wrapper_pipeline_diag(device, "application", &pCreateInfos[i]);
}
wrapper_startup_diag(device, "enter graphics infos=%p count=%u",
(const void *)pCreateInfos, createInfoCount);
VkGraphicsPipelineCreateInfo *legacy = NULL;
VkRenderPass *render_passes = NULL;
void *chain_mem = NULL;
Expand All @@ -4095,6 +4258,13 @@ wrapper_CreateGraphicsPipelines(VkDevice _device, VkPipelineCache pipelineCache,
VkShaderModule *m5_modules = NULL;
uint32_t m5_module_count = 0;

for (uint32_t i = 0; i < createInfoCount; i++)
wrapper_startup_diag(device,
"graphics infos=%p index=%u stages=%u flags=0x%x pNext=%d renderPass=%p",
(const void *)pCreateInfos, i, pCreateInfos[i].stageCount,
pCreateInfos[i].flags, pCreateInfos[i].pNext != NULL,
(void *)(uintptr_t)pCreateInfos[i].renderPass);

for (uint32_t i = 0; i < createInfoCount; i++)
for (uint32_t j = 0; j < pCreateInfos[i].stageCount; j++)
wrapper_scan_inline_shader(&pCreateInfos[i].pStages[j]);
Expand Down Expand Up @@ -4262,23 +4432,40 @@ wrapper_CreateGraphicsPipelines(VkDevice _device, VkPipelineCache pipelineCache,
for (uint32_t i = 0; i < createInfoCount && !stride_emulated; i++)
stride_emulated = wrapper_stride_wants(device, &driver_infos[i]);

wrapper_startup_diag(device,
"graphics lowered infos=%p driver_infos=%p stride=%d inline=%d fold=%d legacy=%d divisor=%d",
(const void *)pCreateInfos, (const void *)driver_infos, stride_emulated,
m5_infos != NULL, fold, legacy != NULL, div_infos != NULL);
if (diagnostic) {
wrapper_startup_diag(device, "actually materialized inline modules=%u", m5_module_count);
for (unsigned i = 0; i < MIN2(createInfoCount, 2); i++)
wrapper_pipeline_diag(device, "driver", &driver_infos[i]);
}
if (stride_emulated) {
for (uint32_t i = 0; i < createInfoCount; i++) {
wrapper_startup_diag(device, "enter graphics dispatch infos=%p index=%u",
(const void *)driver_infos, i);
VkResult r = wrapper_stride_wants(device, &driver_infos[i])
? wrapper_stride_create(device, pipelineCache, &driver_infos[i], pAllocator,
&pPipelines[i])
: device->dispatch_table.CreateGraphicsPipelines(device->dispatch_handle,
pipelineCache, 1, &driver_infos[i], pAllocator, &pPipelines[i]);
wrapper_startup_diag(device, "leave graphics dispatch infos=%p index=%u result=%d",
(const void *)driver_infos, i, r);
if (r != VK_SUCCESS) {
pPipelines[i] = VK_NULL_HANDLE;
if (result == VK_SUCCESS)
result = r;
}
}
} else {
wrapper_startup_diag(device, "enter base graphics infos=%p count=%u",
(const void *)driver_infos, createInfoCount);
result = device->dispatch_table.CreateGraphicsPipelines(
device->dispatch_handle, pipelineCache, createInfoCount, driver_infos,
pAllocator, pPipelines);
wrapper_startup_diag(device, "leave base graphics infos=%p result=%d",
(const void *)driver_infos, result);
}

if (div_lowerings) {
Expand Down
Loading