Commit a1442ecd by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Uber-shader support

For each internal shader, there is now possibly a companion .json file that defines shader variations. The variations consist of a set of flags and a set of enums. Each enum defines a variation that takes one of a few values. Flags are shorthands for 2-value enums. In the shader code, #if can be used to change the shader based on variations derived from flags and enums. On the C++ side, those variations are combined into an index and the appropriate shader is retrieved from a table. Bug: angleproject:2958 Change-Id: Ic4fc7061adb20c047c26624305285e3005092aab Reviewed-on: https://chromium-review.googlesource.com/c/1351117 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 5f01324f
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
"Vulkan format:src/libANGLE/renderer/vulkan/vk_format_map.json": "Vulkan format:src/libANGLE/renderer/vulkan/vk_format_map.json":
"0c14ee33bcec99ee02eb6b39da046bc0", "0c14ee33bcec99ee02eb6b39da046bc0",
"Vulkan internal shader programs:src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py": "Vulkan internal shader programs:src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py":
"c1cc895645db3fe1cd284352890c219e", "b666933fa621018c3ac0e1767a0f7bc1",
"Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/FullScreenQuad.vert": "Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/FullScreenQuad.vert":
"1743adf55153edf91363fa7b4350d859", "1743adf55153edf91363fa7b4350d859",
"Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/PushConstantColor.frag": "Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/PushConstantColor.frag":
......
...@@ -1259,12 +1259,10 @@ angle::Result RendererVk::getFullScreenClearShaderProgram(vk::Context *context, ...@@ -1259,12 +1259,10 @@ angle::Result RendererVk::getFullScreenClearShaderProgram(vk::Context *context,
if (!mFullScreenClearShaderProgram.valid()) if (!mFullScreenClearShaderProgram.valid())
{ {
vk::RefCounted<vk::ShaderAndSerial> *fullScreenQuad = nullptr; vk::RefCounted<vk::ShaderAndSerial> *fullScreenQuad = nullptr;
ANGLE_TRY(mShaderLibrary.getShader(context, vk::InternalShaderID::FullScreenQuad_vert, ANGLE_TRY(mShaderLibrary.getFullScreenQuad_vert(context, 0, &fullScreenQuad));
&fullScreenQuad));
vk::RefCounted<vk::ShaderAndSerial> *pushConstantColor = nullptr; vk::RefCounted<vk::ShaderAndSerial> *pushConstantColor = nullptr;
ANGLE_TRY(mShaderLibrary.getShader(context, vk::InternalShaderID::PushConstantColor_frag, ANGLE_TRY(mShaderLibrary.getPushConstantColor_frag(context, 0, &pushConstantColor));
&pushConstantColor));
mFullScreenClearShaderProgram.setShader(gl::ShaderType::Vertex, fullScreenQuad); mFullScreenClearShaderProgram.setShader(gl::ShaderType::Vertex, fullScreenQuad);
mFullScreenClearShaderProgram.setShader(gl::ShaderType::Fragment, pushConstantColor); mFullScreenClearShaderProgram.setShader(gl::ShaderType::Fragment, pushConstantColor);
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "libANGLE/renderer/vulkan/QueryVk.h" #include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "libANGLE/renderer/vulkan/vk_internal_shaders.h" #include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
namespace egl namespace egl
{ {
......
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
# found in the LICENSE file. # found in the LICENSE file.
# #
# gen_vk_internal_shaders.py: # gen_vk_internal_shaders.py:
# Code generation for internal Vulkan shaders. Should be run when an intenal # Code generation for internal Vulkan shaders. Should be run when an internal
# shader program is changed, added or removed. # shader program is changed, added or removed.
from datetime import date from datetime import date
import json
import os import os
import re
import subprocess import subprocess
import sys import sys
...@@ -29,29 +31,39 @@ template_shader_library_cpp = """// GENERATED FILE - DO NOT EDIT. ...@@ -29,29 +31,39 @@ template_shader_library_cpp = """// GENERATED FILE - DO NOT EDIT.
#include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h" #include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
#include "common/debug.h"
namespace rx namespace rx
{{ {{
namespace vk namespace vk
{{ {{
namespace priv
{{
namespace namespace
{{ {{
{internal_shader_includes} {internal_shader_includes}
constexpr ShaderBlob kShaderBlobs[] = {{ // This is SPIR-V binary blob and the size.
{internal_shader_array_entries} struct ShaderBlob
{{
const uint32_t *code;
size_t codeSize;
}}; }};
{shader_tables_cpp}
}} // anonymous namespace }} // anonymous namespace
const ShaderBlob &GetInternalShaderBlob(InternalShaderID shaderID)
ShaderLibrary::ShaderLibrary()
{{ {{
ASSERT(static_cast<size_t>(shaderID) < static_cast<size_t>(InternalShaderID::EnumCount));
return kShaderBlobs[static_cast<size_t>(shaderID)];
}} }}
}} // namespace priv
ShaderLibrary::~ShaderLibrary()
{{
}}
void ShaderLibrary::destroy(VkDevice device)
{{
{shader_destroy_calls}
}}
{shader_get_functions_cpp}
}} // namespace vk }} // namespace vk
}} // namespace rx }} // namespace rx
""" """
...@@ -69,30 +81,30 @@ template_shader_library_h = """// GENERATED FILE - DO NOT EDIT. ...@@ -69,30 +81,30 @@ template_shader_library_h = """// GENERATED FILE - DO NOT EDIT.
#ifndef LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_ #ifndef LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_
#define LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_ #define LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_
#include <stddef.h> #include "libANGLE/renderer/vulkan/vk_utils.h"
#include <stdint.h>
#include <utility>
namespace rx namespace rx
{{ {{
namespace vk namespace vk
{{ {{
enum class InternalShaderID namespace InternalShader
{{ {{
{internal_shader_ids} {shader_variation_definitions}
}}; }} // namespace InternalShader
namespace priv class ShaderLibrary final : angle::NonCopyable
{{
// This is SPIR-V binary blob and the size.
struct ShaderBlob
{{ {{
const uint32_t *code; public:
size_t codeSize; ShaderLibrary();
~ShaderLibrary();
void destroy(VkDevice device);
{shader_get_functions_h}
private:
{shader_tables_h}
}}; }};
const ShaderBlob &GetInternalShaderBlob(InternalShaderID shaderID);
}} // priv
}} // namespace vk }} // namespace vk
}} // namespace rx }} // namespace rx
...@@ -115,8 +127,16 @@ angle_vulkan_internal_shaders = [ ...@@ -115,8 +127,16 @@ angle_vulkan_internal_shaders = [
""" """
# Gets the constant variable name for a generated shader. # Gets the constant variable name for a generated shader.
def get_var_name(shader): def get_var_name(output, prefix='k'):
return "k" + os.path.basename(shader).replace(".", "_") return prefix + output.replace(".", "_")
# Gets the namespace name given to constants generated from shader_file
def get_namespace_name(shader_file):
return get_var_name(os.path.basename(shader_file), '')
# Gets the namespace name given to constants generated from shader_file
def get_variation_table_name(shader_file, prefix='k'):
return get_var_name(os.path.basename(shader_file), prefix) + '_shaders'
# Gets the internal ID string for a particular shader. # Gets the internal ID string for a particular shader.
def get_shader_id(shader): def get_shader_id(shader):
...@@ -124,8 +144,8 @@ def get_shader_id(shader): ...@@ -124,8 +144,8 @@ def get_shader_id(shader):
return file.replace(".", "_") return file.replace(".", "_")
# Returns the name of the generated SPIR-V file for a shader. # Returns the name of the generated SPIR-V file for a shader.
def get_output_name(shader): def get_output_path(name):
return os.path.join('shaders', 'gen', os.path.basename(shader) + ".inc") return os.path.join('shaders', 'gen', name + ".inc")
# Finds a path to GN's out directory # Finds a path to GN's out directory
def find_build_path(path): def find_build_path(path):
...@@ -155,22 +175,68 @@ def slash(s): ...@@ -155,22 +175,68 @@ def slash(s):
def gen_shader_include(shader): def gen_shader_include(shader):
return '#include "libANGLE/renderer/vulkan/%s"' % slash(shader) return '#include "libANGLE/renderer/vulkan/%s"' % slash(shader)
def get_shader_variations(shader):
variation_file = shader + '.json'
if not os.path.exists(variation_file):
# If there is no variation file, assume none.
return ({}, [])
with open(variation_file) as fin:
variations = json.loads(fin.read())
flags = {}
enums = []
for key, value in variations.iteritems():
if key == "Description":
continue
elif key == "Flags":
flags = value
elif len(value) > 0:
enums.append((key, value))
# sort enums so the ones with the most waste ends up last, reducing the table size
enums.sort(key=lambda enum: (1 << (len(enum[1]) - 1).bit_length()) / float(len(enum[1])))
return (flags, enums)
def get_variation_bits(flags, enums):
flags_bits = len(flags)
enum_bits = [(len(enum[1]) - 1).bit_length() for enum in enums]
return (flags_bits, enum_bits)
def next_enum_variation(enums, enum_indices):
"""Loop through indices from [0, 0, ...] to [L0-1, L1-1, ...]
where Li is len(enums[i]). The list can be thought of as a number with many
digits, where each digit is in [0, Li), and this function effectively implements
the increment operation, with the least-significant digit being the first item."""
for i in range(len(enums)):
current = enum_indices[i]
# if current digit has room, increment it.
if current + 1 < len(enums[i][1]):
enum_indices[i] = current + 1
return True;
# otherwise reset it to 0 and carry to the next digit.
enum_indices[i] = 0
# if this is reached, the number has overflowed and the loop is finished.
return False
compact_newlines_regex = re.compile(r"\n\s*\n", re.MULTILINE)
def cleanup_preprocessed_shader(shader_text):
return compact_newlines_regex.sub('\n\n', shader_text.strip())
# STEP 0: Handle inputs/outputs for run_code_generation.py's auto_script # STEP 0: Handle inputs/outputs for run_code_generation.py's auto_script
shaders_dir = os.path.join('shaders', 'src') shaders_dir = os.path.join('shaders', 'src')
if not os.path.isdir(shaders_dir): if not os.path.isdir(shaders_dir):
raise Exception("Could not find shaders directory") raise Exception("Could not find shaders directory")
input_shaders = sorted([os.path.join(shaders_dir, shader) for shader in os.listdir(shaders_dir)]) valid_extensions = ['.vert', '.frag', '.comp']
output_shaders = sorted([get_output_name(shader) for shader in input_shaders]) input_shaders = sorted([os.path.join(shaders_dir, shader)
for shader in os.listdir(shaders_dir)
outputs = output_shaders + [out_file_cpp, out_file_h] if any([os.path.splitext(shader)[1] == ext for ext in valid_extensions])])
if len(sys.argv) == 2 and sys.argv[1] == 'inputs': if len(sys.argv) == 2 and sys.argv[1] == 'inputs':
print(",".join(input_shaders)) print(",".join(input_shaders))
sys.exit(0) sys.exit(0)
elif len(sys.argv) == 2 and sys.argv[1] == 'outputs':
print(",".join(outputs))
sys.exit(0)
# STEP 1: Call glslang to generate the internal shaders into small .inc files. # STEP 1: Call glslang to generate the internal shaders into small .inc files.
...@@ -189,40 +255,286 @@ if not os.path.isfile(glslang_path): ...@@ -189,40 +255,286 @@ if not os.path.isfile(glslang_path):
raise Exception("Could not find " + glslang_binary) raise Exception("Could not find " + glslang_binary)
# b) Iterate over the shaders and call glslang with the right arguments. # b) Iterate over the shaders and call glslang with the right arguments.
for shader_file in input_shaders: output_shaders = []
glslang_args = [
glslang_path, def compile_variation(shader_file, shader_basename, flags, enums,
'-V', # Output mode is Vulkan flags_active, enum_indices, flags_bits, enum_bits, do_compile):
'--variable-name', get_var_name(shader_file), # C-style variable name
'-o', get_output_name(shader_file), # Output file glslang_args = [glslang_path]
shader_file, # Input GLSL shader
] # generate -D defines and the output file name
result = subprocess.call(glslang_args) #
if result != 0: # The variations are given a bit pattern to be able to OR different flags into a variation. The
raise Exception("Error compiling " + shader_file) # least significant bits are the flags, where there is one bit per flag. After that, each enum
# takes up as few bits as needed to count that many enum values.
variation_bits = 0
variation_string = ''
for f in range(len(flags)):
if flags_active & (1 << f):
flag_name = flags[f]
glslang_args.append('-D' + flag_name + '=1')
variation_bits |= 1 << f
variation_string += '|' + flag_name
current_bit_start = flags_bits
for e in range(len(enums)):
enum_name = enums[e][1][enum_indices[e]]
glslang_args.append('-D' + enum_name + '=1')
variation_bits |= enum_indices[e] << current_bit_start
current_bit_start += enum_bits[e]
variation_string += '|' + enum_name
output_name = '%s.%08X' % (shader_basename, variation_bits)
output_path = get_output_path(output_name)
output_shaders.append(output_path)
if do_compile:
glslang_preprocessor_output_args = glslang_args + ['-E']
glslang_preprocessor_output_args.append(shader_file) # Input GLSL shader
glslang_args += ['-V'] # Output mode is Vulkan
glslang_args += ['--variable-name', get_var_name(output_name)] # C-style variable name
glslang_args += ['-o', output_path] # Output file
glslang_args.append(shader_file) # Input GLSL shader
print output_path + ': ' + shader_basename + variation_string
result = subprocess.call(glslang_args)
if result != 0:
raise Exception("Error compiling " + shader_file)
with open(output_path, 'a') as incfile:
shader_text = subprocess.check_output(glslang_preprocessor_output_args)
incfile.write('\n\n#if 0 // Generated from:\n')
incfile.write(cleanup_preprocessed_shader(shader_text))
incfile.write('\n#endif // Preprocessed code\n')
class ShaderAndVariations:
def __init__(self, shader_file):
self.shader_file = shader_file
(self.flags, self.enums) = get_shader_variations(shader_file)
get_variation_bits(self.flags, self.enums)
(self.flags_bits, self.enum_bits) = get_variation_bits(self.flags, self.enums)
input_shaders_and_variations = [ShaderAndVariations(shader_file) for shader_file in input_shaders]
print_outputs = len(sys.argv) == 2 and sys.argv[1] == 'outputs'
for shader_and_variation in input_shaders_and_variations:
shader_file = shader_and_variation.shader_file
flags = shader_and_variation.flags
enums = shader_and_variation.enums
flags_bits = shader_and_variation.flags_bits
enum_bits = shader_and_variation.enum_bits
# an array where each element i is in [0, len(enums[i])),
# telling which enum is currently selected
enum_indices = [0] * len(enums)
output_name = os.path.basename(shader_file)
while True:
# a number where each bit says whether a flag is active or not,
# with values in [0, 2^len(flags))
for flags_active in range(1 << len(flags)):
compile_variation(shader_file, output_name, flags, enums,
flags_active, enum_indices, flags_bits, enum_bits, not print_outputs)
if not next_enum_variation(enums, enum_indices):
break
output_shaders = sorted(output_shaders)
outputs = output_shaders + [out_file_cpp, out_file_h]
if print_outputs:
print("\n".join(outputs))
sys.exit(0)
# STEP 2: Consolidate the .inc files into an auto-generated cpp/h library. # STEP 2: Consolidate the .inc files into an auto-generated cpp/h library.
def get_variation_definition(shader_and_variation):
shader_file = shader_and_variation.shader_file
flags = shader_and_variation.flags
enums = shader_and_variation.enums
flags_bits = shader_and_variation.flags_bits
enum_bits = shader_and_variation.enum_bits
namespace_name = get_namespace_name(shader_file)
definition = 'namespace %s\n{\n' % namespace_name
if len(flags) > 0:
definition += 'enum flags\n{\n'
definition += ''.join(['k%s = 0x%08X,\n' % (flags[f], 1 << f) for f in range(len(flags))])
definition += 'kFlagsMask = 0x%08X,\n' % ((1 << flags_bits) - 1)
definition += '};\n'
current_bit_start = flags_bits
for e in range(len(enums)):
enum = enums[e]
enum_name = enum[0]
definition += 'enum %s\n{\n' % enum_name
definition += ''.join(['k%s = 0x%08X,\n' %
(enum[1][v], v << current_bit_start) for v in range(len(enum[1]))])
definition += 'k%sMask = 0x%08X,\n' % (enum_name, ((1 << enum_bits[e]) - 1) << current_bit_start)
definition += '};\n'
current_bit_start += enum_bits[e]
definition += '} // namespace %s\n' % namespace_name
return definition
def get_shader_table_h(shader_and_variation):
shader_file = shader_and_variation.shader_file
flags = shader_and_variation.flags
enums = shader_and_variation.enums
table_name = get_variation_table_name(shader_file, 'm')
table = 'RefCounted<ShaderAndSerial> %s[' % table_name
namespace_name = "InternalShader::" + get_namespace_name(shader_file)
first_or = True
if len(flags) > 0:
table += '%s::kFlagsMask' % namespace_name
first_or = False
for e in range(len(enums)):
enum = enums[e]
enum_name = enums[e][0]
if not first_or:
table += ' | '
table += '%s::k%sMask' % (namespace_name, enum_name)
first_or = False
if first_or:
table += '1'
table += '];'
return table
def get_shader_table_cpp(shader_and_variation):
shader_file = shader_and_variation.shader_file
enums = shader_and_variation.enums
flags_bits = shader_and_variation.flags_bits
enum_bits = shader_and_variation.enum_bits
# Cache max and mask value of each enum to quickly know when a possible variation is invalid
enum_maxes = []
enum_masks = []
current_bit_start = flags_bits
for e in range(len(enums)):
enum_values = enums[e][1]
enum_maxes.append((len(enum_values) - 1) << current_bit_start)
enum_masks.append(((1 << enum_bits[e]) - 1) << current_bit_start)
current_bit_start += enum_bits[e]
table_name = get_variation_table_name(shader_file)
var_name = get_var_name(os.path.basename(shader_file))
table = 'constexpr ShaderBlob %s[] = {\n' % table_name
# The last possible variation is every flag enabled and every enum at max
last_variation = ((1 << flags_bits) - 1) | reduce(lambda x, y: x|y, enum_maxes, 0)
for variation in range(last_variation + 1):
# if any variation is invalid, output an empty entry
if any([(variation & enum_masks[e]) > enum_maxes[e] for e in range(len(enums))]):
table += '{nullptr, 0}, // 0x%08X\n' % variation
else:
entry = '%s_%08X' % (var_name, variation)
table += '{%s, sizeof(%s)},\n' % (entry, entry)
table += '};'
return table
def get_get_function_h(shader_and_variation):
shader_file = shader_and_variation.shader_file
function_name = get_var_name(os.path.basename(shader_file), 'get')
definition = 'angle::Result %s' % function_name
definition += '(Context *context, uint32_t shaderFlags, RefCounted<ShaderAndSerial> **shaderOut);'
return definition
def get_get_function_cpp(shader_and_variation):
shader_file = shader_and_variation.shader_file
enums = shader_and_variation.enums
function_name = get_var_name(os.path.basename(shader_file), 'get')
namespace_name = "InternalShader::" + get_namespace_name(shader_file)
member_table_name = get_variation_table_name(shader_file, 'm')
constant_table_name = get_variation_table_name(shader_file)
definition = 'angle::Result ShaderLibrary::%s' % function_name
definition += '(Context *context, uint32_t shaderFlags, RefCounted<ShaderAndSerial> **shaderOut)\n{\n'
definition += 'ASSERT(shaderFlags < ArraySize(%s));\n' % constant_table_name
definition += ''.join(['ASSERT((shaderFlags & %s::k%sMask) >= %s::k%s &&' %
(namespace_name, enums[e][0], namespace_name, enums[e][1][0]) +
'(shaderFlags & %s::k%sMask) <= %s::k%s);\n' %
(namespace_name, enums[e][0], namespace_name, enums[e][1][-1])
for e in range(len(enums))])
definition += 'RefCounted<ShaderAndSerial> &shader = %s[shaderFlags];\n' % member_table_name
definition += '*shaderOut = &shader;\n\n'
definition += 'if (shader.get().valid())\n{\nreturn angle::Result::Continue();\n}\n\n'
definition += '// Create shader lazily. Access will need to be locked for multi-threading.\n'
definition += 'const ShaderBlob &shaderCode = %s[shaderFlags];\n' % constant_table_name
definition += 'return InitShaderAndSerial(context, &shader.get(), shaderCode.code, shaderCode.codeSize);\n'
definition += '}\n'
return definition
def get_destroy_call(shader_and_variation):
shader_file = shader_and_variation.shader_file
table_name = get_variation_table_name(shader_file, 'm')
destroy = 'for (RefCounted<ShaderAndSerial> &shader : %s)\n' % table_name
destroy += '{\nshader.get().destroy(device);\n}'
return destroy
with open(out_file_cpp, 'w') as outfile: with open(out_file_cpp, 'w') as outfile:
includes = "\n".join([gen_shader_include(shader) for shader in output_shaders]) includes = "\n".join([gen_shader_include(shader) for shader in output_shaders])
array_entries = ",\n".join([gen_shader_blob_entry(shader) for shader in output_shaders]) shader_tables_cpp = '\n'.join([get_shader_table_cpp(s)
for s in input_shaders_and_variations])
shader_destroy_calls = '\n'.join([get_destroy_call(s)
for s in input_shaders_and_variations])
shader_get_functions_cpp = '\n'.join([get_get_function_cpp(s)
for s in input_shaders_and_variations])
outcode = template_shader_library_cpp.format( outcode = template_shader_library_cpp.format(
script_name = __file__, script_name = __file__,
copyright_year = date.today().year, copyright_year = date.today().year,
out_file_name = out_file_cpp, out_file_name = out_file_cpp,
input_file_name = 'shaders/src/*', input_file_name = 'shaders/src/*',
internal_shader_includes = includes, internal_shader_includes = includes,
internal_shader_array_entries = array_entries) shader_tables_cpp = shader_tables_cpp,
shader_destroy_calls = shader_destroy_calls,
shader_get_functions_cpp = shader_get_functions_cpp)
outfile.write(outcode) outfile.write(outcode)
outfile.close() outfile.close()
with open(out_file_h, 'w') as outfile: with open(out_file_h, 'w') as outfile:
ids = ",\n".join([get_shader_id(shader) for shader in output_shaders] + ["EnumCount"]) shader_variation_definitions = '\n'.join([get_variation_definition(s)
for s in input_shaders_and_variations])
shader_get_functions_h = '\n'.join([get_get_function_h(s)
for s in input_shaders_and_variations])
shader_tables_h = '\n'.join([get_shader_table_h(s)
for s in input_shaders_and_variations])
outcode = template_shader_library_h.format( outcode = template_shader_library_h.format(
script_name = __file__, script_name = __file__,
copyright_year = date.today().year, copyright_year = date.today().year,
out_file_name = out_file_h, out_file_name = out_file_h,
input_file_name = 'shaders/src/*', input_file_name = 'shaders/src/*',
internal_shader_ids = ids) shader_variation_definitions = shader_variation_definitions,
shader_get_functions_h = shader_get_functions_h,
shader_tables_h = shader_tables_h)
outfile.write(outcode) outfile.write(outcode)
outfile.close() outfile.close()
......
// 7.7.2767 // 7.10.2904
#pragma once #pragma once
const uint32_t kFullScreenQuad_vert[] = { const uint32_t kFullScreenQuad_vert_00000000[] = {
0x07230203,0x00010000,0x00080007,0x00000024,0x00000000,0x00020011,0x00000001,0x0006000b, 0x07230203,0x00010000,0x00080007,0x00000024,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0007000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x0000001b,0x00030003, 0x0007000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x0000001b,0x00030003,
...@@ -34,4 +34,22 @@ const uint32_t kFullScreenQuad_vert[] = { ...@@ -34,4 +34,22 @@ const uint32_t kFullScreenQuad_vert[] = {
0x0000001c,0x0000001b,0x0003003e,0x0000001e,0x00000019,0x00050041,0x0000001f,0x00000020, 0x0000001c,0x0000001b,0x0003003e,0x0000001e,0x00000019,0x00050041,0x0000001f,0x00000020,
0x0000001e,0x0000001c,0x0004003d,0x00000007,0x00000021,0x00000020,0x00050041,0x00000022, 0x0000001e,0x0000001c,0x0004003d,0x00000007,0x00000021,0x00000020,0x00050041,0x00000022,
0x00000023,0x0000000d,0x0000000f,0x0003003e,0x00000023,0x00000021,0x000100fd,0x00010038 0x00000023,0x0000000d,0x0000000f,0x0003003e,0x00000023,0x00000021,0x000100fd,0x00010038
}; };
\ No newline at end of file
#if 0 // Generated from:
#version 450 core
const vec4 kQuadVertices[]= {
vec4(- 1, 1, 0, 1),
vec4(- 1, - 1, 0, 1),
vec4(1, - 1, 0, 1),
vec4(- 1, 1, 0, 1),
vec4(1, - 1, 0, 1),
vec4(1, 1, 0, 1),
};
void main()
{
gl_Position = kQuadVertices[gl_VertexIndex];
}
#endif // Preprocessed code
// 7.7.2767 // 7.10.2904
#pragma once #pragma once
const uint32_t kPushConstantColor_frag[] = { const uint32_t kPushConstantColor_frag_00000000[] = {
0x07230203,0x00010000,0x00080007,0x00000012,0x00000000,0x00020011,0x00000001,0x0006000b, 0x07230203,0x00010000,0x00080007,0x00000012,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0006000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x00030010,0x00000004, 0x0006000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x00030010,0x00000004,
...@@ -17,4 +17,19 @@ const uint32_t kPushConstantColor_frag[] = { ...@@ -17,4 +17,19 @@ const uint32_t kPushConstantColor_frag[] = {
0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041, 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,
0x0000000f,0x00000010,0x0000000c,0x0000000e,0x0004003d,0x00000007,0x00000011,0x00000010, 0x0000000f,0x00000010,0x0000000c,0x0000000e,0x0004003d,0x00000007,0x00000011,0x00000010,
0x0003003e,0x00000009,0x00000011,0x000100fd,0x00010038 0x0003003e,0x00000009,0x00000011,0x000100fd,0x00010038
}; };
\ No newline at end of file
#if 0 // Generated from:
#version 450 core
layout(push_constant)uniform block {
vec4 colorIn;
};
layout(location = 0)out vec4 colorOut;
void main()
{
colorOut = colorIn;
}
#endif // Preprocessed code
# Shader Variations
To build multiple variations of a shader, add a file named X.json corresponding to shader file X. A
variation is generated by building the shader with different definitions (a la glslang_validator's
-DName=1). These definitions come from flags and enumerations defined in the json file.
There are multiple possible fields in the json file:
- "Description": This contains the license and other comments, which will be ignored.
- "Flags": this is a list of flags. Each flag FLAG defines a shader variation with or without the
define FLAG=1.
- other: any other field is a similar list to flags, except that each entry in this enumeration is a
variation. Similar to "flags", every entry ENTRY results in an ENTRY=1 define.
Flags are shorthand for 2-entry enumerations. Given n flags, there are 2^n variations where every
flag is either present or not. For enumerations, only one entry is active in any variation. Thus,
an enumeration with n entries generates n variations.
## Example
Here is an example json file:
{
"Description": [
"Copyright 2018 The ANGLE Project Authors. All rights reserved.",
"Use of this source code is governed by a BSD-style license that can be",
"found in the LICENSE file.",
"",
"RayTrace.comp.json: Build parameters for RayTrace.comp."
],
"Flags": [
"NanFilter",
"WorkaroundIntelBug"
],
"RayTraceQuality": [
"IsRTLowRes",
"IsRTHighRes",
"IsRTAwesome"
],
"ImageType": [
"IsR",
"IsRG",
"IsRGB",
"IsRGBA"
]
}
This will generate 2^2 * 3 * 4 shaders.
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_internal_shaders.cpp:
// Pre-generated shader library for the ANGLE Vulkan back-end.
#include "libANGLE/renderer/vulkan/vk_internal_shaders.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
{
namespace vk
{
ShaderLibrary::ShaderLibrary() {}
ShaderLibrary::~ShaderLibrary() {}
void ShaderLibrary::destroy(VkDevice device)
{
for (RefCounted<ShaderAndSerial> &shader : mShaders)
{
shader.get().destroy(device);
}
}
angle::Result ShaderLibrary::getShader(vk::Context *context,
InternalShaderID shaderID,
RefCounted<ShaderAndSerial> **shaderOut)
{
RefCounted<ShaderAndSerial> &shader = mShaders[shaderID];
*shaderOut = &shader;
if (shader.get().valid())
{
return angle::Result::Continue();
}
// Create shader lazily. Access will need to be locked for multi-threading.
const priv::ShaderBlob &shaderCode = priv::GetInternalShaderBlob(shaderID);
return InitShaderAndSerial(context, &shader.get(), shaderCode.code, shaderCode.codeSize);
}
} // namespace vk
} // namespace rx
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_internal_shaders.h:
// Pre-generated shader library for the ANGLE Vulkan back-end.
#ifndef LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_H_
#define LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_H_
#include "common/PackedEnums.h"
#include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
namespace vk
{
class ShaderLibrary final : angle::NonCopyable
{
public:
ShaderLibrary();
~ShaderLibrary();
angle::Result getShader(Context *context,
InternalShaderID shaderID,
RefCounted<ShaderAndSerial> **shaderOut);
void destroy(VkDevice device);
private:
angle::PackedEnumMap<InternalShaderID, RefCounted<ShaderAndSerial>> mShaders;
};
} // namespace vk
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_H_
...@@ -10,28 +10,81 @@ ...@@ -10,28 +10,81 @@
#include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h" #include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
#include "common/debug.h"
namespace rx namespace rx
{ {
namespace vk namespace vk
{ {
namespace priv
{
namespace namespace
{ {
#include "libANGLE/renderer/vulkan/shaders/gen/FullScreenQuad.vert.inc" #include "libANGLE/renderer/vulkan/shaders/gen/FullScreenQuad.vert.00000000.inc"
#include "libANGLE/renderer/vulkan/shaders/gen/PushConstantColor.frag.inc" #include "libANGLE/renderer/vulkan/shaders/gen/PushConstantColor.frag.00000000.inc"
constexpr ShaderBlob kShaderBlobs[] = {{kFullScreenQuad_vert, sizeof(kFullScreenQuad_vert)}, // This is SPIR-V binary blob and the size.
{kPushConstantColor_frag, sizeof(kPushConstantColor_frag)}}; struct ShaderBlob
{
const uint32_t *code;
size_t codeSize;
};
constexpr ShaderBlob kFullScreenQuad_vert_shaders[] = {
{kFullScreenQuad_vert_00000000, sizeof(kFullScreenQuad_vert_00000000)},
};
constexpr ShaderBlob kPushConstantColor_frag_shaders[] = {
{kPushConstantColor_frag_00000000, sizeof(kPushConstantColor_frag_00000000)},
};
} // anonymous namespace } // anonymous namespace
const ShaderBlob &GetInternalShaderBlob(InternalShaderID shaderID) ShaderLibrary::ShaderLibrary() {}
ShaderLibrary::~ShaderLibrary() {}
void ShaderLibrary::destroy(VkDevice device)
{ {
ASSERT(static_cast<size_t>(shaderID) < static_cast<size_t>(InternalShaderID::EnumCount)); for (RefCounted<ShaderAndSerial> &shader : mFullScreenQuad_vert_shaders)
return kShaderBlobs[static_cast<size_t>(shaderID)]; {
shader.get().destroy(device);
}
for (RefCounted<ShaderAndSerial> &shader : mPushConstantColor_frag_shaders)
{
shader.get().destroy(device);
}
} }
} // namespace priv
angle::Result ShaderLibrary::getFullScreenQuad_vert(Context *context,
uint32_t shaderFlags,
RefCounted<ShaderAndSerial> **shaderOut)
{
ASSERT(shaderFlags < ArraySize(kFullScreenQuad_vert_shaders));
RefCounted<ShaderAndSerial> &shader = mFullScreenQuad_vert_shaders[shaderFlags];
*shaderOut = &shader;
if (shader.get().valid())
{
return angle::Result::Continue();
}
// Create shader lazily. Access will need to be locked for multi-threading.
const ShaderBlob &shaderCode = kFullScreenQuad_vert_shaders[shaderFlags];
return InitShaderAndSerial(context, &shader.get(), shaderCode.code, shaderCode.codeSize);
}
angle::Result ShaderLibrary::getPushConstantColor_frag(Context *context,
uint32_t shaderFlags,
RefCounted<ShaderAndSerial> **shaderOut)
{
ASSERT(shaderFlags < ArraySize(kPushConstantColor_frag_shaders));
RefCounted<ShaderAndSerial> &shader = mPushConstantColor_frag_shaders[shaderFlags];
*shaderOut = &shader;
if (shader.get().valid())
{
return angle::Result::Continue();
}
// Create shader lazily. Access will need to be locked for multi-threading.
const ShaderBlob &shaderCode = kPushConstantColor_frag_shaders[shaderFlags];
return InitShaderAndSerial(context, &shader.get(), shaderCode.code, shaderCode.codeSize);
}
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
...@@ -9,6 +9,6 @@ ...@@ -9,6 +9,6 @@
# List of generated shaders for inclusion in ANGLE's build process. # List of generated shaders for inclusion in ANGLE's build process.
angle_vulkan_internal_shaders = [ angle_vulkan_internal_shaders = [
"shaders/gen/FullScreenQuad.vert.inc", "shaders/gen/FullScreenQuad.vert.00000000.inc",
"shaders/gen/PushConstantColor.frag.inc", "shaders/gen/PushConstantColor.frag.00000000.inc",
] ]
...@@ -11,32 +11,41 @@ ...@@ -11,32 +11,41 @@
#ifndef LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_ #ifndef LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_
#define LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_ #define LIBANGLE_RENDERER_VULKAN_VK_INTERNAL_SHADERS_AUTOGEN_H_
#include <stddef.h> #include "libANGLE/renderer/vulkan/vk_utils.h"
#include <stdint.h>
#include <utility>
namespace rx namespace rx
{ {
namespace vk namespace vk
{ {
enum class InternalShaderID namespace InternalShader
{ {
FullScreenQuad_vert, namespace FullScreenQuad_vert
PushConstantColor_frag, {} // namespace FullScreenQuad_vert
EnumCount
};
namespace priv namespace PushConstantColor_frag
{ {} // namespace PushConstantColor_frag
// This is SPIR-V binary blob and the size.
struct ShaderBlob } // namespace InternalShader
class ShaderLibrary final : angle::NonCopyable
{ {
const uint32_t *code; public:
size_t codeSize; ShaderLibrary();
~ShaderLibrary();
void destroy(VkDevice device);
angle::Result getFullScreenQuad_vert(Context *context,
uint32_t shaderFlags,
RefCounted<ShaderAndSerial> **shaderOut);
angle::Result getPushConstantColor_frag(Context *context,
uint32_t shaderFlags,
RefCounted<ShaderAndSerial> **shaderOut);
private:
RefCounted<ShaderAndSerial> mFullScreenQuad_vert_shaders[1];
RefCounted<ShaderAndSerial> mPushConstantColor_frag_shaders[1];
}; };
const ShaderBlob &GetInternalShaderBlob(InternalShaderID shaderID);
} // namespace priv
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -748,8 +748,6 @@ libangle_vulkan_sources = [ ...@@ -748,8 +748,6 @@ libangle_vulkan_sources = [
"src/libANGLE/renderer/vulkan/vk_format_utils.cpp", "src/libANGLE/renderer/vulkan/vk_format_utils.cpp",
"src/libANGLE/renderer/vulkan/vk_helpers.cpp", "src/libANGLE/renderer/vulkan/vk_helpers.cpp",
"src/libANGLE/renderer/vulkan/vk_helpers.h", "src/libANGLE/renderer/vulkan/vk_helpers.h",
"src/libANGLE/renderer/vulkan/vk_internal_shaders.cpp",
"src/libANGLE/renderer/vulkan/vk_internal_shaders.h",
"src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h", "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h",
"src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp", "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp",
"src/libANGLE/renderer/vulkan/vk_mandatory_format_support_table_autogen.cpp", "src/libANGLE/renderer/vulkan/vk_mandatory_format_support_table_autogen.cpp",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment