Vulkan: Create unresolve shader directly in SPIR-V

Per issue 4889, dependency to glslang is being dropped.  This change
generates the unresolve UtilsVk shader directly in SPIR-V.

This shader is trivial and contains repeating patterns per attachment.
As a result, generating its SPIR-V is exceptionally simple.  The SPIR-V
in this change is first generated by glslang validator and is then
adapted for autogeneration.

See comments in the code for details.

Bug: angleproject:4889
Change-Id: I48dd77ae04e1035c05a8aef7bf2f161e105ae2a4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2407179
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
This commit is contained in:
Shahbaz Youssefi 2020-09-11 22:41:36 -04:00 коммит произвёл Commit Bot
Родитель c054008f9e
Коммит 8844599fba
10 изменённых файлов: 577 добавлений и 93 удалений

Просмотреть файл

@ -1,10 +1,10 @@
{
"src/common/spirv/gen_spirv_builder_and_parser.py":
"60a5245905287df8a9fb55be33acfc48",
"ac2db108072c8c12c7817fd923e22bde",
"src/common/spirv/spirv_instruction_builder_autogen.cpp":
"6ea97ca168ecccb4a621a06446e4933a",
"52f80a4b5b549ff5568be9f74dd2e3c1",
"src/common/spirv/spirv_instruction_builder_autogen.h":
"7f0130816be26511615f7b1e33fda196",
"54ff9094108732d4b10c4c33b4fb38e0",
"src/common/spirv/spirv_instruction_parser_autogen.cpp":
"55d28bb4b003dbecf31e162ff996fc4f",
"src/common/spirv/spirv_instruction_parser_autogen.h":

Просмотреть файл

@ -90,7 +90,34 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
return static_cast<uint32_t>(length) << 16 | op;
}
} // anonymous namespace"""
} // anonymous namespace
void WriteSpirvHeader(std::vector<uint32_t> *blob, uint32_t idCount)
{
// Header:
//
// - Magic number
// - Version (1.0)
// - ANGLE's Generator number:
// * 24 for tool id (higher 16 bits)
// * 0 for tool version (lower 16 bits))
// - Bound (idCount)
// - 0 (reserved)
constexpr uint32_t kANGLEGeneratorId = 24;
ASSERT(blob->empty());
blob->push_back(spv::MagicNumber);
blob->push_back(0x00010000);
blob->push_back(kANGLEGeneratorId << 16 | 0);
blob->push_back(idCount);
blob->push_back(0x00000000);
}
"""
BUILDER_HELPER_FUNCTION_PROTOTYPE = """
void WriteSpirvHeader(std::vector<uint32_t> *blob, uint32_t idCount);
"""
PARSER_FIXED_FUNCTIONS_PROTOTYPES = """void GetInstructionOpAndLength(const uint32_t *_instruction,
spv::Op *opOut, uint32_t *lengthOut);
@ -157,7 +184,7 @@ class Writer:
self.bit_mask_types = set([])
# List of generated instructions builder/parser functions so far.
self.instruction_builder_prototypes = []
self.instruction_builder_prototypes = [BUILDER_HELPER_FUNCTION_PROTOTYPE]
self.instruction_builder_impl = []
self.instruction_parser_prototypes = [PARSER_FIXED_FUNCTIONS_PROTOTYPES]
self.instruction_parser_impl = [PARSER_FIXED_FUNCTIONS]

Просмотреть файл

