Skip to content

Commit

Permalink
Add support for KHR disassembly extensions.
Browse files Browse the repository at this point in the history
Fall back to AMD extension as needed.
  • Loading branch information
HansKristian-Work committed Sep 12, 2019
1 parent 7379b66 commit 66340e9
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 16 deletions.
10 changes: 7 additions & 3 deletions cli/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ static bool find_extension(const vector<VkExtensionProperties> &exts, const char
return itr != end(exts);
}

static bool filter_extension(const char *ext, bool need_disasm)
static bool filter_extension(const char *ext, bool want_amd_shader_info)
{
// Ban certain extensions, because they conflict with others.
if (strcmp(ext, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0)
return false;
else if (strcmp(ext, VK_AMD_SHADER_INFO_EXTENSION_NAME) == 0 && !need_disasm)
else if (strcmp(ext, VK_AMD_SHADER_INFO_EXTENSION_NAME) == 0 && !want_amd_shader_info)
{
// Mesa disables the pipeline cache when VK_AMD_shader_info is used, so disable this extension unless we need it.
return false;
Expand Down Expand Up @@ -319,14 +319,18 @@ bool VulkanDevice::init_device(const Options &opts)

for (auto &ext : device_ext_props)
{
if (filter_extension(ext.extensionName, opts.need_disasm))
if (filter_extension(ext.extensionName, opts.want_amd_shader_info))
active_device_extensions.push_back(ext.extensionName);
}

supports_pipeline_feedback = find_if(begin(active_device_extensions), end(active_device_extensions), [](const char *ext) {
return strcmp(ext, VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME) == 0;
}) != end(active_device_extensions);

amd_shader_info = find_if(begin(active_device_extensions), end(active_device_extensions), [](const char *ext) {
return strcmp(ext, VK_AMD_SHADER_INFO_EXTENSION_NAME) == 0;
}) != end(active_device_extensions);

VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
device_info.pNext = has_device_features2 ? &gpu_features2 : nullptr;
device_info.pEnabledFeatures = has_device_features2 ? nullptr : gpu_features;
Expand Down
8 changes: 7 additions & 1 deletion cli/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class VulkanDevice
struct Options
{
bool enable_validation = false;
bool need_disasm = true;
bool want_amd_shader_info = false;
bool null_device = false;
bool want_pipeline_stats = false;
int device_index = -1;
Expand Down Expand Up @@ -79,6 +79,11 @@ class VulkanDevice
return validation_cache;
}

bool has_amd_shader_info() const
{
return amd_shader_info;
}

private:
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice gpu = VK_NULL_HANDLE;
Expand All @@ -94,5 +99,6 @@ class VulkanDevice
bool is_null_device = false;
bool pipeline_stats = false;
bool validation_cache = false;
bool amd_shader_info = false;
};
}
107 changes: 97 additions & 10 deletions cli/fossilize_disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ struct DisasmReplayer : StateCreatorInterface
{
if (device)
{
if (device->has_pipeline_stats())
const_cast<VkComputePipelineCreateInfo *>(create_info)->flags |= VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;

LOGI("Creating compute pipeline %0" PRIX64 "\n", hash);
if (vkCreateComputePipelines(device->get_device(), pipeline_cache, 1, create_info, nullptr, pipeline) !=
VK_SUCCESS)
Expand All @@ -216,6 +219,9 @@ struct DisasmReplayer : StateCreatorInterface
{
if (device)
{
if (device->has_pipeline_stats())
const_cast<VkGraphicsPipelineCreateInfo *>(create_info)->flags |= VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;

LOGI("Creating graphics pipeline %0" PRIX64 "\n", hash);
if (vkCreateGraphicsPipelines(device->get_device(), pipeline_cache, 1, create_info, nullptr, pipeline) !=
VK_SUCCESS)
Expand Down Expand Up @@ -263,7 +269,7 @@ enum class DisasmMethod
{
Asm,
GLSL,
AMD
ISA
};

static DisasmMethod method_from_string(const char *method)
Expand All @@ -272,8 +278,10 @@ static DisasmMethod method_from_string(const char *method)
return DisasmMethod::Asm;
else if (strcmp(method, "glsl") == 0)
return DisasmMethod::GLSL;
else if (strcmp(method, "amd") == 0)
return DisasmMethod::AMD;
else if (strcmp(method, "amd") == 0) // Compat
return DisasmMethod::ISA;
else if (strcmp(method, "isa") == 0) // Compat
return DisasmMethod::ISA;
else
{
LOGE("Invalid disasm method: %s\n", method);
Expand Down Expand Up @@ -390,10 +398,9 @@ static string disassemble_spirv_glsl(const VkShaderModuleCreateInfo *create_info

static string disassemble_spirv_amd(const VulkanDevice &device, VkPipeline pipeline, VkShaderStageFlagBits stage)
{
if (!vkGetShaderInfoAMD)
if (!device.has_amd_shader_info())
{
LOGE("Does not have vkGetShaderInfoAMD.\n");
// FIXME: Check extension properly, lazy for now :)
return "";
}

Expand All @@ -415,6 +422,77 @@ static string disassemble_spirv_amd(const VulkanDevice &device, VkPipeline pipel
return string(begin(ret), end(ret));
}

static string disassemble_spirv_isa(const VulkanDevice &device, VkPipeline pipeline, VkShaderStageFlagBits stage)
{
if (device.has_pipeline_stats())
{
uint32_t count = 0;
VkPipelineInfoKHR pipeline_info = { VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR };
pipeline_info.pipeline = pipeline;

if (vkGetPipelineExecutablePropertiesKHR(device.get_device(), &pipeline_info, &count, nullptr) != VK_SUCCESS)
return "";

vector<VkPipelineExecutablePropertiesKHR> executables(count);
for (auto &exec : executables)
exec.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR;

if (vkGetPipelineExecutablePropertiesKHR(device.get_device(), &pipeline_info, &count, executables.data()) != VK_SUCCESS)
return "";

uint32_t index = 0;
for (; index < count; index++)
{
if ((executables[index].stages & stage) != 0)
break;
}

if (index >= count)
return "// Could not find stage in compiled pipeline.";

VkPipelineExecutableInfoKHR executable = { VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR };
executable.pipeline = pipeline;
executable.executableIndex = index;

if (vkGetPipelineExecutableInternalRepresentationsKHR(device.get_device(), &executable, &count, nullptr) != VK_SUCCESS)
return "";

vector<VkPipelineExecutableInternalRepresentationKHR> representations(count);
for (auto &rep : representations)
rep.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR;

if (vkGetPipelineExecutableInternalRepresentationsKHR(device.get_device(), &executable, &count, representations.data()) != VK_SUCCESS)
return "";

for (auto &rep : representations)
rep.pData = malloc(rep.dataSize);

if (vkGetPipelineExecutableInternalRepresentationsKHR(device.get_device(), &executable, &count, representations.data()) != VK_SUCCESS)
return "";

string result;
for (auto &rep : representations)
{
if (rep.isText)
{
result += "Representation: ";
result += rep.name;
result += " (";
result += rep.description;
result += ")\n\n";
result += static_cast<const char *>(rep.pData);
result += "\n\n";
}
free(rep.pData);
}
return result;
}
else if (device.has_amd_shader_info())
return disassemble_spirv_amd(device, pipeline, stage);
else
return "";
}

static string disassemble_spirv(const VulkanDevice &device, VkPipeline pipeline,
DisasmMethod method, VkShaderStageFlagBits stage,
const VkShaderModuleCreateInfo *module_create_info, const char *entry_point)
Expand All @@ -427,8 +505,8 @@ static string disassemble_spirv(const VulkanDevice &device, VkPipeline pipeline,
case DisasmMethod::GLSL:
return disassemble_spirv_glsl(module_create_info, entry_point, stage);

case DisasmMethod::AMD:
return disassemble_spirv_amd(device, pipeline, stage);
case DisasmMethod::ISA:
return disassemble_spirv_isa(device, pipeline, stage);

default:
return "";
Expand All @@ -442,7 +520,7 @@ static void print_help()
"\t[--device-index <index>]\n"
"\t[--enable-validation]\n"
"\t[--output <path>]\n"
"\t[--target asm/glsl/amd]\n"
"\t[--target asm/glsl/isa]\n"
"state.json\n");
}

Expand Down Expand Up @@ -508,11 +586,14 @@ int main(int argc, char *argv[])
}

VulkanDevice device;
if (method == DisasmMethod::AMD)
if (method == DisasmMethod::ISA)
{
opts.want_amd_shader_info = true;
opts.want_pipeline_stats = true;

if (module_only)
{
LOGE("Cannot do module-only disassembly with AMD target.\n");
LOGE("Cannot do module-only disassembly with ISA target.\n");
return EXIT_FAILURE;
}

Expand All @@ -521,6 +602,12 @@ int main(int argc, char *argv[])
LOGE("Failed to create device.\n");
return EXIT_FAILURE;
}

if (!device.has_amd_shader_info() && !device.has_pipeline_stats())
{
LOGE("Neither AMD_shader_info or executable properties extension are available.\n");
return EXIT_FAILURE;
}
}

DisasmReplayer replayer(device.get_device() ? &device : nullptr);
Expand Down
1 change: 0 additions & 1 deletion cli/fossilize_replay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,6 @@ struct ThreadedReplayer : StateCreatorInterface
device.reset(new VulkanDevice);
device_opts.application_info = app;
device_opts.features = features;
device_opts.need_disasm = false;
device_opts.want_pipeline_stats = opts.pipeline_stats;
auto start_device = chrono::steady_clock::now();
if (!device->init_device(device_opts))
Expand Down
1 change: 0 additions & 1 deletion test/multi_instance_and_device_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ void test_thread(const VkApplicationInfo *info, const VkPhysicalDeviceFeatures2
VulkanDevice::Options opts;
opts.application_info = info;
opts.features = features;
opts.need_disasm = false;
opts.enable_validation = false;
VulkanDevice device;
if (!device.init_device(opts))
Expand Down

0 comments on commit 66340e9

Please sign in to comment.