From 769c58a9b2c45bbef6f33f03a9c5275a6a3eb183 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 20 Feb 2016 16:24:42 -0800 Subject: [PATCH] Adding `xb genspirv` to do glsl->.h. --- src/xenia/ui/vulkan/premake5.lua | 3 + .../immediate_frag.h} | 4 +- .../immediate_frag.spv} | Bin .../ui/vulkan/shaders/bin/immediate_frag.txt | 94 +++++++++++++++++ .../immediate_vert.h} | 4 +- .../immediate_vert.spv} | Bin .../ui/vulkan/shaders/bin/immediate_vert.txt | 96 +++++++++++++++++ src/xenia/ui/vulkan/shaders/build.bat | 2 - src/xenia/ui/vulkan/shaders/immediate.frag | 3 + src/xenia/ui/vulkan/shaders/immediate.vert | 3 + .../ui/vulkan/vulkan_immediate_drawer.cc | 14 +-- xenia-build | 98 ++++++++++++++++++ 12 files changed, 310 insertions(+), 11 deletions(-) rename src/xenia/ui/vulkan/shaders/{immediate.frag.h => bin/immediate_frag.h} (99%) rename src/xenia/ui/vulkan/shaders/{immediate.frag.spv => bin/immediate_frag.spv} (100%) create mode 100644 src/xenia/ui/vulkan/shaders/bin/immediate_frag.txt rename src/xenia/ui/vulkan/shaders/{immediate.vert.h => bin/immediate_vert.h} (99%) rename src/xenia/ui/vulkan/shaders/{immediate.vert.spv => bin/immediate_vert.spv} (100%) create mode 100644 src/xenia/ui/vulkan/shaders/bin/immediate_vert.txt delete mode 100644 src/xenia/ui/vulkan/shaders/build.bat diff --git a/src/xenia/ui/vulkan/premake5.lua b/src/xenia/ui/vulkan/premake5.lua index 2144ca30a..71824e5ec 100644 --- a/src/xenia/ui/vulkan/premake5.lua +++ b/src/xenia/ui/vulkan/premake5.lua @@ -18,6 +18,9 @@ project("xenia-ui-vulkan") project_root.."/third_party/vulkan/", }) local_platform_files() + files({ + "shaders/bin/*.h", + }) removefiles({"*_demo.cc"}) group("demos") diff --git a/src/xenia/ui/vulkan/shaders/immediate.frag.h b/src/xenia/ui/vulkan/shaders/bin/immediate_frag.h similarity index 99% rename from src/xenia/ui/vulkan/shaders/immediate.frag.h rename to src/xenia/ui/vulkan/shaders/bin/immediate_frag.h index e1efd613a..4cdf8593b 100644 --- a/src/xenia/ui/vulkan/shaders/immediate.frag.h +++ b/src/xenia/ui/vulkan/shaders/bin/immediate_frag.h @@ -1,4 +1,6 @@ -const uint8_t immediate_frag_spv[] = { +// generated from `xb genspirv` +// source: immediate.frag +const uint8_t immediate_frag[] = { 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, diff --git a/src/xenia/ui/vulkan/shaders/immediate.frag.spv b/src/xenia/ui/vulkan/shaders/bin/immediate_frag.spv similarity index 100% rename from src/xenia/ui/vulkan/shaders/immediate.frag.spv rename to src/xenia/ui/vulkan/shaders/bin/immediate_frag.spv diff --git a/src/xenia/ui/vulkan/shaders/bin/immediate_frag.txt b/src/xenia/ui/vulkan/shaders/bin/immediate_frag.txt new file mode 100644 index 000000000..c4b6ea61f --- /dev/null +++ b/src/xenia/ui/vulkan/shaders/bin/immediate_frag.txt @@ -0,0 +1,94 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 53 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 %11 %30 + OpExecutionMode %4 OriginLowerLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %9 "out_color" + OpName %11 "vtx_color" + OpName %16 "PushConstants" + OpMemberName %16 0 "projection_matrix" + OpMemberName %16 1 "restrict_texture_samples" + OpName %18 "push_constants" + OpName %30 "vtx_uv" + OpName %42 "tex_color" + OpName %46 "texture_sampler" + OpDecorate %9 Location 0 + OpDecorate %11 Location 1 + OpMemberDecorate %16 0 ColMajor + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 0 MatrixStride 16 + OpMemberDecorate %16 1 Offset 64 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %30 Location 0 + OpDecorate %46 DescriptorSet 0 + OpDecorate %46 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpTypePointer Input %7 + %11 = OpVariable %10 Input + %13 = OpTypeBool + %14 = OpTypeMatrix %7 4 + %15 = OpTypeInt 32 1 + %16 = OpTypeStruct %14 %15 + %17 = OpTypePointer PushConstant %16 + %18 = OpVariable %17 PushConstant + %19 = OpConstant %15 1 + %20 = OpTypePointer PushConstant %15 + %23 = OpConstant %15 0 + %28 = OpTypeVector %6 2 + %29 = OpTypePointer Input %28 + %30 = OpVariable %29 Input + %31 = OpTypeInt 32 0 + %32 = OpConstant %31 0 + %33 = OpTypePointer Input %6 + %36 = OpConstant %6 1 + %41 = OpTypePointer Function %7 + %43 = OpTypeImage %6 2D 0 0 0 1 Unknown + %44 = OpTypeSampledImage %43 + %45 = OpTypePointer UniformConstant %44 + %46 = OpVariable %45 UniformConstant + %4 = OpFunction %2 None %3 + %5 = OpLabel + %42 = OpVariable %41 Function + %12 = OpLoad %7 %11 + OpStore %9 %12 + %21 = OpAccessChain %20 %18 %19 + %22 = OpLoad %15 %21 + %24 = OpIEqual %13 %22 %23 + %25 = OpLogicalNot %13 %24 + OpSelectionMerge %27 None + OpBranchConditional %25 %26 %27 + %26 = OpLabel + %34 = OpAccessChain %33 %30 %32 + %35 = OpLoad %6 %34 + %37 = OpFOrdLessThanEqual %13 %35 %36 + OpBranch %27 + %27 = OpLabel + %38 = OpPhi %13 %24 %5 %37 %26 + OpSelectionMerge %40 None + OpBranchConditional %38 %39 %40 + %39 = OpLabel + %47 = OpLoad %44 %46 + %48 = OpLoad %28 %30 + %49 = OpImageSampleImplicitLod %7 %47 %48 + OpStore %42 %49 + %50 = OpLoad %7 %42 + %51 = OpLoad %7 %9 + %52 = OpFMul %7 %51 %50 + OpStore %9 %52 + OpBranch %40 + %40 = OpLabel + OpReturn + OpFunctionEnd diff --git a/src/xenia/ui/vulkan/shaders/immediate.vert.h b/src/xenia/ui/vulkan/shaders/bin/immediate_vert.h similarity index 99% rename from src/xenia/ui/vulkan/shaders/immediate.vert.h rename to src/xenia/ui/vulkan/shaders/bin/immediate_vert.h index b454eb260..3d2c0687e 100644 --- a/src/xenia/ui/vulkan/shaders/immediate.vert.h +++ b/src/xenia/ui/vulkan/shaders/bin/immediate_vert.h @@ -1,4 +1,6 @@ -const uint8_t immediate_vert_spv[] = { +// generated from `xb genspirv` +// source: immediate.vert +const uint8_t immediate_vert[] = { 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, diff --git a/src/xenia/ui/vulkan/shaders/immediate.vert.spv b/src/xenia/ui/vulkan/shaders/bin/immediate_vert.spv similarity index 100% rename from src/xenia/ui/vulkan/shaders/immediate.vert.spv rename to src/xenia/ui/vulkan/shaders/bin/immediate_vert.spv diff --git a/src/xenia/ui/vulkan/shaders/bin/immediate_vert.txt b/src/xenia/ui/vulkan/shaders/bin/immediate_vert.txt new file mode 100644 index 000000000..a8e36189e --- /dev/null +++ b/src/xenia/ui/vulkan/shaders/bin/immediate_vert.txt @@ -0,0 +1,96 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 48 +; Schema: 0 + OpCapability Shader + OpCapability ClipDistance + OpCapability CullDistance + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %4 "main" %13 %25 %41 %42 %44 %46 + OpSource GLSL 450 + OpName %4 "main" + OpName %11 "gl_PerVertex" + OpMemberName %11 0 "gl_Position" + OpMemberName %11 1 "gl_PointSize" + OpMemberName %11 2 "gl_ClipDistance" + OpMemberName %11 3 "gl_CullDistance" + OpName %13 "" + OpName %17 "PushConstants" + OpMemberName %17 0 "projection_matrix" + OpMemberName %17 1 "restrict_texture_samples" + OpName %19 "push_constants" + OpName %25 "in_pos" + OpName %41 "vtx_uv" + OpName %42 "in_uv" + OpName %44 "vtx_color" + OpName %46 "in_color" + OpMemberDecorate %11 0 BuiltIn Position + OpMemberDecorate %11 1 BuiltIn PointSize + OpMemberDecorate %11 2 BuiltIn ClipDistance + OpMemberDecorate %11 3 BuiltIn CullDistance + OpDecorate %11 Block + OpMemberDecorate %17 0 ColMajor + OpMemberDecorate %17 0 Offset 0 + OpMemberDecorate %17 0 MatrixStride 16 + OpMemberDecorate %17 1 Offset 64 + OpDecorate %17 Block + OpDecorate %19 DescriptorSet 0 + OpDecorate %25 Location 0 + OpDecorate %41 Location 0 + OpDecorate %42 Location 1 + OpDecorate %44 Location 1 + OpDecorate %46 Location 2 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeInt 32 0 + %9 = OpConstant %8 1 + %10 = OpTypeArray %6 %9 + %11 = OpTypeStruct %7 %6 %10 %10 + %12 = OpTypePointer Output %11 + %13 = OpVariable %12 Output + %14 = OpTypeInt 32 1 + %15 = OpConstant %14 0 + %16 = OpTypeMatrix %7 4 + %17 = OpTypeStruct %16 %14 + %18 = OpTypePointer PushConstant %17 + %19 = OpVariable %18 PushConstant + %20 = OpTypePointer PushConstant %16 + %23 = OpTypeVector %6 2 + %24 = OpTypePointer Input %23 + %25 = OpVariable %24 Input + %27 = OpConstant %6 0 + %28 = OpConstant %6 1 + %33 = OpTypePointer Output %7 + %35 = OpTypePointer Output %6 + %40 = OpTypePointer Output %23 + %41 = OpVariable %40 Output + %42 = OpVariable %24 Input + %44 = OpVariable %33 Output + %45 = OpTypePointer Input %7 + %46 = OpVariable %45 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %21 = OpAccessChain %20 %19 %15 + %22 = OpLoad %16 %21 + %26 = OpLoad %23 %25 + %29 = OpCompositeExtract %6 %26 0 + %30 = OpCompositeExtract %6 %26 1 + %31 = OpCompositeConstruct %7 %29 %30 %27 %28 + %32 = OpMatrixTimesVector %7 %22 %31 + %34 = OpAccessChain %33 %13 %15 + OpStore %34 %32 + %36 = OpAccessChain %35 %13 %15 %9 + %37 = OpLoad %6 %36 + %38 = OpFNegate %6 %37 + %39 = OpAccessChain %35 %13 %15 %9 + OpStore %39 %38 + %43 = OpLoad %23 %42 + OpStore %41 %43 + %47 = OpLoad %7 %46 + OpStore %44 %47 + OpReturn + OpFunctionEnd diff --git a/src/xenia/ui/vulkan/shaders/build.bat b/src/xenia/ui/vulkan/shaders/build.bat deleted file mode 100644 index c3e0322b0..000000000 --- a/src/xenia/ui/vulkan/shaders/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -glslangValidator -V immediate.vert -o immediate.vert.spv -glslangValidator -V immediate.frag -o immediate.frag.spv diff --git a/src/xenia/ui/vulkan/shaders/immediate.frag b/src/xenia/ui/vulkan/shaders/immediate.frag index b5fcdda35..c1ebb265e 100644 --- a/src/xenia/ui/vulkan/shaders/immediate.frag +++ b/src/xenia/ui/vulkan/shaders/immediate.frag @@ -1,3 +1,6 @@ +// NOTE: This file is compiled and embedded into the exe. +// Use `xenia-build genspirv` and check in any changes under bin/. + #version 450 core precision highp float; diff --git a/src/xenia/ui/vulkan/shaders/immediate.vert b/src/xenia/ui/vulkan/shaders/immediate.vert index 732553dcf..025c6ae4a 100644 --- a/src/xenia/ui/vulkan/shaders/immediate.vert +++ b/src/xenia/ui/vulkan/shaders/immediate.vert @@ -1,3 +1,6 @@ +// NOTE: This file is compiled and embedded into the exe. +// Use `xenia-build genspirv` and check in any changes under bin/. + #version 450 core precision highp float; diff --git a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc index 463e7ece0..aa9c84c72 100644 --- a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc +++ b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc @@ -20,8 +20,9 @@ namespace xe { namespace ui { namespace vulkan { -#include "xenia/ui/vulkan/shaders/immediate.frag.h" -#include "xenia/ui/vulkan/shaders/immediate.vert.h" +// Generated with `xenia-build genspirv`. +#include "xenia/ui/vulkan/shaders/bin/immediate_frag.h" +#include "xenia/ui/vulkan/shaders/bin/immediate_vert.h" constexpr uint32_t kCircularBufferCapacity = 2 * 1024 * 1024; @@ -380,9 +381,8 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context) vertex_shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vertex_shader_info.pNext = nullptr; vertex_shader_info.flags = 0; - vertex_shader_info.codeSize = sizeof(immediate_vert_spv); - vertex_shader_info.pCode = - reinterpret_cast(immediate_vert_spv); + vertex_shader_info.codeSize = sizeof(immediate_vert); + vertex_shader_info.pCode = reinterpret_cast(immediate_vert); VkShaderModule vertex_shader; err = vkCreateShaderModule(*device, &vertex_shader_info, nullptr, &vertex_shader); @@ -391,9 +391,9 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context) fragment_shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; fragment_shader_info.pNext = nullptr; fragment_shader_info.flags = 0; - fragment_shader_info.codeSize = sizeof(immediate_frag_spv); + fragment_shader_info.codeSize = sizeof(immediate_frag); fragment_shader_info.pCode = - reinterpret_cast(immediate_frag_spv); + reinterpret_cast(immediate_frag); VkShaderModule fragment_shader; err = vkCreateShaderModule(*device, &fragment_shader_info, nullptr, &fragment_shader); diff --git a/xenia-build b/xenia-build index 1986b3299..4587374c4 100755 --- a/xenia-build +++ b/xenia-build @@ -396,6 +396,7 @@ def discover_commands(subparsers): 'pull': PullCommand(subparsers), 'premake': PremakeCommand(subparsers), 'build': BuildCommand(subparsers), + 'genspirv': GenSpirvCommand(subparsers), 'gentests': GenTestsCommand(subparsers), 'test': TestCommand(subparsers), 'gputest': GpuTestCommand(subparsers), @@ -623,6 +624,103 @@ class BuildCommand(BaseBuildCommand): return result +class GenSpirvCommand(Command): + """'genspirv' command.""" + + def __init__(self, subparsers, *args, **kwargs): + super(GenSpirvCommand, self).__init__( + subparsers, + name='genspirv', + help_short='Generates SPIR-V binaries and header files.', + help_long=''' + Generates the .spv/.h binaries under src/xenia/*/vulkan/shaders/bin/). + Run after modifying any .vert/.geom/.frag files. + ''', + *args, **kwargs) + + def execute(self, args, pass_args, cwd): + print('Generating SPIR-V binaries...') + print('') + + # TODO(benvanik): actually find vulkan SDK. Env var? etc? + vulkan_sdk_path = 'C:\\VulkanSDK\\1.0.3.1' + vulkan_bin_path = os.path.join(vulkan_sdk_path, 'bin') + glslang = os.path.join(vulkan_bin_path, 'glslangValidator') + spirv_dis = os.path.join(vulkan_bin_path, 'spirv-dis') + spirv_remap = os.path.join(vulkan_bin_path, 'spirv-remap') + + # Ensure we have the tools. + if not os.path.exists(vulkan_sdk_path): + print('ERROR: could not find the Vulkan SDK') + return 1 + elif not has_bin(glslang): + print('ERROR: could not find glslangValidator') + return 1 + elif not has_bin(spirv_dis): + print('ERROR: could not find spirv-dis') + return 1 + elif not has_bin(spirv_remap): + print('ERROR: could not find spirv-remap') + return 1 + + src_files = [os.path.join(root, name) + for root, dirs, files in os.walk('src') + for name in files + if (name.endswith('.vert') or name.endswith('.geom') or + name.endswith('.frag'))] + + any_errors = False + for src_file in src_files: + print('- %s' % (src_file)) + src_name = os.path.splitext(os.path.basename(src_file))[0] + identifier = os.path.basename(src_file).replace('.', '_') + + bin_path = os.path.join(os.path.dirname(src_file), 'bin') + spv_file = os.path.join(bin_path, identifier) + '.spv' + txt_file = os.path.join(bin_path, identifier) + '.txt' + h_file = os.path.join(bin_path, identifier) + '.h' + + # GLSL source -> .spv binary + shell_call([ + glslang, + '-V', src_file, + '-o', spv_file, + ]) + + # Disassemble binary into human-readable text. + shell_call([ + spirv_dis, + '-o', txt_file, + spv_file, + ]) + + # TODO(benvanik): remap? + + # bin2c so we get a header file we can compile in. + with open(h_file, 'wb') as out_file: + out_file.write('// generated from `xb genspirv`\n') + out_file.write('// source: %s\n' % os.path.basename(src_file)) + out_file.write('const uint8_t %s[] = {' % (identifier)) + with open(spv_file, 'rb') as in_file: + index = 0 + c = in_file.read(1) + while c != '': + if index % 12 == 0: + out_file.write('\n ') + else: + out_file.write(' ') + index += 1 + out_file.write('0x%02X,' % ord(c)) + c = in_file.read(1) + out_file.write('\n};\n') + + if any_errors: + print('ERROR: failed to build one or more SPIR-V files.') + return 1 + + return 0 + + class TestCommand(BaseBuildCommand): """'test' command."""