@ -29,6 +29,28 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
}
} // anonymous namespace
void WriteSpirvHeader(std::vector<uint32_t> *blob, uint32_t idCount)
{
// Header:
//
// - Magic number
// - Version (1.0)
// - ANGLE's Generator number:
// * 24 for tool id (higher 16 bits)
// * 0 for tool version (lower 16 bits))
// - Bound (idCount)
// - 0 (reserved)
constexpr uint32_t kANGLEGeneratorId = 24;
ASSERT(blob->empty());
blob->push_back(spv::MagicNumber);
blob->push_back(0x00010000);
blob->push_back(kANGLEGeneratorId << 16 | 0);
blob->push_back(idCount);
blob->push_back(0x00000000);
}
void WriteNop(std::vector<uint32_t> *blob)
{
const size_t startSize = blob->size();

Просмотреть файл

@ -17,6 +17,8 @@ namespace angle
{
namespace spirv
{
void WriteSpirvHeader(std::vector<uint32_t> *blob, uint32_t idCount);
void WriteNop(std::vector<uint32_t> *blob);
void WriteUndef(std::vector<uint32_t> *blob, IdResultType idResultType, IdResult idResult);
void WriteSourceContinued(std::vector<uint32_t> *blob, LiteralString continuedSource);

Просмотреть файл

@ -5130,23 +5130,4 @@ angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
return angle::Result::Continue;
}
angle::Result GlslangCompileShaderOneOff(const GlslangErrorCallback &callback,
gl::ShaderType shaderType,
const std::string &shaderSource,
SpirvBlob *spirvBlobOut)
{
const TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
glslang::TShader shader(kShLanguageMap[shaderType]);
glslang::TProgram program;
ANGLE_TRY(
CompileShader(callback, builtInResources, shaderType, shaderSource, &shader, &program));
ANGLE_TRY(LinkProgram(callback, &program));
glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
glslang::GlslangToSpv(*intermediate, *spirvBlobOut);
return angle::Result::Continue;
}
} // namespace rx

Просмотреть файл

@ -212,11 +212,6 @@ angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut);
angle::Result GlslangCompileShaderOneOff(const GlslangErrorCallback &callback,
gl::ShaderType shaderType,
const std::string &shaderSource,
SpirvBlob *spirvBlobOut);
} // namespace rx
#endif // LIBANGLE_RENDERER_GLSLANG_WRAPPER_UTILS_H_

Просмотреть файл

@ -221,6 +221,8 @@ angle_source_set("angle_vulkan_backend") {
"$angle_root:angle_compression",
"$angle_root:angle_gpu_info_util",
"$angle_root:angle_image_util",
"$angle_root/src/common/spirv:angle_spirv_builder",
"$angle_spirv_headers_dir:spv_headers",
]
public_deps = [

Просмотреть файл

@ -93,15 +93,4 @@ angle::Result GlslangWrapperVk::TransformSpirV(
[context](GlslangError error) { return ErrorHandler(context, error); }, options,
variableInfoMap, initialSpirvBlob, shaderCodeOut);
}
// static
angle::Result GlslangWrapperVk::CompileShaderOneOff(vk::Context *context,
gl::ShaderType shaderType,
const std::string &shaderSource,
SpirvBlob *spirvBlobOut)
{
return GlslangCompileShaderOneOff(
[context](GlslangError error) { return ErrorHandler(context, error); }, shaderType,
shaderSource, spirvBlobOut);
}
} // namespace rx

Просмотреть файл

@ -48,11 +48,6 @@ class GlslangWrapperVk
const ShaderInterfaceVariableInfoMap &variableInfoMap,
const SpirvBlob &initialSpirvBlob,
SpirvBlob *shaderCodeOut);
static angle::Result CompileShaderOneOff(vk::Context *context,
gl::ShaderType shaderType,
const std::string &shaderSource,
SpirvBlob *spirvBlobOut);
};
} // namespace rx

Просмотреть файл

