Hash :
47c66901
Author :
Date :
2024-10-21T12:47:22
Vulkan: Set gl_Layer to 0 if the framebuffer is not layered Bug: angleproject:372390039 Change-Id: I29067c9488e06f6dd2e90f207fecb843267fb77c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5949263 Reviewed-by: Charlie Lao <cclao@google.com> Reviewed-by: Yuxin Hu <yuxinhu@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//
// Copyright 2023 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.
//
// ReswizzleYUVOps: Adjusts swizzles for YUV channel order difference between
// GLES and Vulkan
//
//
#include "compiler/translator/tree_ops/spirv/EmulateYUVBuiltIns.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
namespace sh
{
namespace
{
// A traverser that adjusts channel order for various yuv ops.
class ReswizzleYUVOpsTraverser : public TIntermTraverser
{
public:
ReswizzleYUVOpsTraverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable)
{}
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
bool adjustOutput(TCompiler *compiler, TIntermBlock *root, const TIntermSymbol &yuvOutput);
private:
};
// OpenGLES and Vulkan has different color component mapping for YUV. OpenGL spec maps R_gl=y,
// G_gl=u, B_gl=v, but Vulkan wants R_vulkan=v, G_vulkan=y, B_vulkan=u. We want all calculation to
// be in OpenGLES mapping during shader execution, but the actual buffer/image will be stored as
// vulkan mapping. This means when we sample from VkImage, we need to map from vulkan order back to
// GL order, which comes out to be R_gl=y=G_vulkan=1, G_gl=u=B_vulkan=2, B_gl=v=R_vulkan=0. i.e, {1,
// 2, 0, 3}. This function will check if the aggregate is a texture{proj|fetch}(samplerExternal,...)
// and if yes it will compose and return a swizzle node.
TIntermSwizzle *CheckTextureOpWithSamplerExternal2DY2YAndSwizzle(Visit visit,
TIntermAggregate *node)
{
if (visit != Visit::PreVisit)
{
return nullptr;
}
if (!BuiltInGroup::IsBuiltIn(node->getOp()))
{
return nullptr;
}
TOperator op = node->getFunction()->getBuiltInOp();
if (op == EOpTexture || op == EOpTextureProj || op == EOpTexelFetch)
{
TIntermSequence *arguments = node->getSequence();
TType const &samplerType = (*arguments)[0]->getAsTyped()->getType();
if (samplerType.getBasicType() != EbtSamplerExternal2DY2YEXT)
{
return nullptr;
}
// texture(...).gbra
TIntermSwizzle *yuvSwizzle = new TIntermSwizzle(node, {1, 2, 0, 3});
return yuvSwizzle;
}
return nullptr;
}
bool ReswizzleYUVOpsTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
TIntermSwizzle *yuvSwizzle = CheckTextureOpWithSamplerExternal2DY2YAndSwizzle(visit, node);
if (yuvSwizzle != nullptr)
{
ASSERT(!getParentNode()->getAsSwizzleNode());
queueReplacement(yuvSwizzle, OriginalNode::BECOMES_CHILD);
return false;
}
return true;
}
bool ReswizzleYUVOpsTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
{
TIntermAggregate *aggregate = node->getOperand()->getAsAggregate();
if (aggregate == nullptr)
{
return true;
}
// There is swizzle on YUV texture sampler, and we need to apply YUV swizzle first and
// then followed by the original swizzle. Finally we fold the two swizzles into one.
TIntermSwizzle *yuvSwizzle = CheckTextureOpWithSamplerExternal2DY2YAndSwizzle(visit, aggregate);
if (yuvSwizzle != nullptr)
{
TIntermTyped *replacement = new TIntermSwizzle(yuvSwizzle, node->getSwizzleOffsets());
replacement = replacement->fold(nullptr);
queueReplacement(replacement, OriginalNode::IS_DROPPED);
return false;
}
return true;
}
// OpenGLES and Vulkan has different color component mapping for YUV. When we write YUV data, we
// need to convert OpenGL mapping to vulkan's mapping, which comes out to be {2, 0, 1, 3}.
bool ReswizzleYUVOpsTraverser::adjustOutput(TCompiler *compiler,
TIntermBlock *root,
const TIntermSymbol &yuvOutput)
{
TIntermBlock *block = new TIntermBlock;
// output = output.brga
TVector<int> swizzle = {2, 0, 1, 3};
const int size = yuvOutput.getType().getNominalSize();
if (size < 4)
{
swizzle.resize(size);
}
TIntermTyped *assignment = new TIntermBinary(EOpAssign, yuvOutput.deepCopy(),
new TIntermSwizzle(yuvOutput.deepCopy(), swizzle));
block->appendStatement(assignment);
return RunAtTheEndOfShader(compiler, root, block, mSymbolTable);
}
} // anonymous namespace
bool ReswizzleYUVOps(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable,
const TIntermSymbol *yuvOutput)
{
ReswizzleYUVOpsTraverser traverser(symbolTable);
root->traverse(&traverser);
if (!traverser.updateTree(compiler, root))
{
return false;
}
if (yuvOutput != nullptr && !traverser.adjustOutput(compiler, root, *yuvOutput))
{
return false;
}
return true;
}
} // namespace sh