@ -9,10 +9,12 @@
#include "libANGLE/renderer/vulkan/UtilsVk.h"
#include "common/spirv/spirv_instruction_builder_autogen.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
@ -30,6 +32,8 @@ namespace OverlayDraw_comp = vk::InternalShader::OverlayDraw_co
namespace ConvertIndexIndirectLineLoop_comp = vk::InternalShader::ConvertIndexIndirectLineLoop_comp;
namespace GenerateMipmap_comp = vk::InternalShader::GenerateMipmap_comp;
namespace spirv = angle::spirv;
namespace
{
constexpr uint32_t kConvertIndexDestinationBinding = 0;
@ -408,7 +412,9 @@ void SetStencilForShaderExport(ContextVk *contextVk, vk::GraphicsPipelineDesc *d
desc->setStencilBackWriteMask(completeMask);
}
// Creates a shader that looks like the following, based on the number and types of unresolve
namespace unresolve
{
// The unresolve shader looks like the following, based on the number and types of unresolve
// attachments.
//
// #version 450 core
@ -431,79 +437,543 @@ void SetStencilForShaderExport(ContextVk *contextVk, vk::GraphicsPipelineDesc *d
// gl_FragDepth = subpassLoad(depthIn).x;
// gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
// }
angle::Result MakeUnresolveFragShader(
vk::Context *context,
uint32_t colorAttachmentCount,
gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *spirvBlobOut)
//
// This shader compiles to the following SPIR-V:
//
// OpCapability Shader \
// OpCapability InputAttachment \
// OpCapability StencilExportEXT \ Preamble. Mostly fixed, except
// OpExtension "SPV_EXT_shader_stencil_export" \ OpEntryPoint should enumerate
// %1 = OpExtInstImport "GLSL.std.450" \ out variables, stencil export
// OpMemoryModel Logical GLSL450 / is conditional to stencil
// OpEntryPoint Fragment %4 "main" %26 %27 %28 %29 %30 / unresolve, and depth replacing
// OpExecutionMode %4 OriginUpperLeft / conditional to depth unresolve.
// OpExecutionMode %4 DepthReplacing /
// OpSource GLSL 450 /
//
// OpName %4 "main" \
// OpName %26 "colorOut0" \
// OpName %27 "colorOut1" \
// OpName %28 "colorOut2" \
// OpName %29 "gl_FragDepth" \ Debug information. Not generated here.
// OpName %30 "gl_FragStencilRefARB" /
// OpName %31 "colorIn0" /
// OpName %32 "colorIn1" /
// OpName %33 "colorIn2" /
// OpName %34 "depthIn" /
// OpName %35 "stencilIn" /
//
// OpDecorate %26 Location 0 \
// OpDecorate %27 Location 1 \ Location decoration of out variables.
// OpDecorate %28 Location 2 /
//
// OpDecorate %29 BuiltIn FragDepth \ Builtin outputs, conditional to depth
// OpDecorate %30 BuiltIn FragStencilRefEXT / and stencil unresolve.
//
// OpDecorate %31 DescriptorSet 0 \
// OpDecorate %31 Binding 0 \
// OpDecorate %31 InputAttachmentIndex 0 \
// OpDecorate %32 DescriptorSet 0 \
// OpDecorate %32 Binding 1 \
// OpDecorate %32 InputAttachmentIndex 1 \
// OpDecorate %33 DescriptorSet 0 \ set, binding and input_attachment
// OpDecorate %33 Binding 2 \ decorations of the subpassInput
// OpDecorate %33 InputAttachmentIndex 2 / variables.
// OpDecorate %34 DescriptorSet 0 /
// OpDecorate %34 Binding 3 /
// OpDecorate %34 InputAttachmentIndex 3 /
// OpDecorate %35 DescriptorSet 0 /
// OpDecorate %35 Binding 4 /
// OpDecorate %35 InputAttachmentIndex 3 /
//
// %2 = OpTypeVoid \ Type of main(). Fixed.
// %3 = OpTypeFunction %2 /
//
// %6 = OpTypeFloat 32 \
// %7 = OpTypeVector %6 4 \
// %8 = OpTypePointer Output %7 \ Type declaration for "out vec4"
// %9 = OpTypeImage %6 SubpassData 0 0 0 2 Unknown / and "subpassInput". Fixed.
// %10 = OpTypePointer UniformConstant %9 /
//
// %11 = OpTypeInt 32 1 \
// %12 = OpTypeVector %11 4 \
// %13 = OpTypePointer Output %12 \ Type declaration for "out ivec4"
// %14 = OpTypeImage %11 SubpassData 0 0 0 2 Unknown / and "isubpassInput". Fixed.
// %15 = OpTypePointer UniformConstant %14 /
//
// %16 = OpTypeInt 32 0 \
// %17 = OpTypeVector %16 4 \
// %18 = OpTypePointer Output %17 \ Type declaration for "out uvec4"
// %19 = OpTypeImage %16 SubpassData 0 0 0 2 Unknown / and "usubpassInput". Fixed.
// %20 = OpTypePointer UniformConstant %19 /
//
// %21 = OpTypePointer Output %6 \ Type declaraions for depth and stencil. Fixed.
// %22 = OpTypePointer Output %11 /
//
// %23 = OpConstant %11 0 \
// %24 = OpTypeVector %11 2 \ ivec2(0) for OpImageRead. subpassLoad
// %25 = OpConstantComposite %22 %21 %21 / doesn't require coordinates. Fixed.
//
// %26 = OpVariable %8 Output \
// %27 = OpVariable %13 Output \
// %28 = OpVariable %18 Output \
// %29 = OpVariable %21 Output \
// %30 = OpVariable %22 Output \ Actual "out" and "*subpassInput"
// %31 = OpVariable %10 UniformConstant / variable declarations.
// %32 = OpVariable %15 UniformConstant /
// %33 = OpVariable %20 UniformConstant /
// %34 = OpVariable %10 UniformConstant /
// %35 = OpVariable %20 UniformConstant /
//
// %4 = OpFunction %2 None %3 \ Top of main(). Fixed.
// %5 = OpLabel /
//
// %36 = OpLoad %9 %31 \
// %37 = OpImageRead %7 %36 %23 \ colorOut0 = subpassLoad(colorIn0);
// OpStore %26 %37 /
//
// %38 = OpLoad %14 %32 \
// %39 = OpImageRead %12 %38 %23 \ colorOut1 = subpassLoad(colorIn1);
// OpStore %27 %39 /
//
// %40 = OpLoad %19 %33 \
// %41 = OpImageRead %17 %40 %23 \ colorOut2 = subpassLoad(colorIn2);
// OpStore %28 %41 /
//
// %42 = OpLoad %9 %34 \
// %43 = OpImageRead %7 %42 %23 \ gl_FragDepth = subpassLoad(depthIn).x;
// %44 = OpCompositeExtract %6 %43 0 /
// OpStore %29 %44 /
//
// %45 = OpLoad %19 %35 \
// %46 = OpImageRead %17 %45 %23 \
// %47 = OpCompositeExtract %16 %46 0 \ gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
// %48 = OpBitcast %11 %47 /
// OpStore %30 %48 /
//
// OpReturn \ Bottom of main(). Fixed.
// OpFunctionEnd /
//
// What makes the generation of this shader manageable is that the majority of it is constant
// between the different variations of the shader. The rest are repeating patterns with different
// ids or indices.
enum
{
std::ostringstream source;
// main() ids
kIdExtInstImport = 1,
kIdVoid,
kIdMainType,
kIdMain,
kIdMainLabel,
source << "#version 450 core\n";
// Types for "out vec4" and "subpassInput"
kIdFloatType,
kIdFloat4Type,
kIdFloat4OutType,
kIdFloatSubpassImageType,
kIdFloatSubpassInputType,
// Types for "out ivec4" and "isubpassInput"
kIdSIntType,
kIdSInt4Type,
kIdSInt4OutType,
kIdSIntSubpassImageType,
kIdSIntSubpassInputType,
// Types for "out uvec4" and "usubpassInput"
kIdUIntType,
kIdUInt4Type,
kIdUInt4OutType,
kIdUIntSubpassImageType,
kIdUIntSubpassInputType,
// Types for gl_FragDepth && gl_FragStencilRefARB
kIdFloatOutType,
kIdSIntOutType,
// ivec2(0) constant
kIdSIntZero,
kIdSInt2Type,
kIdSInt2Zero,
// Output variable ids
kIdColor0Out,
kIdDepthOut = kIdColor0Out + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
kIdStencilOut,
// Input variable ids
kIdColor0In,
kIdDepthIn = kIdColor0In + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
kIdStencilIn,
// Ids for temp variables
kIdColor0Load,
// 2 temp ids per color unresolve
kIdDepthLoad = kIdColor0Load + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2,
// 3 temp ids for depth unresolve
kIdStencilLoad = kIdDepthLoad + 3,
// Total number of ids used
// 4 temp ids for stencil unresolve
kIdCount = kIdStencilLoad + 4,
};
void InsertPreamble(uint32_t colorAttachmentCount,
bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *blobOut)
{
spirv::WriteCapability(blobOut, spv::CapabilityShader);
spirv::WriteCapability(blobOut, spv::CapabilityInputAttachment);
if (unresolveStencil)
{
source << "#extension GL_ARB_shader_stencil_export : require\n";
spirv::WriteCapability(blobOut, spv::CapabilityStencilExportEXT);
spirv::WriteExtension(blobOut, "SPV_EXT_shader_stencil_export");
}
// OpExtInstImport is actually not needed by this shader. We don't use any instructions from
// GLSL.std.450.
spirv::WriteMemoryModel(blobOut, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
// Create the list of entry point ids, including only the out variables.
spirv::IdRefList entryPointIds;
for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
{
const UnresolveColorAttachmentType type = colorAttachmentTypes[attachmentIndex];
ASSERT(type != kUnresolveTypeUnused);
const char *prefix =
type == kUnresolveTypeUint ? "u" : type == kUnresolveTypeSint ? "i" : "";
source << "layout(location=" << attachmentIndex << ") out " << prefix << "vec4 colorOut"
<< attachmentIndex << ";\n";
source << "layout(input_attachment_index=" << attachmentIndex
<< ", set=" << DescriptorSetIndex::InternalShader << ", binding=" << attachmentIndex
<< ") uniform " << prefix << "subpassInput colorIn" << attachmentIndex << ";\n";
entryPointIds.push_back(spirv::IdRef(kIdColor0Out + colorIndex));
}
const uint32_t depthStencilInputIndex = colorAttachmentCount;
uint32_t depthStencilBindingIndex = colorAttachmentCount;
if (unresolveDepth)
{
source << "layout(input_attachment_index=" << depthStencilInputIndex
<< ", set=" << DescriptorSetIndex::InternalShader
<< ", binding=" << depthStencilBindingIndex << ") uniform subpassInput depthIn;\n";
entryPointIds.push_back(spirv::IdRef(kIdDepthOut));
}
if (unresolveStencil)
{
entryPointIds.push_back(spirv::IdRef(kIdStencilOut));
}
spirv::WriteEntryPoint(blobOut, spv::ExecutionModelFragment, spirv::IdRef(kIdMain), "main",
entryPointIds);
spirv::WriteExecutionMode(blobOut, spirv::IdRef(kIdMain), spv::ExecutionModeOriginUpperLeft);
if (unresolveDepth)
{
spirv::WriteExecutionMode(blobOut, spirv::IdRef(kIdMain), spv::ExecutionModeDepthReplacing);
}
spirv::WriteSource(blobOut, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
nullptr);
}
void InsertInputDecorations(spirv::IdRef id,
uint32_t attachmentIndex,
uint32_t binding,
SpirvBlob *blobOut)
{
spirv::WriteDecorate(blobOut, id, spv::DecorationDescriptorSet,
{spirv::LiteralInteger(DescriptorSetIndex::InternalShader)});
spirv::WriteDecorate(blobOut, id, spv::DecorationBinding, {spirv::LiteralInteger(binding)});
spirv::WriteDecorate(blobOut, id, spv::DecorationInputAttachmentIndex,
{spirv::LiteralInteger(attachmentIndex)});
}
void InsertColorDecorations(uint32_t colorIndex, SpirvBlob *blobOut)
{
// Decorate the output color attachment with Location
spirv::WriteDecorate(blobOut, spirv::IdRef(kIdColor0Out + colorIndex), spv::DecorationLocation,
{spirv::LiteralInteger(colorIndex)});
// Decorate the subpasss input color attachment with Set/Binding/InputAttachmentIndex.
InsertInputDecorations(spirv::IdRef(kIdColor0In + colorIndex), colorIndex, colorIndex, blobOut);
}
void InsertDepthStencilDecorations(uint32_t depthStencilInputIndex,
uint32_t depthStencilBindingIndex,
bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *blobOut)
{
if (unresolveDepth)
{
// Decorate the output depth attachment with Location
spirv::WriteDecorate(blobOut, spirv::IdRef(kIdDepthOut), spv::DecorationBuiltIn,
{spirv::LiteralInteger(spv::BuiltInFragDepth)});
// Decorate the subpasss input depth attachment with Set/Binding/InputAttachmentIndex.
InsertInputDecorations(spirv::IdRef(kIdDepthIn), depthStencilInputIndex,
depthStencilBindingIndex, blobOut);
// Advance the binding. Note that the depth/stencil attachment has the same input
// attachment index (it's the same attachment in the subpass), but different bindings (one
// aspect per image view).
++depthStencilBindingIndex;
}
if (unresolveStencil)
{
source << "layout(input_attachment_index=" << depthStencilInputIndex
<< ", set=" << DescriptorSetIndex::InternalShader
<< ", binding=" << depthStencilBindingIndex
<< ") uniform usubpassInput stencilIn;\n";
// Decorate the output stencil attachment with Location
spirv::WriteDecorate(blobOut, spirv::IdRef(kIdStencilOut), spv::DecorationBuiltIn,
{spirv::LiteralInteger(spv::BuiltInFragStencilRefEXT)});
// Decorate the subpasss input stencil attachment with Set/Binding/InputAttachmentIndex.
InsertInputDecorations(spirv::IdRef(kIdStencilIn), depthStencilInputIndex,
depthStencilBindingIndex, blobOut);
}
}
source << "void main(){\n";
void InsertDerivativeTypes(spirv::IdRef baseId,
spirv::IdRef vec4Id,
spirv::IdRef vec4OutId,
spirv::IdRef imageTypeId,
spirv::IdRef inputTypeId,
SpirvBlob *blobOut)
{
spirv::WriteTypeVector(blobOut, vec4Id, baseId, spirv::LiteralInteger(4));
spirv::WriteTypePointer(blobOut, vec4OutId, spv::StorageClassOutput, vec4Id);
spirv::WriteTypeImage(blobOut, imageTypeId, baseId, spv::DimSubpassData,
// Unused with subpass inputs
spirv::LiteralInteger(0),
// Not arrayed
spirv::LiteralInteger(0),
// Not multisampled
spirv::LiteralInteger(0),
// Used without a sampler
spirv::LiteralInteger(2), spv::ImageFormatUnknown, nullptr);
spirv::WriteTypePointer(blobOut, inputTypeId, spv::StorageClassUniformConstant, imageTypeId);
}
for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
void InsertCommonTypes(SpirvBlob *blobOut)
{
// Types to support main().
spirv::WriteTypeVoid(blobOut, spirv::IdRef(kIdVoid));
spirv::WriteTypeFunction(blobOut, spirv::IdRef(kIdMainType), spirv::IdRef(kIdVoid), {});
// Float types
spirv::WriteTypeFloat(blobOut, spirv::IdRef(kIdFloatType), spirv::LiteralInteger(32));
InsertDerivativeTypes(spirv::IdRef(kIdFloatType), spirv::IdRef(kIdFloat4Type),
spirv::IdRef(kIdFloat4OutType), spirv::IdRef(kIdFloatSubpassImageType),
spirv::IdRef(kIdFloatSubpassInputType), blobOut);
// Int types
spirv::WriteTypeInt(blobOut, spirv::IdRef(kIdSIntType), spirv::LiteralInteger(32),
spirv::LiteralInteger(1));
InsertDerivativeTypes(spirv::IdRef(kIdSIntType), spirv::IdRef(kIdSInt4Type),
spirv::IdRef(kIdSInt4OutType), spirv::IdRef(kIdSIntSubpassImageType),
spirv::IdRef(kIdSIntSubpassInputType), blobOut);
// Unsigned int types
spirv::WriteTypeInt(blobOut, spirv::IdRef(kIdUIntType), spirv::LiteralInteger(32),
spirv::LiteralInteger(0));
InsertDerivativeTypes(spirv::IdRef(kIdUIntType), spirv::IdRef(kIdUInt4Type),
spirv::IdRef(kIdUInt4OutType), spirv::IdRef(kIdUIntSubpassImageType),
spirv::IdRef(kIdUIntSubpassInputType), blobOut);
// Types to support depth/stencil
spirv::WriteTypePointer(blobOut, spirv::IdRef(kIdFloatOutType), spv::StorageClassOutput,
spirv::IdRef(kIdFloatType));
spirv::WriteTypePointer(blobOut, spirv::IdRef(kIdSIntOutType), spv::StorageClassOutput,
spirv::IdRef(kIdSIntType));
// Constants used to load from subpass inputs
spirv::WriteConstant(blobOut, spirv::IdRef(kIdSIntType), spirv::IdRef(kIdSIntZero),
spirv::LiteralInteger(0));
spirv::WriteTypeVector(blobOut, spirv::IdRef(kIdSInt2Type), spirv::IdRef(kIdSIntType),
spirv::LiteralInteger(2));
spirv::WriteConstantComposite(blobOut, spirv::IdRef(kIdSInt2Type), spirv::IdRef(kIdSInt2Zero),
{spirv::IdRef(kIdSIntZero), spirv::IdRef(kIdSIntZero)});
}
void InsertVariableDecl(spirv::IdRef outType,
spirv::IdRef outId,
spirv::IdRef inType,
spirv::IdRef inId,
SpirvBlob *blobOut)
{
// Declare both the output and subpass input variables.
spirv::WriteVariable(blobOut, outType, outId, spv::StorageClassOutput, nullptr);
spirv::WriteVariable(blobOut, inType, inId, spv::StorageClassUniformConstant, nullptr);
}
void InsertColorVariableDecl(uint32_t colorIndex,
UnresolveColorAttachmentType type,
SpirvBlob *blobOut)
{
// Find the correct types for color variable declarations.
spirv::IdRef outType(kIdFloat4OutType);
spirv::IdRef outId(kIdColor0Out + colorIndex);
spirv::IdRef inType(kIdFloatSubpassInputType);
spirv::IdRef inId(kIdColor0In + colorIndex);
switch (type)
{
source << "colorOut" << attachmentIndex << " = subpassLoad(colorIn" << attachmentIndex
<< ");\n";
case kUnresolveTypeSint:
outType = spirv::IdRef(kIdSInt4OutType);
inType = spirv::IdRef(kIdSIntSubpassInputType);
break;
case kUnresolveTypeUint:
outType = spirv::IdRef(kIdUInt4OutType);
inType = spirv::IdRef(kIdUIntSubpassInputType);
break;
default:
break;
}
InsertVariableDecl(outType, outId, inType, inId, blobOut);
}
void InsertDepthStencilVariableDecl(bool unresolveDepth, bool unresolveStencil, SpirvBlob *blobOut)
{
if (unresolveDepth)
{
source << "gl_FragDepth = subpassLoad(depthIn).x;\n";
InsertVariableDecl(spirv::IdRef(kIdFloatOutType), spirv::IdRef(kIdDepthOut),
spirv::IdRef(kIdFloatSubpassInputType), spirv::IdRef(kIdDepthIn),
blobOut);
}
if (unresolveStencil)
{
source << "gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);\n";
InsertVariableDecl(spirv::IdRef(kIdSIntOutType), spirv::IdRef(kIdStencilOut),
spirv::IdRef(kIdUIntSubpassInputType), spirv::IdRef(kIdStencilIn),
blobOut);
}
}
void InsertTopOfMain(SpirvBlob *blobOut)
{
spirv::WriteFunction(blobOut, spirv::IdRef(kIdVoid), spirv::IdRef(kIdMain),
spv::FunctionControlMaskNone, spirv::IdRef(kIdMainType));
spirv::WriteLabel(blobOut, spirv::IdRef(kIdMainLabel));
}
void InsertColorUnresolveLoadStore(uint32_t colorIndex,
UnresolveColorAttachmentType type,
SpirvBlob *blobOut)
{
spirv::IdRef loadResult(kIdColor0Load + colorIndex * 2);
spirv::IdRef imageReadResult(loadResult + 1);
// Find the correct types for load/store.
spirv::IdRef loadType(kIdFloatSubpassImageType);
spirv::IdRef readType(kIdFloat4Type);
spirv::IdRef inId(kIdColor0In + colorIndex);
spirv::IdRef outId(kIdColor0Out + colorIndex);
switch (type)
{
case kUnresolveTypeSint:
loadType = spirv::IdRef(kIdSIntSubpassImageType);
readType = spirv::IdRef(kIdSInt4Type);
break;
case kUnresolveTypeUint:
loadType = spirv::IdRef(kIdUIntSubpassImageType);
readType = spirv::IdRef(kIdUInt4Type);
break;
default:
break;
}
source << "}\n";
return GlslangWrapperVk::CompileShaderOneOff(context, gl::ShaderType::Fragment, source.str(),
spirvBlobOut);
// Load the subpass input image, read from it, and store in output.
spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
spirv::IdRef(kIdSInt2Zero), nullptr, {});
spirv::WriteStore(blobOut, outId, imageReadResult, nullptr);
}
void InsertDepthStencilUnresolveLoadStore(bool unresolveDepth,
bool unresolveStencil,
SpirvBlob *blobOut)
{
if (unresolveDepth)
{
spirv::IdRef loadResult(kIdDepthLoad);
spirv::IdRef imageReadResult(loadResult + 1);
spirv::IdRef extractResult(imageReadResult + 1);
spirv::IdRef loadType(kIdFloatSubpassImageType);
spirv::IdRef readType(kIdFloat4Type);
spirv::IdRef inId(kIdDepthIn);
spirv::IdRef outId(kIdDepthOut);
// Load the subpass input image, read from it, select .x, and store in output.
spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
spirv::IdRef(kIdSInt2Zero), nullptr, {});
spirv::WriteCompositeExtract(blobOut, spirv::IdRef(kIdFloatType), extractResult,
imageReadResult, {spirv::LiteralInteger(0)});
spirv::WriteStore(blobOut, outId, extractResult, nullptr);
}
if (unresolveStencil)
{
spirv::IdRef loadResult(kIdStencilLoad);
spirv::IdRef imageReadResult(loadResult + 1);
spirv::IdRef extractResult(imageReadResult + 1);
spirv::IdRef bitcastResult(extractResult + 1);
spirv::IdRef loadType(kIdUIntSubpassImageType);
spirv::IdRef readType(kIdUInt4Type);
spirv::IdRef inId(kIdStencilIn);
spirv::IdRef outId(kIdStencilOut);
// Load the subpass input image, read from it, select .x, and store in output. There's a
// bitcast involved since the stencil subpass input has unsigned type, while
// gl_FragStencilRefARB is signed!
spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
spirv::IdRef(kIdSInt2Zero), nullptr, {});
spirv::WriteCompositeExtract(blobOut, spirv::IdRef(kIdUIntType), extractResult,
imageReadResult, {spirv::LiteralInteger(0)});
spirv::WriteBitcast(blobOut, spirv::IdRef(kIdSIntType), bitcastResult, extractResult);
spirv::WriteStore(blobOut, outId, bitcastResult, nullptr);
}
}
void InsertBottomOfMain(SpirvBlob *blobOut)
{
spirv::WriteReturn(blobOut);
spirv::WriteFunctionEnd(blobOut);
}
std::vector<uint32_t> MakeFragShader(
uint32_t colorAttachmentCount,
gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
bool unresolveDepth,
bool unresolveStencil)
{
SpirvBlob code;
// Reserve a sensible amount of memory. A single-attachment shader is 169 words.
code.reserve(169);
// Header
spirv::WriteSpirvHeader(&code, kIdCount);
// The preamble
InsertPreamble(colorAttachmentCount, unresolveDepth, unresolveStencil, &code);
// Color attachment decorations
for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
{
InsertColorDecorations(colorIndex, &code);
}
const uint32_t depthStencilInputIndex = colorAttachmentCount;
uint32_t depthStencilBindingIndex = colorAttachmentCount;
InsertDepthStencilDecorations(depthStencilInputIndex, depthStencilBindingIndex, unresolveDepth,
unresolveStencil, &code);
// Common types
InsertCommonTypes(&code);
// Attachment declarations
for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
{
InsertColorVariableDecl(colorIndex, colorAttachmentTypes[colorIndex], &code);
}
InsertDepthStencilVariableDecl(unresolveDepth, unresolveStencil, &code);
// Top of main
InsertTopOfMain(&code);
// Load and store for each attachment
for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
{
InsertColorUnresolveLoadStore(colorIndex, colorAttachmentTypes[colorIndex], &code);
}
InsertDepthStencilUnresolveLoadStore(unresolveDepth, unresolveStencil, &code);
// Bottom of main
InsertBottomOfMain(&code);
return code;
}
} // namespace unresolve
angle::Result GetUnresolveFrag(
vk::Context *context,
uint32_t colorAttachmentCount,
@ -517,9 +987,10 @@ angle::Result GetUnresolveFrag(
return angle::Result::Continue;
}
SpirvBlob shaderCode;
ANGLE_TRY(MakeUnresolveFragShader(context, colorAttachmentCount, colorAttachmentTypes,
unresolveDepth, unresolveStencil, &shaderCode));
std::vector<uint32_t> shaderCode = unresolve::MakeFragShader(
colorAttachmentCount, colorAttachmentTypes, unresolveDepth, unresolveStencil);
ASSERT(spirv::Validate(shaderCode));
// Create shader lazily. Access will need to be locked for multi-threading.
return vk::InitShaderAndSerial(context, &shader->get(), shaderCode.data(),